diff --git a/2311/.nojekyll b/2311/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/2311/assets/css/home.css b/2311/assets/css/home.css new file mode 100644 index 00000000..61eef4fc --- /dev/null +++ b/2311/assets/css/home.css @@ -0,0 +1,63 @@ +body { + background-image: url("../images/home.png"); + -webkit-background-size: cover; + -moz-background-size: cover; + background-size: cover; + -o-background-size: cover; + background-repeat: no-repeat; + background-position: center center; + background-attachment: scroll; +} + +.navbar { + background-color: transparent !important; +} + +.nav-footer { + background-color: transparent !important; +} + +.home-grid-parent { + display: grid; + margin: auto; + max-width: 1200px; + padding-left: 2em; + padding-right: 2em; + align-items: center; + grid-template-columns: repeat(2, 1fr); + grid-column-gap: 2em; + grid-template-areas: "text hero"; + /*grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));*/ +} + +.home-grid-child-left { + grid-area: text; +} + +.home-grid-child-right { + grid-area: hero; +} + +@media only screen and (max-width: 576px) { + .home-grid-parent { + grid-template-columns: 1fr; + grid-column-gap: 0; + grid-template-areas: + "hero" + "text"; + } +} + +@media only screen and (min-width: 576px) { + .home-grid-parent { + margin: 0; + position: absolute; + top: 50%; + -ms-transform: translateY(-50%); + transform: translateY(-50%); + } +} + +.home-grid-child-left h2 { + margin-top: 0.5em; +} diff --git a/2311/assets/favicon.png b/2311/assets/favicon.png new file mode 100644 index 00000000..f720d511 Binary files /dev/null and b/2311/assets/favicon.png differ diff --git a/2311/assets/images/cover.png b/2311/assets/images/cover.png new file mode 100644 index 00000000..58435859 Binary files /dev/null and b/2311/assets/images/cover.png differ diff --git a/2311/assets/images/filezilla.png b/2311/assets/images/filezilla.png new file mode 100644 index 00000000..227bc4ae Binary files /dev/null and b/2311/assets/images/filezilla.png differ diff --git a/2311/assets/images/home.png b/2311/assets/images/home.png new file mode 100644 index 00000000..23e2a07d Binary files /dev/null and b/2311/assets/images/home.png differ diff --git a/2311/assets/images/landing.png b/2311/assets/images/landing.png new file mode 100644 index 00000000..16956a06 Binary files /dev/null and b/2311/assets/images/landing.png differ diff --git a/2311/assets/images/mobaxterm.png b/2311/assets/images/mobaxterm.png new file mode 100644 index 00000000..de124d8e Binary files /dev/null and b/2311/assets/images/mobaxterm.png differ diff --git a/2311/assets/images/supr-login.jpg b/2311/assets/images/supr-login.jpg new file mode 100644 index 00000000..2d1e3296 Binary files /dev/null and b/2311/assets/images/supr-login.jpg differ diff --git a/2311/assets/images/supr-projects.jpg b/2311/assets/images/supr-projects.jpg new file mode 100644 index 00000000..3e3943ec Binary files /dev/null and b/2311/assets/images/supr-projects.jpg differ diff --git a/2311/assets/images/supr-request.jpg b/2311/assets/images/supr-request.jpg new file mode 100644 index 00000000..45fa3d13 Binary files /dev/null and b/2311/assets/images/supr-request.jpg differ diff --git a/2311/assets/images/supr-tetralith.jpg b/2311/assets/images/supr-tetralith.jpg new file mode 100644 index 00000000..07261b4e Binary files /dev/null and b/2311/assets/images/supr-tetralith.jpg differ diff --git a/2311/assets/images/thinlinc.png b/2311/assets/images/thinlinc.png new file mode 100644 index 00000000..9a4aeee8 Binary files /dev/null and b/2311/assets/images/thinlinc.png differ diff --git a/2311/assets/images/xquartz.png b/2311/assets/images/xquartz.png new file mode 100644 index 00000000..859a7d57 Binary files /dev/null and b/2311/assets/images/xquartz.png differ diff --git a/2311/assets/logos/nbis-scilifelab-ngi.svg b/2311/assets/logos/nbis-scilifelab-ngi.svg new file mode 100644 index 00000000..2c886bc8 --- /dev/null +++ b/2311/assets/logos/nbis-scilifelab-ngi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/2311/assets/logos/nbis-scilifelab.png b/2311/assets/logos/nbis-scilifelab.png new file mode 100644 index 00000000..e7512a05 Binary files /dev/null and b/2311/assets/logos/nbis-scilifelab.png differ diff --git a/2311/assets/logos/nbis.png b/2311/assets/logos/nbis.png new file mode 100644 index 00000000..f063960f Binary files /dev/null and b/2311/assets/logos/nbis.png differ diff --git a/2311/assets/logos/scilifelab.png b/2311/assets/logos/scilifelab.png new file mode 100644 index 00000000..b7e675b4 Binary files /dev/null and b/2311/assets/logos/scilifelab.png differ diff --git a/2311/home_contents.html b/2311/home_contents.html new file mode 100644 index 00000000..a2217ad4 --- /dev/null +++ b/2311/home_contents.html @@ -0,0 +1,482 @@ + + + + + + + + + + +Contents + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+

Contents

+
+
+ Course materials organised by topic. When following a live workshop, use Schedule.
Slides: / , Labs: , Videos: +
+
+
+
+ + +
+ + + + +
+ + +
+ + + + +
+ + + + +
+

Introduction to Linux

+
    +
  • Introduction to Linux
  • +
+
+
+

File types in Linux

+
    +
  • File types in Bioinformatics
    +
  • +
  • Linux file permissions
  • +
+
+
+

Uppmax

+
    +
  • Introduction to UPPMAX
    +
  • +
  • UPPMAX Pipelines
  • +
+
+
+

Advanced Linux

+
    +
  • Better terminal experience
  • +
  • Advanced Linux
  • +
+
+
+

Variant-calling workflow

+
    +
  • Variant-calling
  • +
+
+
+

RNA-Seq workflow

+
    +
  • RNA-Seq workflow
  • +
  • Simon’s report
  • +
+
+
+

NGS technologies

+
    +
  • NGS technologies and challenges
  • +
  • NGS Pipelines
  • +
+
+
+

Other

+
    +
  • QC of FastQ reads
  • +
  • Data management
  • +
+
+
+

Useful resources

+
    +
  • Connecting to Uppmax
  • +
  • Uploading & downloading files from Uppmax
  • +
  • Working on Tetralith: The backup cluster
  • +
  • Linux cheatsheet
  • +
  • Bash cheat sheet 1
  • +
  • Bash cheat sheet 2
  • +
  • Bash cheat sheet 3
  • +
  • Uppmax cheatsheet
  • +
  • Mac keyboard
  • +
+ + +
+ +
+ +
+ + + + + + \ No newline at end of file diff --git a/2311/home_info.html b/2311/home_info.html new file mode 100644 index 00000000..06cdcdb8 --- /dev/null +++ b/2311/home_info.html @@ -0,0 +1,460 @@ + + + + + + + + + +Practical Info + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+

Practical Info

+

Venue, address, travel and contact information

+
+
+ + +
+ + + + +
+ + +
+ + + + +
+ + + + +
+

Location

+
+ +
+
+
+
+
+ +
+
+

Room E10:1309
Entrance C11
Biomedicinskt centrum
Uppsala University / ScilifeLab
Husargatan 3
75237 Uppsala
Sweden

+

Few selected hotels are listed below ranked by distance from the venue.

+ +

The venue and hotels are also marked on the map.

+

Use the UL website or the UL app for bus and train services around Uppsala. For buses from the Centralstation (Train/Bus), take Bus 4 (towards Gottsunda Centrum) or 8 (towards Sunnersta) and get off at the stop Uppsala Science Park. Bus tickets can be purchased in the app or directly from the driver using a credit card.

+
+
+
+
+
+

Contact

+

This workshop is run by the National Bioinformatics Infrastructure Sweden (NBIS) in collaboration with National Genomics Infrastructure (NGI). Both, NGI and NBIS are platforms at SciLifeLab.

+

If you would like to get in touch with us regarding this workshop, please contact us at edu.intro-ngs [at] nbis.se.

+
+
+
+

+
+
+ + +
+ +
+ +
+ + + + + + + \ No newline at end of file diff --git a/2311/home_precourse.html b/2311/home_precourse.html new file mode 100644 index 00000000..ef5946a9 --- /dev/null +++ b/2311/home_precourse.html @@ -0,0 +1,596 @@ + + + + + + + + + +Precourse + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+

Precourse

+

These are steps to be completed before the workshop

+
+
+ + +
+ + + + +
+ + +
+ + + + +
+ + + + +
+

1 UPPMAX

+

Remote computing cluster UPPMAX will be use for data analyses. A SUPR/NAISS account is needed to use these resources.

+

If you do not already have one, create an account at SUPR/NAISS. Then, Log in to SUPR/NAISS, preferably using the SWAMID.

+
+
+

+
+
+

Before proceeding with applying for project membership and user accounts, we have to accept the NAISS User Agreement. Do this by clicking the Personal Information link in the left sidebar menu. The scroll down a bit until you reach the section User Agreements. If you already have accepted it the State will be a green box with the text Accepted in it. If it is anything else, click it to start the accepting process.

+
+
+
+ +
+
+Tip +
+
+
+

This is where you might run into trouble if you don’t have a SWAMID connected account. You will not be able to accept the user agreement online without it, so you will have to send in your acceptance in paper form together with a copy of your passport. This process can take a week or more, so please make sure you can accept the user agreement in good time.

+
+
+

After making sure you have an accepted user agreement, go to the SUPR/NAISS Projects page and request membership to the project ID: naiss2023-22-862

+
+
+

+
+
+

Once you are accepted to a project, you should see that project listed under your active projects.

+
+
+

+
+
+

Finally you need to request login accounts to NSC and UPPMAX. These are the accounts you use to log in to the actual computers, so they are not the same as your SUPR account. Login to SUPR and go to the Accounts page. Under the Possible Resource Account Requests heading click on Request Account on Tetralith @ NSC and Request Account on Rackham @ UPPMAX button and confirm it on the next page. If either of them are missing from this page, it could be because you already have a login account created (only 1 account per person allowed), or that you have not yet gotten your project memberships approved.

+
+
+

+
+
+

Checking your request and approving your account requires some manual work, so you might have to wait for some time (up to a working day) before the next step. When the account is ready to be created, you will receive an email to your registered email address (shown in your SUPR contact information) with information on how to proceed. You will get a one-time URL that you use to get the password (within seven days) to login to the cluster with. The link is only valid for 1 visit, so write down the password you get. When that has been done, the account ready for use within 15 minutes and you can then login using your password. Once you have logged into the cluster you can change your password by typing passwd in the terminal and follow the instuctions.

+
+
+
+ +
+
+Note +
+
+
+

You will get one username & password for the account on UPPMAX, and one username and password for the account on NSC. Please keep track of both, we will tell you when to use which account during the workshop.

+
+
+
+
+

2 Install tools

+
+

2.1 ThinLinc

+
+
+

+
+
+

ThinLinc allows graphical connection to UPPMAX. Download and install from https://www.cendio.com/thinlinc/download. It can be used directly from the browser but it is recommended to download and install the client for better copy/paste operation.

+
+
+

2.2 XQuartz

+
+
+

+
+
+

Mac users will need to download and install XQuartz for X11 forwarding. ie; to forward remotely opened windows to local machine.

+
+
+

2.3 MobaXterm (Optional)

+
+
+

+
+
+

If you are on a Windows system, and you want to open graphical applications from the terminal, we recommend MobaXterm. It is recommended that you INSTALL the program and not use the portable version. MobaXterm also has an integrated SFTP file browser.

+
+
+

2.4 Filezilla (Optional)

+
+
+

+
+
+

When you need to transfer data between the remote cluster and your computer, you can use the tools SCP or SFTP through the terminal. Windows users can use the SFTP browser available with MobaXterm. If you prefer a GUI to upload and download files from the remote cluster, we recommend installing FileZilla.

+
+
+
+

3 Connect to UPPMAX

+

See Connecting to UPPMAX instructions listed on the Contents page.

+
+
+
+ +
+
+Tip +
+
+
+

If you want to get a primer on using the terminal, you can get started with the following Tutorial One at this link Unix tutorial for beginners. You can use https://scilifelab.github.io/courses/ngsintro/common/emu/ (or this mirror) to try the commands in the tutorial, so that you don’t mess up any real world system. If you have any questions regarding this tutorial contact: martin.dahlo [at] scilifelab.uu.se.

+
+
+
+
+

4 Create a user folder

+
+
+
+ +
+
+Note +
+
+
+

Where username is mentioned, change to your user name.

+
+
+

Once you have logged in to UPPMAX, run the following command.

+
+
+
+
+
bash
+
+
mkdir /proj/naiss2023-22-862/nobackup/username
+
+
+
+

This creates a directory with your user name. You will work inside this directory for the workshop. If you cannot write to the folder, the most likely reason is that you have not requested access to the workshop project via SUPR. This is described in step 1 above.

+
+
+
+ +
+
+Note +
+
+
+

It may take an hour or so from request approval, before you can actually write to the folder. We will check before the workshop that all students have logged in and done this, so do not forget!

+
+
+ + +
+ +
+ +
+ + + + + + + \ No newline at end of file diff --git a/2311/home_schedule.html b/2311/home_schedule.html new file mode 100644 index 00000000..711c5958 --- /dev/null +++ b/2311/home_schedule.html @@ -0,0 +1,636 @@ + + + + + + + + + + +Schedule + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+

Schedule

+
+
+ The schedule is intended for when following a live workshop. If you are following this at your own pace, see Contents +
+
+
+
+ + +
+ + + + +
+ + +
+ + + + +
+ + + + +
+
+
+ +
+
+Note +
+
+
+

Coffee breaks are planned for approximately 10:00 and 14:30 every day.

+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeTopicTeacherAssistant

13-Nov-2023MonUppsala

09:00 - 09:30Welcome and general introduction Martin Dahlö
09:30 - 10:30Intro to Linux Martin Dahlö
10:30 - 11:45Intro to Linux Martin DahlöGDGuilherme Dias,LSLucile Soler
11:45 - 13:00Lunch
13:00 - 14:00Intro to Uppmax Martin Dahlö
14:00 - 17:00Intro to Uppmax Martin DahlöGDGuilherme Dias

14-Nov-2023TueUppsala

09:00 - 09:30File types in Bioinformatics Martin Dahlö
09:30 - 11:00File types in Bioinformatics Martin DahlöMRMiguel Redondo,MPMartin Pippel
11:00 - 11:45Better terminal experience Martin Dahlö
11:45 - 13:00Lunch
13:00 - 14:00Quality control  Malin LarssonGDGuilherme Dias,MPMartin Pippel
14:00 - 15:00Advanced Bash Martin Dahlö
15:00 - 17:00Advanced Bash Martin DahlöKLKatarina Lejonlid,MPMartin Pippel

15-Nov-2023WedUppsala

09:00 - 10:15NGS tech & challenges Adam Ameur & Johanna Lagensjö
10:15 - 11:00NGS tech & challengesAdam Ameur & Johanna Lagensjö
11:00 - 11:45NGS Pipelines Adam Ameur
12:00 - 13:00Lunch
13:00 - 14:00Variant-calling workflow Malin Larsson
14:00 - 17:00Variant-calling workflow Malin LarssonJHJason Hill,MMMarkus Mayrhofer
18:00 - 21:00Course Dinner

16-Nov-2023ThuUppsala

09:00 - 09:30GATK best practicesMalin Larsson
09:30 - 11:45Variant-calling workflowMalin LarssonAJAnna Johansson,MMMarkus Mayrhofer
11:45 - 13:00Lunch
13:00 - 14:00RNA-Seq workflow Roy Francis
14:00 - 17:00RNA-Seq workflow Roy FrancisMLMalin Larsson,VHVincent van Hoef

17-Nov-2023FriUppsala

09:00 - 11:45RNA-Seq workflowRoy FrancisVHVincent van Hoef,MDMartin Dahlö
11:45 - 13:00Lunch
13:00 - 14:00Data management practices Elin Kronander
14:00 - 14:15NBIS Elin Kronander
+
+
+ +

+ Date Venue Slides Lab Video +

+
+ + + +
+ +
+ + + + + + \ No newline at end of file diff --git a/2311/home_syllabus.html b/2311/home_syllabus.html new file mode 100644 index 00000000..5c8cdd31 --- /dev/null +++ b/2311/home_syllabus.html @@ -0,0 +1,472 @@ + + + + + + + + + +Syllabus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+

Syllabus

+

This workshop is aimed towards biologists, researchers, computer scientists or data analysts with limited experience in analysing NGS data.

+
+
+ + +
+ + + + +
+ + +
+ + + + +
+ + + + +
+ +
+
+

The syllabus for this workshop are as follows.

+
    +
  • Working on the unix/linux command line +
      +
    • Command line navigation and related commands: cd, mkdir, rm, rmdir
    • +
    • Commonly used linux tools: cp, mv, tar, less, more, head, tail, nano, grep, top, man
    • +
    • Wildcards
    • +
    • Ownership and permissions
    • +
    • Symbolic links
    • +
    • Piping commands
    • +
  • +
  • Working on remote computing cluster +
      +
    • Logging on to UPPMAX
    • +
    • Booking resources
    • +
    • Job templates, submission and queues
    • +
    • Modules
    • +
  • +
  • Commonly used bioinformatic tools and pipelines
  • +
  • Working with integrated genome viewer
  • +
  • Variant-calling workflow +
      +
    • Mapping reads to the reference genome
    • +
    • Variant detection
    • +
    • VCF file format
    • +
  • +
  • RNA-Seq workflow +
      +
    • RNA-Seq experimental design and considerations
    • +
    • QC, mapping and gene expression counts
    • +
    • Differential gene expression analyses
    • +
  • +
  • Current advances in NGS technologies
  • +
+
+
+

After this workshop you should be able to:

+
    +
  • Describe the basic principles of next generation sequencing.
  • +
  • Use the Linux command line interface to manage simple file processing operations, and organise directory structures.
  • +
  • Connect to and work on a remote compute cluster.
  • +
  • Apply programs in Linux for analysis of NGS data.
  • +
  • Summarise the applications of current NGS technologies, including the weakness and strengths of the approaches and when it is appropriate to use which one of them.
  • +
  • Explain common NGS file formats.
  • +
  • Interpret quality control of NGS reads.
  • +
  • Explain the steps involved in variant calling using whole genome sequencing data.
  • +
  • Independently perform a basic variant calling workflow on example data.
  • +
  • Explain the steps involved in a differential gene expression workflow using RNA seq data.
  • +
  • Hands-on experience with handling of raw RNA sequencing data, QC and quantification of gene expression.
  • +
  • Conceptual understanding of differential gene expression analysis.
  • +
+
+
+
    +
  • This is a national course open to PhD students, postdocs, group leaders and core facility staff.

  • +
  • A background in genetics, cell biology, biomedicine, biochemistry, bioinformatics or comparable is desirable. To get the maximum benefit from the workshop we would like you to

  • +
  • Have a research project where you are currently using next generation sequencing or are planning to use next generation sequencing. It is beneficial if you are directly performing analyses or if you have a support role and will be able to participate in a wide range of projects and transfer your knowledge to others.

  • +
  • Selection criteria include correct entry requirements, motivation to attend the workshop as well as gender and geographical balance. Applicants affiliated to a Swedish institution are prioritized. International applicants are considered only if/when seats are available. Further prioritization: PhD scholars > Post-Docs, PIs, Healthcare staff > Master’s students).

  • +
  • Please note that NBIS training events do not provide any formal university credits. The training content is estimated to correspond to a certain number of credits, however the estimated credits are just guidelines. If formal credits are crucial, the student needs to confer with the home department before submitting a course application in order to establish whether the course is valid for formal credits or not.

  • +
+
+
+
+ + + +
+ +
+ + + + + + \ No newline at end of file diff --git a/2311/index.html b/2311/index.html new file mode 100644 index 00000000..2fe62425 --- /dev/null +++ b/2311/index.html @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + + + + \ No newline at end of file diff --git a/2311/search.json b/2311/search.json new file mode 100644 index 00000000..096e795e --- /dev/null +++ b/2311/search.json @@ -0,0 +1,1290 @@ +[ + { + "objectID": "troubleshooting.html", + "href": "troubleshooting.html", + "title": "Status & Troubleshooting", + "section": "", + "text": "Useful commands for monitoring status and user activity on UPPMAX.\n\n\nList all jobs running an a project\n\n\nsqueue -A naiss2023-22-862 | sort -k 4\n\n\nSample output\n 23186770 core _interac analopez R 2:15:00 1 r55\n 23175660 core (null) anitav R 6:52:28 1 r480\n 23188713 core (null) annha R 1:42:59 1 r480\n 23185442 core (null) annha R 2:47:11 1 r480\n 23185433 core (null) inene424 R 2:47:42 1 r479\n 23185391 core (null) inene424 R 2:50:04 1 r479\n 23185540 core (null) shengyz R 2:46:20 1 r480\n JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n 23185119 core (null) wingf R 2:53:40 1 r479\n\n\n\nSorted list of jobs per user\n\n\nsqueue -A naiss2023-22-862 | tr -s ' ' | cut -d' ' -f5 | sort | uniq -c | sort -k1\n\n\nSample output\n 1 tami\n 1 tommal\n 1 USER\n 1 valeriia\n 1 vioww\n 1 vishnupk\n 1 ylvafr\n 2 mehran96\n 2 miika\n 3 mariasve\n\n\n\n\nTotal number of cores used on a project\n\n\nsqueue -A naiss2023-22-862 -o %C | awk '{total += $0} END{print total}'\n\n\n\n\n\nAmount of storage space used per project\n\n\nuquota | grep naiss2023-22-862\n\n\nSample output\nYour project Your File Area Unit Usage Quota Limit Over Quota\n--------------- --------------------- -------- ------ ----------- ----------\nsnic2022-22-123 /proj/snic2022-22-123 GBytes 4.6 128\n\n\n\nList users by reservation ID\n\n\nsqueue -R naiss2023-22-862_1 | sort -k 4\nsqueue -R naiss2023-22-862_2 | sort -k 4\nsqueue -R naiss2023-22-862_3 | sort -k 4\nsqueue -R naiss2023-22-862_4 | sort -k 4\nsqueue -R naiss2023-22-862_5 | sort -k 4\n\n\nSample output\n23188713 core (null) annha R 2:01:15 1 r480\n23185442 core (null) annha R 3:05:27 1 r480\n23187840 core (null) evangc R 2:11:02 1 r479\n23186811 core (null) shengyz R 2:34:45 1 r479\n23185540 core (null) shengyz R 3:04:36 1 r480\n JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n23185119 core (null) wingf R 3:11:56 1 r479\n\n\n\n\nList last activity in a directory for all users\n\n\nbash /sw/courses/utils/list_modification_times.sh /proj/naiss2023-22-862/nobackup/\n\n\nSample output\nhkyle 2021-11-22 13:59:59 (/proj/snic2021-22-644/nobackup/hkyle/uppmax_tutorial/job_template)\nmalinh 2021-11-22 14:12:10 (/proj/snic2021-22-644/nobackup/malinh/slurm-23182638.out)\naliraz 2021-11-22 14:23:16 (/proj/snic2021-22-644/nobackup/aliraz/slurm-23184022.out)\nkristaps 2021-11-22 14:25:08 (/proj/snic2021-22-644/nobackup/kristaps/uppmax_tutorial/jobData.sam)\nanapin 2021-11-22 14:56:14 (/proj/snic2021-22-644/nobackup/anapin/uppmax_tutorial/uppmax_tutorial/jobData.sam)\nanalopez 2021-11-22 14:56:16 (/proj/snic2021-22-644/nobackup/analopez/uppmax_tutorial/jobData.sam)\nprivate Not available ()\n\n\n\n\n\nscontrol show res | grep naiss2023-22-862\n\n\nSample output\nReservationName=snic2021-22-644_wed StartTime=2021-11-24T12:00:00 EndTime=2021-11-24T18:00:00 Duration=06:00:00\n Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a\nReservationName=snic2021-22-644_thu StartTime=2021-11-25T08:30:00 EndTime=2021-11-25T17:30:00 Duration=09:00:00\n Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a\nReservationName=snic2021-22-644_fri StartTime=2021-11-26T08:30:00 EndTime=2021-11-26T13:30:00 Duration=05:00:00\n Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a\n\n\n\n\n\nprojmembers naiss2023-22-862\n\n\nSample output\nsnic2022-22-123 abusiddi Abu Bakar Siddique\nsnic2022-22-123 afifac Afifa Enam Chowdhury\nsnic2022-22-123 asve0014 Ashish Verma\nsnic2022-22-123 berka Berkay Paylar\nsnic2022-22-123 btleren Betül Eren Keskin\n\n\n\nFetch user information from username\n\nfinger username" + }, + { + "objectID": "troubleshooting.html#status", + "href": "troubleshooting.html#status", + "title": "Status & Troubleshooting", + "section": "", + "text": "Useful commands for monitoring status and user activity on UPPMAX.\n\n\nList all jobs running an a project\n\n\nsqueue -A naiss2023-22-862 | sort -k 4\n\n\nSample output\n 23186770 core _interac analopez R 2:15:00 1 r55\n 23175660 core (null) anitav R 6:52:28 1 r480\n 23188713 core (null) annha R 1:42:59 1 r480\n 23185442 core (null) annha R 2:47:11 1 r480\n 23185433 core (null) inene424 R 2:47:42 1 r479\n 23185391 core (null) inene424 R 2:50:04 1 r479\n 23185540 core (null) shengyz R 2:46:20 1 r480\n JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n 23185119 core (null) wingf R 2:53:40 1 r479\n\n\n\nSorted list of jobs per user\n\n\nsqueue -A naiss2023-22-862 | tr -s ' ' | cut -d' ' -f5 | sort | uniq -c | sort -k1\n\n\nSample output\n 1 tami\n 1 tommal\n 1 USER\n 1 valeriia\n 1 vioww\n 1 vishnupk\n 1 ylvafr\n 2 mehran96\n 2 miika\n 3 mariasve\n\n\n\n\nTotal number of cores used on a project\n\n\nsqueue -A naiss2023-22-862 -o %C | awk '{total += $0} END{print total}'\n\n\n\n\n\nAmount of storage space used per project\n\n\nuquota | grep naiss2023-22-862\n\n\nSample output\nYour project Your File Area Unit Usage Quota Limit Over Quota\n--------------- --------------------- -------- ------ ----------- ----------\nsnic2022-22-123 /proj/snic2022-22-123 GBytes 4.6 128\n\n\n\nList users by reservation ID\n\n\nsqueue -R naiss2023-22-862_1 | sort -k 4\nsqueue -R naiss2023-22-862_2 | sort -k 4\nsqueue -R naiss2023-22-862_3 | sort -k 4\nsqueue -R naiss2023-22-862_4 | sort -k 4\nsqueue -R naiss2023-22-862_5 | sort -k 4\n\n\nSample output\n23188713 core (null) annha R 2:01:15 1 r480\n23185442 core (null) annha R 3:05:27 1 r480\n23187840 core (null) evangc R 2:11:02 1 r479\n23186811 core (null) shengyz R 2:34:45 1 r479\n23185540 core (null) shengyz R 3:04:36 1 r480\n JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n23185119 core (null) wingf R 3:11:56 1 r479\n\n\n\n\nList last activity in a directory for all users\n\n\nbash /sw/courses/utils/list_modification_times.sh /proj/naiss2023-22-862/nobackup/\n\n\nSample output\nhkyle 2021-11-22 13:59:59 (/proj/snic2021-22-644/nobackup/hkyle/uppmax_tutorial/job_template)\nmalinh 2021-11-22 14:12:10 (/proj/snic2021-22-644/nobackup/malinh/slurm-23182638.out)\naliraz 2021-11-22 14:23:16 (/proj/snic2021-22-644/nobackup/aliraz/slurm-23184022.out)\nkristaps 2021-11-22 14:25:08 (/proj/snic2021-22-644/nobackup/kristaps/uppmax_tutorial/jobData.sam)\nanapin 2021-11-22 14:56:14 (/proj/snic2021-22-644/nobackup/anapin/uppmax_tutorial/uppmax_tutorial/jobData.sam)\nanalopez 2021-11-22 14:56:16 (/proj/snic2021-22-644/nobackup/analopez/uppmax_tutorial/jobData.sam)\nprivate Not available ()\n\n\n\n\n\nscontrol show res | grep naiss2023-22-862\n\n\nSample output\nReservationName=snic2021-22-644_wed StartTime=2021-11-24T12:00:00 EndTime=2021-11-24T18:00:00 Duration=06:00:00\n Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a\nReservationName=snic2021-22-644_thu StartTime=2021-11-25T08:30:00 EndTime=2021-11-25T17:30:00 Duration=09:00:00\n Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a\nReservationName=snic2021-22-644_fri StartTime=2021-11-26T08:30:00 EndTime=2021-11-26T13:30:00 Duration=05:00:00\n Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a\n\n\n\n\n\nprojmembers naiss2023-22-862\n\n\nSample output\nsnic2022-22-123 abusiddi Abu Bakar Siddique\nsnic2022-22-123 afifac Afifa Enam Chowdhury\nsnic2022-22-123 asve0014 Ashish Verma\nsnic2022-22-123 berka Berkay Paylar\nsnic2022-22-123 btleren Betül Eren Keskin\n\n\n\nFetch user information from username\n\nfinger username" + }, + { + "objectID": "troubleshooting.html#troubleshooting", + "href": "troubleshooting.html#troubleshooting", + "title": "Status & Troubleshooting", + "section": "2 Troubleshooting", + "text": "2 Troubleshooting\n\n2.1 X-forwarding\n\n2.1.1 Setup\nMac users\n\nInstall Xquartz and restart computer\nOpen the Xquartz terminal and connect to Uppmax\nIn my recent macos (10.xxx) , x-forwarding only works if I explicitly run the Xquartz terminal\n\nssh -XY username@rackham.uppmax.uu.se\nAlso use this when logging in to the compute node!\nssh -XY username@node\nWindows users\nIn MobaXTerm, go to settings and make sure that X-forwarding is checked.\n\n\n2.1.2 Testing X-forwarding\nType xeyes in the terminal.\n\n\n\n2.2 Open .html documents on Rackham\nFirst ensure X-forwarding works, then run firefox --no-remote filename.html\n\n\n2.3 SCP fails with *\nSometimes students have problems to download files with SCP when there is a * in the end of the line. For example; scp user@rackham.uppmax.uu.se:/proj/bla/HG00097.bam* .. It needs to be changed to scp user@rackham.uppmax.uu.se:/proj/bla/HG00097.bam\\* ..\n\n\n2.4 Thinlinc\n\n2.4.1 Login\nWhen logging in through an installed client, username/password seems to work. When logging in through the browser, username/password+2FA may be required.\n\n\n2.4.2 Minimize the ThinLinc window\nOn a Mac, press Fn + F8, then select: Minimize window.\n\n\n2.4.3 Gedit opening issues\nWhen opening it from the terminal (gedit &), it was not able to connect to a display to show the graphics. The DISPLAY variable was empty. This was when using ThinLinc, so it should have worked. The issue was solved by opening gedit from the menu. Gedit could be labelled Text Editor.\n\n\n\n2.5 Set persistent home directory in MobaXTerm\nThis is to specify where the home directory in MobaXTerm is located in the computer’s file system. In Settings > Configuration, set the persistent home directory to a suitable folder. Restart MobaXTerm.\n\n\n2.6 Typing $ on a Swedish keyboard\nPress AltGr + 4.\n\n\n2.7 Black background for XQuartz windows on M1 Mac\nAs documented here, run:\n\ndefaults write org.xquartz.X11 enable_render_extension 0" + }, + { + "objectID": "topics/vc/lab_vc_answers.html", + "href": "topics/vc/lab_vc_answers.html", + "title": "Variant Calling Answers", + "section": "", + "text": "Unable to display PDF file. Download instead." + }, + { + "objectID": "topics/uppmax/pipeline/lab_uppmax_pipeline.html", + "href": "topics/uppmax/pipeline/lab_uppmax_pipeline.html", + "title": "Uppmax Pipeline", + "section": "", + "text": "Note\n\n\n\nIn code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window." + }, + { + "objectID": "topics/uppmax/pipeline/lab_uppmax_pipeline.html#load-the-module", + "href": "topics/uppmax/pipeline/lab_uppmax_pipeline.html#load-the-module", + "title": "Uppmax Pipeline", + "section": "4.1 Load the module", + "text": "4.1 Load the module\nIn this exercise, we’ll pretend that we are running analyses. This will give you a peek at what running programs in linux is like, and get you ready for the real stuff during the week!\nThe first thing you usually do is to load the modules for the programs you want to run. During this exercise we’ll only run my dummy scripts that don’t actually do any analysis, so they don’t have a module of their own. What we can do instead is to manually do what module loading usually does: to modify the $PATH variable.\nThe $PATH variable specifies directories where the computer should look for programs whenever you type a command. For instance, when you type\n$ nano\nhow does the computer know which program to start? You gave it the name nano, but that could refer to any file named nano in the computer, yet it starts the correct one every time. The answer is that it looks in the directories stored in the $PATH variable and start the first program it finds that is named nano.\nTo see which directories that are available by default, type\n$ echo $PATH\nIt should give you something like this, a list of directories, separated by colon signs:\n$ echo $PATH\n/home/dahlo/perl//bin/:/home/dahlo/.pyenv/shims:/home/dahlo/.pyenv/bin:\n/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:\n/sbin:/opt/thinlinc/bin:/sw/uppmax/bin:/home/dahlo/usr/bin\nTry loading a module, and then look at the $PATH variable again. You’ll see that there are a few extra directories there now, after the module has been loaded.\n$ module load bioinfo-tools samtools/1.6\n$ echo $PATH\n/sw/apps/bioinfo/samtools/1.6/rackham/bin:/home/dahlo/perl/bin:/home/dahlo/.pyenv/shims:\n/home/dahlo/.pyenv/bin:/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:\n/usr/sbin:/sbin:/opt/thinlinc/bin:/sw/uppmax/bin:/home/dahlo/usr/bin\nTo pretend that we are loading a module, instead of actually loading a module for them, we’ll manually do what the module system would have done. We will just add a the directory containing my dummy scripts to the $PATH variable, and it will be like we loaded the module for them. Now, when we type the name of one of my scripts, the computer will look in all the directories specified in the $PATH variable, which now includes the location where i keep my scripts. The computer will now find programs named as my scripts are and it will run them.\n$ export PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts\nThis will set the $PATH variable to whatever it is at the moment, and add a directory at the end of it. Note the lack of a dollar sign infront of the variable name directly after export. You don’t use dollar signs when assigning values to variables, and you always use dollar signs when getting values from variables.\n\n Important\nThe export command affects only the terminal you type it in. If you have 2 terminals open, only the terminal you typed it in will have a modified path. If you close that terminal and open a new one, it will not have the modified path.\n\nEnough with variables now. Let’s try the scripts out!" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#what-is-rna", + "href": "topics/rnaseq/slide_rnaseq.html#what-is-rna", + "title": "Bulk RNASeq Analysis", + "section": "What is RNA?", + "text": "What is RNA?\n\n\nThe transcriptome is spatially and temporally dynamic\nData comes from functional units (coding regions)\nOnly a tiny fraction of the genome\n\n\n\nCentral dogma of molecular biology. DNA -> RNA -> Protein.\nWe have gene models to describe the organisation of a genome into functional units.\nVery tiny portion of the genome is transcribed into RNA.\nThere are many types of RNA. Commonly protein coding RNA, also called mRNA. There are tRNA, sRNA, miRNA, siRNA, lincRNA, piRNA, snRNA etc.\nWhat is the most abundant RNA? rRNA.\nWhile DNA is mostly considered constant in all cells for an organism, expressed RNA varies from cell to cell and from time to time.\nWhen we say RNA sequencing, we are not sequencing RNA molecules directly. RNA is first converted to DNA through reverse transcription followed by regular DNA sequencing." + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#applications", + "href": "topics/rnaseq/slide_rnaseq.html#applications", + "title": "Bulk RNASeq Analysis", + "section": "Applications", + "text": "Applications\n\nIdentify gene sequences in genomes (annotation)\nLearn about gene function\nDifferential gene expression\nExplore isoform and allelic expression\nUnderstand co-expression, pathways and networks\nGene fusion\nRNA editing" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#workflow", + "href": "topics/rnaseq/slide_rnaseq.html#workflow", + "title": "Bulk RNASeq Analysis", + "section": "Workflow", + "text": "Workflow\n\n\nConesa et al. (2016)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#de-novo-assembly", + "href": "topics/rnaseq/slide_rnaseq.html#de-novo-assembly", + "title": "Bulk RNASeq Analysis", + "section": "De-Novo assembly", + "text": "De-Novo assembly\n\nWhen no reference genome available\nTo identify novel genes/transcripts/isoforms\nIdentify fusion genes\nAssemble transcriptome from short reads\nAccess quality of assembly and refine\nMap reads back to assembled transcriptome\n\n\nTrinity, SOAPdenovo-Trans, Oases, rnaSPAdes, Hsieh et al. (2019), Wang & Gribskov (2017)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#experimental-design", + "href": "topics/rnaseq/slide_rnaseq.html#experimental-design", + "title": "Bulk RNASeq Analysis", + "section": "Experimental design", + "text": "Experimental design\n\n\n\nBiological replicates: 6 - 12 Schurch et al. (2016)\nSample size estimation Hart et al. (2013)\nPower analysis Zhao et al. (2018) RNASeqPower web app\nBalanced design to avoid batch effects DeclareDesign\nRIN values have strong effect Gallego Romero et al. (2014)\n\n\n\n\n\n\n\nTechnical replicates are not necessary Marioni et al. (2008)\nPrevious publications can be useful in experimental planning to avoid repeating the same mistakes" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#library-sequencing", + "href": "topics/rnaseq/slide_rnaseq.html#library-sequencing", + "title": "Bulk RNASeq Analysis", + "section": "Library & Sequencing", + "text": "Library & Sequencing\n\n\n\n\n\n\npolyA selection/Ribosomal RNA depletion\nsingle-end/Paired-end" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#library-prep", + "href": "topics/rnaseq/slide_rnaseq.html#library-prep", + "title": "Bulk RNASeq Analysis", + "section": "Library prep", + "text": "Library prep\n\n80% of the RNA in a cell is ribosomal RNA (rRNA)\nrRNA can be eliminated using polyA selection or rRNA depletion\nPolyA selection mostly captures only protein-coding genes / mRNA but gives cleaner results\nDepletion of rRNA is the solution if it’s important to retain all RNA species\nsmallRNAs are purified through size selection\nPCR amplification may be needed for low quantity input (See section PCR duplicates)\nPreferably opt for stranded (directional) libraries Zhao et al. (2015), Levin et al. (2010)\n\nAccurately identify sense/antisense transcript\nResolve overlapping genes\n\nExome capture\nLibrary normalisation to concentrate specific transcripts\nLibraries should have high complexity/low duplication. Daley & Smith (2013)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#sequencing", + "href": "topics/rnaseq/slide_rnaseq.html#sequencing", + "title": "Bulk RNASeq Analysis", + "section": "Sequencing", + "text": "Sequencing\n\nShort reads vs long reads (Illumina/PacBio)\nRead length Chhangawala et al. (2015)\n\nGreater than 50bp does not improve DGE\nLonger reads better for isoforms\n\nPooling samples\nSequencing depth (Coverage/Reads per sample)\nSingle-end reads (Cheaper)\nPaired-end reads\n\nIncreased mappable reads\nIncreased power in assemblies\nBetter for structural variation and isoforms\nDecreased false-positives for DGE\n\nMore replicates are better than more depth Liu et al. (2014)\n\nCorley et al. (2017), SciLifeLab" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#workflow-dge", + "href": "topics/rnaseq/slide_rnaseq.html#workflow-dge", + "title": "Bulk RNASeq Analysis", + "section": "Workflow • DGE", + "text": "Workflow • DGE" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#read-qc", + "href": "topics/rnaseq/slide_rnaseq.html#read-qc", + "title": "Bulk RNASeq Analysis", + "section": "Read QC", + "text": "Read QC\n\nNumber of reads\nPer base sequence quality\nPer sequence quality score\nPer base sequence content\nPer sequence GC content\nPer base N content\nSequence length distribution\nSequence duplication levels\nOverrepresented sequences\nAdapter content\nKmer content\n\n\nFastQC, MultiQC\nhttps://sequencing.qcfail.com/" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#fastqc", + "href": "topics/rnaseq/slide_rnaseq.html#fastqc", + "title": "Bulk RNASeq Analysis", + "section": "FastQC", + "text": "FastQC\n\n\nGood quality\n\n\n\n\n\n\nPoor quality" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#read-qc-pbsq-psqs", + "href": "topics/rnaseq/slide_rnaseq.html#read-qc-pbsq-psqs", + "title": "Bulk RNASeq Analysis", + "section": "Read QC • PBSQ, PSQS", + "text": "Read QC • PBSQ, PSQS\nPer base sequence quality\n\nPer sequence quality scores" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#read-qc-pbsc-psgc", + "href": "topics/rnaseq/slide_rnaseq.html#read-qc-pbsc-psgc", + "title": "Bulk RNASeq Analysis", + "section": "Read QC • PBSC, PSGC", + "text": "Read QC • PBSC, PSGC\nPer base sequence content\n\nPer sequence GC content" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#read-qc-sdl-ac", + "href": "topics/rnaseq/slide_rnaseq.html#read-qc-sdl-ac", + "title": "Bulk RNASeq Analysis", + "section": "Read QC • SDL, AC", + "text": "Read QC • SDL, AC\nSequence duplication level\n\nAdapter content" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#trimming", + "href": "topics/rnaseq/slide_rnaseq.html#trimming", + "title": "Bulk RNASeq Analysis", + "section": "Trimming", + "text": "Trimming\n\n\n\nTrimming reads to remove adapter/readthrough or low quality bases\nRelated options are hard clipping, filtering reads\nSliding window trimming\nFilter by min/max read length\n\nRemove reads less than ~18nt\n\nDemultiplexing/Splitting\n\nWhen to avoid trimming?\n\nRead trimming may not always be necessary Liao & Shi (2020)\nFixed read length may sometimes be more important\nExpected insert size distribution may be more important for assemblers\n\nCutadapt, fastp, Prinseq" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#mapping", + "href": "topics/rnaseq/slide_rnaseq.html#mapping", + "title": "Bulk RNASeq Analysis", + "section": "Mapping", + "text": "Mapping\n\n\nAligning reads back to a reference sequence\nMapping to genome vs transcriptome\nSplice-aware alignment (genome) (STAR, HISAT2 etc)\n\nSTAR, HiSat2, Baruzzo et al. (2017)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#aligners-metrics", + "href": "topics/rnaseq/slide_rnaseq.html#aligners-metrics", + "title": "Bulk RNASeq Analysis", + "section": "Aligners • Metrics", + "text": "Aligners • Metrics\n\n\n\n\n\n\n\n\nBaruzzo et al. (2017)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#aligners-time-and-ram", + "href": "topics/rnaseq/slide_rnaseq.html#aligners-time-and-ram", + "title": "Bulk RNASeq Analysis", + "section": "Aligners time and RAM", + "text": "Aligners time and RAM\n\n\n\nProgram\nTime_Min\nMemory_GB\n\n\n\n\nHISATx1\n22.7\n4.3\n\n\nHISATx2\n47.7\n4.3\n\n\nHISAT\n26.7\n4.3\n\n\nSTAR\n25\n28\n\n\nSTARx2\n50.5\n28\n\n\nGSNAP\n291.9\n20.2\n\n\nTopHat2\n1170\n4.3" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#mapping-1", + "href": "topics/rnaseq/slide_rnaseq.html#mapping-1", + "title": "Bulk RNASeq Analysis", + "section": "Mapping", + "text": "Mapping\n\nReads (FASTQ)\n\n@ST-E00274:179:HHYMLALXX:8:1101:1641:1309 1:N:0:NGATGT\nNCATCGTGGTATTTGCACATCTTTTCTTATCAAATAAAAAGTTTAACCTACTCAGTTATGCGCATACGTTTTTTGATGGCATTTCCATAAACCGATTTTTTTTTTATGCACGTACCCAAAACGTGCAGAAAAATACGCTGCTAGAAATGTA\n+\n#AAAFAFA<-AFFJJJAFA-FFJJJJFFFAJJJJ-<FFJJJ-A-F-7--FA7F7-----FFFJFA<FFFFJ<AJ--FF-A<A-<JJ-7-7-<FF-FFFJAFFAA--A--7FJ-7----77-A--7F7)---7F-A----7)7-----7<<-\n@instrument:runid:flowcellid:lane:tile:xpos:ypos read:isfiltered:controlnumber:sampleid\n\nReference Genome/Transcriptome (FASTA)\n\n>1 dna:chromosome chromosome:GRCz10:1:1:58871917:1 REF\nGATCTTAAACATTTATTCCCCCTGCAAACATTTTCAATCATTACATTGTCATTTCCCCTC\nCAAATTAAATTTAGCCAGAGGCGCACAACATACGACCTCTAAAAAAGGTGCTGTAACATG\n\nAnnotation (GTF/GFF)\n\n#!genome-build GRCz10\n#!genebuild-last-updated 2016-11\n4 ensembl_havana gene 6732 52059 . - . gene_id \"ENSDARG00000104632\"; gene_version \"2\"; gene_name \"rerg\"; gene_source \"ensembl_havana\"; gene_biotype \"protein_coding\"; havana_gene \"OTTDARG00000044080\"; havana_gene_version \"1\";\nseq source feature start end score strand frame attribute\nIllumina FASTQ format, GTF format" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#alignment", + "href": "topics/rnaseq/slide_rnaseq.html#alignment", + "title": "Bulk RNASeq Analysis", + "section": "Alignment", + "text": "Alignment\n\nSAM/BAM (Sequence Alignment Map format)\n\nST-E00274:188:H3JWNCCXY:4:1102:32431:49900 163 1 1 60 8S139M4S = 385 535 TATTTAGAGATCTTAAACATCCATTCCCCCTGCAAACATTTTCAATCATTACATTGTCATTTTCCCTCCAAATTAAATTTAGCCAGAGGCGCACAACATACGACCTCTAAAAAAGGTGCTGGAACATGTACCTATATGCAGCACCACCATC AAAFAFFAFFFFJ7FFFFJ<JAFA7F-<AJ7JJ<FFFJ--<FAJF<7<7FAFJ-<AFA<-JJJ-AF-AJ-FF<F--A<FF<-7777-7JA-77A---F-7AAFF-FJA--77FJ<--77)))7<JJA<J77<-------<7--))7)))7- NM:i:4 MD:Z:12T0T40C58T25 AS:i:119 XS:i:102 XA:Z:17,-53287490,4S33M4D114M,11; MQ:i:60 MC:Z:151M RG:Z:ST-E00274_188_H3JWNCCXY_4\nquery flag ref pos mapq cigar mrnm mpos tlen seq qual opt\nNever store alignment files in raw SAM format. Always compress it! SAM format\n\n\n\nFormat\nSize_GB\n\n\n\n\nSAM\n7.4\n\n\nBAM\n1.9\n\n\nCRAM lossless Q\n1.4\n\n\nCRAM 8 bins Q\n0.8\n\n\nCRAM no Q\n0.26" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#visualisation-igv", + "href": "topics/rnaseq/slide_rnaseq.html#visualisation-igv", + "title": "Bulk RNASeq Analysis", + "section": "Visualisation • IGV", + "text": "Visualisation • IGV\n\nIGV, UCSC Genome Browser, SeqMonk" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#visualisation-tview", + "href": "topics/rnaseq/slide_rnaseq.html#visualisation-tview", + "title": "Bulk RNASeq Analysis", + "section": "Visualisation • tview", + "text": "Visualisation • tview\nsamtools tview alignment.bam genome.fasta" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#visualisation-seqmonk", + "href": "topics/rnaseq/slide_rnaseq.html#visualisation-seqmonk", + "title": "Bulk RNASeq Analysis", + "section": "Visualisation • SeqMonk", + "text": "Visualisation • SeqMonk\n\nSeqMonk" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#alignment-qc", + "href": "topics/rnaseq/slide_rnaseq.html#alignment-qc", + "title": "Bulk RNASeq Analysis", + "section": "Alignment QC", + "text": "Alignment QC\n\nNumber of reads mapped/unmapped/paired etc\nUniquely mapped\nInsert size distribution\nCoverage\nGene body coverage\nBiotype counts / Chromosome counts\nCounts by region: gene/intron/non-genic\nSequencing saturation\nStrand specificity\n\nSTAR (final log file), samtools stats, bamtools stats, QoRTs, RSeQC, Qualimap" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#alignment-qc-star-log", + "href": "topics/rnaseq/slide_rnaseq.html#alignment-qc-star-log", + "title": "Bulk RNASeq Analysis", + "section": "Alignment QC • STAR Log", + "text": "Alignment QC • STAR Log\nMultiQC can be used to summarise and plot STAR log files." + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#alignment-qc-features", + "href": "topics/rnaseq/slide_rnaseq.html#alignment-qc-features", + "title": "Bulk RNASeq Analysis", + "section": "Alignment QC • Features", + "text": "Alignment QC • Features\nQoRTs was run on all samples and summarised using MultiQC." + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#alignment-qc-qorts", + "href": "topics/rnaseq/slide_rnaseq.html#alignment-qc-qorts", + "title": "Bulk RNASeq Analysis", + "section": "Alignment QC • QoRTs", + "text": "Alignment QC • QoRTs" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#alignment-qc-examples", + "href": "topics/rnaseq/slide_rnaseq.html#alignment-qc-examples", + "title": "Bulk RNASeq Analysis", + "section": "Alignment QC • Examples", + "text": "Alignment QC • Examples\n\n\nRead mapping profile \n\nGene body coverage \nSigurgeirsson et al. (2014)\n\n\n\nThe read mapping profile shows how well bases along a read mapped to the reference for all reads. Mapability usually decreases towards the 5’ and 3’ ends due to soft-clipping. This is is more pronounced in untrimmed reads.\nGene body coverage shows read coverage over the gene for all genes. An even coverage is ideally expected. A bias in either direction could be indicative of library quality. A bias toward the 3’ end is usually seen in polyA selected libraries." + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#alignment-qc-examples-1", + "href": "topics/rnaseq/slide_rnaseq.html#alignment-qc-examples-1", + "title": "Bulk RNASeq Analysis", + "section": "Alignment QC • Examples", + "text": "Alignment QC • Examples\n\n\nInsert size\n\n\nSaturation curve\n\nFrancis et al. (2013)\n\n\n\nNegative insert size implies overlapping mate pairs.\nConserved genes in the mouse transcriptome. Saturation curves of discovery of genes in the mouse heart from a set of a subset of 248 conserved orthologs; genes which have any blast hit are shown in circles; genes which the translated protein was within the expected size range of the conserved gene are in squares; proteins which are 100% identical to a canonical protein in Uniprot/Swissprot mouse database are shown in triangles." + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#quantification-counts", + "href": "topics/rnaseq/slide_rnaseq.html#quantification-counts", + "title": "Bulk RNASeq Analysis", + "section": "Quantification • Counts", + "text": "Quantification • Counts\n\n\n\nRead counts = gene expression\nReads can be quantified on any feature (gene, transcript, exon etc)\nIntersection on gene models\nGene/Transcript level\n\n\nfeatureCounts, HTSeq" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#quantification", + "href": "topics/rnaseq/slide_rnaseq.html#quantification", + "title": "Bulk RNASeq Analysis", + "section": "Quantification", + "text": "Quantification\n\n\nPCR duplicates\n\nComputational deduplication not recommended Klepikova et al. (2017), Parekh et al. (2016)\nUse PCR-free library-prep kits\nUse UMIs during library-prep Fu et al. (2018)\n\nMulti-mapping\n\nAdded (BEDTools multicov)\nDiscard (featureCounts, HTSeq)\nDistribute counts (Cufflinks, featureCounts)\nRescue\n\nProbabilistic assignment (Rcount, Cufflinks)\nPrioritise features (Rcount)\nProbabilistic assignment with EM (RSEM)\n\n\n\n\n\n\n\nTools that detect duplicate reads (like Picard MarkDuplicates) is looking for reads that start and end at the same coordinates. Such reads are expected to be PCR derived and can be collapsed down to 1 read. This makes sense in whole genome sequencing, but in RNA-Seq, this is naturally expected since highly expressed genes create huge number of identical transcripts which may fragment at hotspots leading to fragmentation bias Roberts et al. (2011). Therefore, removing PCR duplicates may remove real duplicates as well." + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#quantification-abundance", + "href": "topics/rnaseq/slide_rnaseq.html#quantification-abundance", + "title": "Bulk RNASeq Analysis", + "section": "Quantification • Abundance", + "text": "Quantification • Abundance\n\nCount methods\n\nProvide no inference on isoforms\nCannot accurately measure fold change\n\n\n\n\nProbabilistic assignment\n\nDeconvolute ambiguous mappings\nTranscript-level\ncDNA reference\n\n\nKallisto, Salmon\n\nUltra-fast & alignment-free\nBootstrapping & quantification confidence\nTranscript-level counts\nTranscript-level estimates improves gene-level estimates Soneson et al. (2015), tximport\nEvaluation and comparison of isoform quantification tools Zhang et al. (2017)\n\nRSEM, Kallisto, Salmon\n\nGene expression counts may be literal counts (reads overlapping to gene models) or probabilistically estimated based on the data. Proponents of probabilistically estimation claims that it is a better estimate that corrects for sampling biases.\nTools such as RSEM, Kallisto and Salmon produce probabilistic abundance estimates. Soneson et al. (2015) claims that estimating abundance using Kallisto at the transcript levels and then summarising down to gene-level counts results in improved estimates of gene expression.\nKallisto/Salmon -> transcript-counts -> tximport() -> gene-counts" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#quantification-qc", + "href": "topics/rnaseq/slide_rnaseq.html#quantification-qc", + "title": "Bulk RNASeq Analysis", + "section": "Quantification QC", + "text": "Quantification QC\nENSG00000000003 140 242 188 143 287 344 438 280 253\nENSG00000000005 0 0 0 0 0 0 0 0 0\nENSG00000000419 69 98 77 55 52 94 116 79 69\nENSG00000000457 56 75 104 79 157 205 183 178 153\nENSG00000000460 33 27 23 19 27 42 69 44 40\n\n\n\nPairwise correlation between samples must be high (>0.9)\n\n\n\n\nCount QC using RNASeqComp\n\n\nRNASeqComp, Teng et al. (2016)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#multiqc", + "href": "topics/rnaseq/slide_rnaseq.html#multiqc", + "title": "Bulk RNASeq Analysis", + "section": "MultiQC", + "text": "MultiQC" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#normalisation", + "href": "topics/rnaseq/slide_rnaseq.html#normalisation", + "title": "Bulk RNASeq Analysis", + "section": "Normalisation", + "text": "Normalisation\n\nControl for Sequencing depth, compositional bias and more\nMedian of Ratios (DESeq2) and TMM (edgeR) perform the best\n\n\n\nFor DGE using DGE packages, use raw counts\nFor clustering, heatmaps etc use VST, VOOM or RLOG\nFor own analysis, plots etc, use TPM\nOther solutions: spike-ins/house-keeping genes\n\n\nDillies et al. (2013), Evans et al. (2018), Wagner et al. (2012)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#exploratory", + "href": "topics/rnaseq/slide_rnaseq.html#exploratory", + "title": "Bulk RNASeq Analysis", + "section": "Exploratory", + "text": "Exploratory\n\n\n\nRemove lowly expressed genes\nHeatmaps, MDS, PCA etc.\n\n\npheatmap\n\n\nTransform raw counts to VST, VOOM, RLOG, TPM etc" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#batch-correction", + "href": "topics/rnaseq/slide_rnaseq.html#batch-correction", + "title": "Bulk RNASeq Analysis", + "section": "Batch correction", + "text": "Batch correction\n\nEstimate variation explained by variables (PVCA)\n\n\n\nFind confounding effects as surrogate variables (SVA)\nModel known batches in the LM/GLM model\nCorrect known batches (ComBat from SVA)(Only if you are desperate! Zindler et al. (2020))\nInteractively evaluate batch effects and correction (BatchQC) Manimaran et al. (2016)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#differential-expression", + "href": "topics/rnaseq/slide_rnaseq.html#differential-expression", + "title": "Bulk RNASeq Analysis", + "section": "Differential expression", + "text": "Differential expression\n\n\nUnivariate testing gene-by-gene\nMore descriptive, less predictive" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#differential-expression-1", + "href": "topics/rnaseq/slide_rnaseq.html#differential-expression-1", + "title": "Bulk RNASeq Analysis", + "section": "Differential expression", + "text": "Differential expression\n\nDESeq2, edgeR (Neg-binom > GLM > Test)\nLimma-Voom (Neg-binom > Voom-transform > LM > Test)\nDESeq2 ~age+condition\n\nEstimate size factors estimateSizeFactors()\nEstimate gene-wise dispersion estimateDispersions()\nFit curve to gene-wise dispersion estimates\nShrink gene-wise dispersion estimates\nGLM fit for each gene\nWald test nbinomWaldTest()\n\n\n\nDESeq2, edgeR, limma, Seyednasrollah et al. (2015)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#dge", + "href": "topics/rnaseq/slide_rnaseq.html#dge", + "title": "Bulk RNASeq Analysis", + "section": "DGE", + "text": "DGE\n\nResults results()\n\nlog2 fold change (MLE): type type2 vs control\nWald test p-value: type type2 vs control\nDataFrame with 1 row and 6 columns\n baseMean log2FoldChange lfcSE\n <numeric> <numeric> <numeric>\nENSG00000000003 242.307796723287 -0.932926089608546 0.114285150312285\n stat pvalue padj\n <numeric> <numeric> <numeric>\nENSG00000000003 -8.16314356729037 3.26416150242775e-16 1.36240609998527e-14\n\nSummary summary()\n\nout of 17889 with nonzero total read count\nadjusted p-value < 0.1\nLFC > 0 (up) : 4526, 25%\nLFC < 0 (down) : 5062, 28%\noutliers [1] : 25, 0.14%\nlow counts [2] : 0, 0%\n(mean count < 3)" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#dge-1", + "href": "topics/rnaseq/slide_rnaseq.html#dge-1", + "title": "Bulk RNASeq Analysis", + "section": "DGE", + "text": "DGE\n\n\n\nMA plot plotMA()\n\n\n\nVolcano plot\n\n\n\n\nNormalised counts plotCounts()" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#functional-analysis-go", + "href": "topics/rnaseq/slide_rnaseq.html#functional-analysis-go", + "title": "Bulk RNASeq Analysis", + "section": "Functional analysis • GO", + "text": "Functional analysis • GO\n\nGene set analysis (GSA)\nGene set enrichment analysis (GSEA)\nGene ontology / Reactome databases" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#functional-analysis-kegg", + "href": "topics/rnaseq/slide_rnaseq.html#functional-analysis-kegg", + "title": "Bulk RNASeq Analysis", + "section": "Functional analysis • Kegg", + "text": "Functional analysis • Kegg\n\nPathway analysis (Kegg)\n\n\nDAVID, clusterProfiler, ClueGO, ErmineJ, pathview" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#summary", + "href": "topics/rnaseq/slide_rnaseq.html#summary", + "title": "Bulk RNASeq Analysis", + "section": "Summary", + "text": "Summary\n\nSound experimental design to avoid confounding\nPlan carefully about lib prep, sequencing etc based on experimental objective\nFor DGE, biological replicates may be more important than other considerations (paired-end, sequencing depth, long reads etc)\nDiscard low quality bases, reads, genes and samples\nVerify that tools and methods align with data assumptions\nExperiment with multiple pipelines and tools\nQC! QC everything at every step\n\n\nConesa, A., Madrigal, P., Tarazona, S., Gomez-Cabrero, D., Cervera, A., McPherson, A., … & Mortazavi, A. (2016). A survey of best practices for RNA-seq data analysis. Genome biology, 17(1), 1-19." + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#further-learning", + "href": "topics/rnaseq/slide_rnaseq.html#further-learning", + "title": "Bulk RNASeq Analysis", + "section": "Further learning", + "text": "Further learning\n\nGriffith lab RNA-Seq using HiSat & StringTie tutorial\nHBC Training DGE using DeSeq2 tutorial\nHemberg lab scRNA-Seq tutorial\nRNA-Seq Blog\nSciLifeLab courses" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#section", + "href": "topics/rnaseq/slide_rnaseq.html#section", + "title": "Bulk RNASeq Analysis", + "section": "", + "text": "Thank you. Questions?" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#references", + "href": "topics/rnaseq/slide_rnaseq.html#references", + "title": "Bulk RNASeq Analysis", + "section": "References", + "text": "References\n\n\nBaruzzo, G., Hayer, K. E., Kim, E. J., Di Camillo, B., FitzGerald, G. A., & Grant, G. R. (2017). Simulation-based comprehensive benchmarking of RNA-seq aligners. Nature Methods, 14(2), 135–139. https://www.nature.com/articles/nmeth.4106\n\n\nChhangawala, S., Rudy, G., Mason, C. E., & Rosenfeld, J. A. (2015). The impact of read length on quantification of differentially expressed genes and splice junction detection. Genome Biology, 16(1), 1–10. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4531809/\n\n\nConesa, A., Madrigal, P., Tarazona, S., Gomez-Cabrero, D., Cervera, A., McPherson, A., Szcześniak, M. W., Gaffney, D. J., Elo, L. L., Zhang, X., et al. (2016). A survey of best practices for RNA-seq data analysis. Genome Biology, 17(1), 1–19.\n\n\nCorley, S. M., MacKenzie, K. L., Beverdam, A., Roddam, L. F., & Wilkins, M. R. (2017). Differentially expressed genes from RNA-seq and functional enrichment results are affected by the choice of single-end versus paired-end reads and stranded versus non-stranded protocols. BMC Genomics, 18(1), 1–13. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5442695/\n\n\nDaley, T., & Smith, A. D. (2013). Predicting the molecular complexity of sequencing libraries. Nature Methods, 10(4), 325–327. https://www.nature.com/articles/nmeth.2375\n\n\nDillies, M.-A., Rau, A., Aubert, J., Hennequet-Antier, C., Jeanmougin, M., Servant, N., Keime, C., Marot, G., Castel, D., Estelle, J., et al. (2013). A comprehensive evaluation of normalization methods for illumina high-throughput RNA sequencing data analysis. Briefings in Bioinformatics, 14(6), 671–683.\n\n\nEvans, C., Hardin, J., & Stoebel, D. M. (2018). Selecting between-sample RNA-seq normalization methods from the perspective of their assumptions. Briefings in Bioinformatics, 19(5), 776–792.\n\n\nFrancis, W. R., Christianson, L. M., Kiko, R., Powers, M. L., Shaner, N. C., & D Haddock, S. H. (2013). A comparison across non-model animals suggests an optimal sequencing depth for de novotranscriptome assembly. BMC Genomics, 14(1), 1–12. https://bmcgenomics.biomedcentral.com/articles/10.1186/1471-2164-14-167\n\n\nFu, Y., Wu, P.-H., Beane, T., Zamore, P. D., & Weng, Z. (2018). Elimination of PCR duplicates in RNA-seq and small RNA-seq using unique molecular identifiers. Bmc Genomics, 19, 1–14.\n\n\nGallego Romero, I., Pai, A. A., Tung, J., & Gilad, Y. (2014). RNA-seq: Impact of RNA degradation on transcript quantification. BMC Biology, 12(1), 1–13. https://bmcbiol.biomedcentral.com/articles/10.1186/1741-7007-12-42\n\n\nHart, S. N., Therneau, T. M., Zhang, Y., Poland, G. A., & Kocher, J.-P. (2013). Calculating sample size estimates for RNA sequencing data. Journal of Computational Biology, 20(12), 970–978. https://www.liebertpub.com/doi/10.1089/cmb.2012.0283\n\n\nHsieh, P.-H., Oyang, Y.-J., & Chen, C.-Y. (2019). Effect of de novo transcriptome assembly on transcript quantification. Scientific Reports, 9(1), 8304. https://www.nature.com/articles/s41598-019-44499-3\n\n\nKlepikova, A. V., Kasianov, A. S., Chesnokov, M. S., Lazarevich, N. L., Penin, A. A., & Logacheva, M. (2017). Effect of method of deduplication on estimation of differential gene expression using RNA-seq. PeerJ, 5, e3091. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5357343/\n\n\nLevin, J. Z., Yassour, M., Adiconis, X., Nusbaum, C., Thompson, D. A., Friedman, N., Gnirke, A., & Regev, A. (2010). Comprehensive comparative analysis of strand-specific RNA sequencing methods. Nature Methods, 7(9), 709–715. https://www.nature.com/articles/nmeth.1491\n\n\nLiao, Y., & Shi, W. (2020). Read trimming is not required for mapping and quantification of RNA-seq reads at the gene level. NAR Genomics and Bioinformatics, 2(3), lqaa068. https://pubmed.ncbi.nlm.nih.gov/33575617/\n\n\nLiu, Y., Zhou, J., & White, K. P. (2014). RNA-seq differential expression studies: More sequence or more replication? Bioinformatics, 30(3), 301–304. https://academic.oup.com/bioinformatics/article/30/3/301/228651\n\n\nManimaran, S., Selby, H. M., Okrah, K., Ruberman, C., Leek, J. T., Quackenbush, J., Haibe-Kains, B., Bravo, H. C., & Johnson, W. E. (2016). BatchQC: Interactive software for evaluating sample and batch effects in genomic data. Bioinformatics, 32(24), 3836–3838.\n\n\nMarioni, J. C., Mason, C. E., Mane, S. M., Stephens, M., & Gilad, Y. (2008). RNA-seq: An assessment of technical reproducibility and comparison with gene expression arrays. Genome Research, 18(9), 1509–1517. https://genome.cshlp.org/content/18/9/1509.long\n\n\nParekh, S., Ziegenhain, C., Vieth, B., Enard, W., & Hellmann, I. (2016). The impact of amplification on differential expression analyses by RNA-seq. Scientific Reports, 6(1), 25533. https://www.nature.com/articles/srep25533\n\n\nRoberts, A., Trapnell, C., Donaghey, J., Rinn, J. L., & Pachter, L. (2011). Improving RNA-seq expression estimates by correcting for fragment bias. Genome Biology, 12(3), 1–14.\n\n\nSchurch, N. J., Schofield, P., Gierliński, M., Cole, C., Sherstnev, A., Singh, V., Wrobel, N., Gharbi, K., Simpson, G. G., Owen-Hughes, T., et al. (2016). How many biological replicates are needed in an RNA-seq experiment and which differential expression tool should you use? Rna, 22(6), 839–851. https://rnajournal.cshlp.org/content/early/2016/03/30/rna.053959.115.abstract\n\n\nSeyednasrollah, F., Laiho, A., & Elo, L. L. (2015). Comparison of software packages for detecting differential expression in RNA-seq studies. Briefings in Bioinformatics, 16(1), 59–70.\n\n\nSigurgeirsson, B., Emanuelsson, O., & Lundeberg, J. (2014). Sequencing degraded RNA addressed by 3’tag counting. PloS One, 9(3), e91851. https://pubmed.ncbi.nlm.nih.gov/24632678/\n\n\nSoneson, C., Love, M. I., & Robinson, M. D. (2015). Differential analyses for RNA-seq: Transcript-level estimates improve gene-level inferences. F1000Research, 4.\n\n\nTeng, M., Love, M. I., Davis, C. A., Djebali, S., Dobin, A., Graveley, B. R., Li, S., Mason, C. E., Olson, S., Pervouchine, D., et al. (2016). A benchmark for RNA-seq quantification pipelines. Genome Biology, 17(1), 1–12.\n\n\nWagner, G. P., Kin, K., & Lynch, V. J. (2012). Measurement of mRNA abundance using RNA-seq data: RPKM measure is inconsistent among samples. Theory in Biosciences, 131, 281–285.\n\n\nWang, S., & Gribskov, M. (2017). Comprehensive evaluation of de novo transcriptome assembly programs and their effects on differential gene expression analysis. Bioinformatics, 33(3), 327–333. https://academic.oup.com/bioinformatics/article/33/3/327/2580374\n\n\nZhang, C., Zhang, B., Lin, L.-L., & Zhao, S. (2017). Evaluation and comparison of computational tools for RNA-seq isoform quantification. BMC Genomics, 18(1), 1–11.\n\n\nZhao, S., Li, C.-I., Guo, Y., Sheng, Q., & Shyr, Y. (2018). RnaSeqSampleSize: Real data based sample size estimation for RNA sequencing. BMC Bioinformatics, 19(1), 1–8. https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-018-2191-5\n\n\nZhao, S., Zhang, Y., Gordon, W., Quan, J., Xi, H., Du, S., Schack, D. von, & Zhang, B. (2015). Comparison of stranded and non-stranded RNA-seq transcriptome profiling and investigation of gene overlap. BMC Genomics, 16(1), 1–14. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4559181/\n\n\nZindler, T., Frieling, H., Neyazi, A., Bleich, S., & Friedel, E. (2020). Simulating ComBat: How batch correction can lead to the systematic introduction of false positive results in DNA methylation microarray studies. BMC Bioinformatics, 21, 1–15." + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#hands-on-tutorial", + "href": "topics/rnaseq/slide_rnaseq.html#hands-on-tutorial", + "title": "Bulk RNASeq Analysis", + "section": "Hands-On tutorial", + "text": "Hands-On tutorial\nMain exercise\n\n01 Check the quality of the raw reads with FastQC\n02 Map the reads to the reference genome using HISAT2\n03 Assess the post-alignment quality using QualiMap\n04 Count the reads overlapping with genes using featureCounts\n05 Find differentially expressed genes using DESeq2 in R\n\nBonus exercises\n\n01 Functional annotation of DE genes using GO/Reactome/Kegg databases\n02 RNA-Seq figures and plots using R\n03 Visualisation of RNA-seq BAM files using IGV genome browser\n\nData: /sw/courses/ngsintro/rnaseq/\nWork: /proj/naiss2023-22-862/nobackup/user/rnaseq/" + }, + { + "objectID": "topics/rnaseq/slide_rnaseq.html#hands-on-tutorial-1", + "href": "topics/rnaseq/slide_rnaseq.html#hands-on-tutorial-1", + "title": "Bulk RNASeq Analysis", + "section": "Hands-On tutorial", + "text": "Hands-On tutorial\n\n\n\nCourse data directory\n\n/sw/courses/ngsintro/rnaseq/\nrnaseq/\n+-- bonus/\n| +-- assembly/\n| +-- exon/\n| +-- funannot/\n| +-- plots/\n+-- documents/\n+-- main/\n +-- 1_raw/\n +-- 2_fastqc/\n +-- 3_mapping/\n +-- 4_qualimap/\n +-- 5_dge/\n +-- 6_multiqc/\n +-- reference/\n | +-- mouse_chr19_hisat2/\n +-- scripts/\n\n\nYour work directory\n\n/proj/naiss2023-22-862/nobackup/user/rnaseq/\n[user]/\nrnaseq/\n +-- 1_raw/\n +-- 2_fastqc/\n +-- 3_mapping/\n +-- 4_qualimap/\n +-- 5_dge/\n +-- 6_multiqc/\n +-- reference/\n | +-- mouse_chr19_hisat2/\n +-- scripts/\n +-- funannot/\n +-- plots/" + }, + { + "objectID": "topics/other/lab_tetralith.html", + "href": "topics/other/lab_tetralith.html", + "title": "Working on Tetralith cluster", + "section": "", + "text": "The ThinLinc client can be downloaded for free from http://www.cendio.com/downloads/clients/. It is available for Windows, Mac OS X, Linux and Solaris.\nTo use ThinLinc to connect to Tetralith:\n\nIf you haven’t already done so, download the ThinLinc client matching your local computer (i.e Windows, Linux, MacOS X or Solaris) and install it.\nStart the client.\nChange the “Server” setting to “tetralith.nsc.liu.se”.\nChange the “Name” setting to your Tetralith username (e.g x_abcde).\nYou do not need to change any other settings.\nEnter your cluster Tetralith password in the “Password” box.\nPress the “Connect” button.\nEnter the 6-digit code generated by the two-factor authentication app on your phone.\nIf you connect for the first time, you will see the “The server’s host key is not cached …” dialog. Verify that the fingerprint shown on your screen matches the one listed below! If it does not match, press Abort and then contact NSC Support!\n\nTetralith SSH server host key fingerprint: 20:19:f4:6b:38:d6:e7:ac:e6:7c:8e:38:0a:7f:34:dc\nAfter a few seconds, a window with a simple desktop session in it will appear. From the Applications menu, start a Terminal Window." + }, + { + "objectID": "topics/other/lab_tetralith.html#connect-to-nsc-via-thinlinc", + "href": "topics/other/lab_tetralith.html#connect-to-nsc-via-thinlinc", + "title": "Working on Tetralith cluster", + "section": "", + "text": "The ThinLinc client can be downloaded for free from http://www.cendio.com/downloads/clients/. It is available for Windows, Mac OS X, Linux and Solaris.\nTo use ThinLinc to connect to Tetralith:\n\nIf you haven’t already done so, download the ThinLinc client matching your local computer (i.e Windows, Linux, MacOS X or Solaris) and install it.\nStart the client.\nChange the “Server” setting to “tetralith.nsc.liu.se”.\nChange the “Name” setting to your Tetralith username (e.g x_abcde).\nYou do not need to change any other settings.\nEnter your cluster Tetralith password in the “Password” box.\nPress the “Connect” button.\nEnter the 6-digit code generated by the two-factor authentication app on your phone.\nIf you connect for the first time, you will see the “The server’s host key is not cached …” dialog. Verify that the fingerprint shown on your screen matches the one listed below! If it does not match, press Abort and then contact NSC Support!\n\nTetralith SSH server host key fingerprint: 20:19:f4:6b:38:d6:e7:ac:e6:7c:8e:38:0a:7f:34:dc\nAfter a few seconds, a window with a simple desktop session in it will appear. From the Applications menu, start a Terminal Window." + }, + { + "objectID": "topics/other/lab_tetralith.html#interactive-session", + "href": "topics/other/lab_tetralith.html#interactive-session", + "title": "Working on Tetralith cluster", + "section": "2 Interactive session", + "text": "2 Interactive session\nStart an interactive session with three compute cores for todays lab:\n\n\ninteractive -A naiss2023-22-862 -t 04:00:00 -n 3\n\n\nPlease adjust the requested time depending on what lab you will be working on. After a minute or so you should have gotten your interactive job.\n\n\n\n\n\n\nTip\n\n\n\nNote that your terminal prompt changed from <nsc_username>@tetralith$ to something like <nsc_username>@n424$ (or another node name), which means that you are now running on one of the compute nodes." + }, + { + "objectID": "topics/other/lab_tetralith.html#uppmax-singularity-container", + "href": "topics/other/lab_tetralith.html#uppmax-singularity-container", + "title": "Working on Tetralith cluster", + "section": "3 UPPMAX singularity container", + "text": "3 UPPMAX singularity container\nWe will use a singularity container (a virtual computer) that mimics the UPPMAX computing environment. Once you have started the singularity container your environment will look exactly as on UPPMAX, and the software used in this workshop will be available through the module system inside the container. Use this command to start the singularity container:\n\n\nsingularity shell -B /proj/naiss2023-22-862/users:/proj/naiss2023-22-862/nobackup -B /proj/naiss2023-22-862 /proj/naiss2023-22-862/ngsintro.sif\n\n\n\n\n\n\n\n\nTip\n\n\n\nYour terminal prompt changed to something like <nsc_username>@offline-uppmax$. This means that you have moved into a “virtual computer” that mimics the UPPMAX environment.\n\n\nIn the singularity container type this to make the module system behave properly:\n\n\nsource /uppmax_init\n\n\nEverything from this point and onwards should be identical to running the exercise on UPPMAX. To close the singularity container later on just type exitin the terminal, but don’t do that now.\n\n\n\n\n\n\nNote\n\n\n\nNote: Since this is not actually running on uppmax, none of the queue system commands (squeue, sbatch, jobinfo etc) will work." + }, + { + "objectID": "topics/other/lab_tetralith.html#cluster-workspace", + "href": "topics/other/lab_tetralith.html#cluster-workspace", + "title": "Working on Tetralith cluster", + "section": "4 Cluster workspace", + "text": "4 Cluster workspace\nWhile running the UPPMAX singularity container, create a workspace for this exercise. This will be the “cluster workspace” in which you should perform the analyses, as if you would have worked on UPPMAX.\nThe name of the workspace depends on what lab you are working on. For example, if you are working on the introduction to Linux lab then call the workspace “linux_tutorial”. Once the workspace is created you should go into it.\n\n\nmkdir /proj/naiss2023-22-862/nobackup/<nsc_username>/linux_tutorial\ncd /proj/naiss2023-22-862/nobackup/<nsc_username>/linux_tutorial\n\n\nWhen you have the UPPMAX singularity container up and running you can follow regular lab instructions, except that you should not connect to UPPMAX or book a node, and you should work in the cluster workspace defined here. Also, IGV is started with a special command,see below." + }, + { + "objectID": "topics/other/lab_tetralith.html#igv", + "href": "topics/other/lab_tetralith.html#igv", + "title": "Working on Tetralith cluster", + "section": "5 IGV", + "text": "5 IGV\nTo start IGV at NSC type this in the command:\n\n\n/proj/naiss2023-22-862/igv/igv.sh\n\n\nYou can use the same command both when running the UPPMAX singularity container and from a normal terminal window at NSC." + }, + { + "objectID": "topics/other/lab_tetralith.html#exit-the-uppmax-singularity-container", + "href": "topics/other/lab_tetralith.html#exit-the-uppmax-singularity-container", + "title": "Working on Tetralith cluster", + "section": "6 Exit the UPPMAX singularity container", + "text": "6 Exit the UPPMAX singularity container\nWhen you are done with the lab just type exit to close the singularity container:\n\n\noffline-uppmax$ exit\n\n\nAll files and folders that you create in /proj/naiss2023-22-862/nobackup/nsc_username/ while running the singularity container can be reached also from outside of the container, in this folder on Tetralith:\n\n\n/proj/naiss2023-22-862/users/<nsc_username>/" + }, + { + "objectID": "topics/other/lab_open_session.html", + "href": "topics/other/lab_open_session.html", + "title": "Open session", + "section": "", + "text": "0.1 Friday at 13:15\n\n\n\n\n\n\nRoom\nTopic\nStaff\n\n\n\n\nRoom 1\nWhole genome sequencing, variant calling\nMalin Larsson, Diana Ekman\n\n\nRoom 2\nRNA-Seq, scRNA-Seq\nJulie Lorent, Juliana Assis, Prasoon Agarwal, Roy Francis\n\n\nRoom 3\nBash, Uppmax, Computing\nMartin Dahlö\n\n\nRoom 4\nEpigenetics, Chip-Seq, RNA-Seq, scRNASeq, small RNA\nAgata Smialowska, Vincent van Hoef\n\n\nRoom 5\nNGI, Assembly, Long read sequencing\nAdam Ameur, Estelle Proux\n\n\nRoom 6\nMetagenomics, Prokaryots, RNA-Seq\nDag Ahrén, Lokesh Manoharan, John Sundh" + }, + { + "objectID": "topics/other/lab_download_files.html", + "href": "topics/other/lab_download_files.html", + "title": "Uppmax IO", + "section": "", + "text": "Note\n\n\n\nIn code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window." + }, + { + "objectID": "topics/other/lab_download_files.html#local-workspace", + "href": "topics/other/lab_download_files.html#local-workspace", + "title": "Uppmax IO", + "section": "1 Local workspace", + "text": "1 Local workspace\nStart by creating a folder on your laptop where the files that you will download should end up. You need to have write permission in this folder. This folder will be referred to as your local workspace throughout these instructions.\nOpen a terminal window on your laptop and move into your local workspace." + }, + { + "objectID": "topics/other/lab_download_files.html#download-a-file-from-uppmax", + "href": "topics/other/lab_download_files.html#download-a-file-from-uppmax", + "title": "Uppmax IO", + "section": "2 Download a file from UPPMAX", + "text": "2 Download a file from UPPMAX\nLets assume that you have a file “results.txt” in the following folder on UPPMAX:\n\n\n/proj/naiss2023-22-862/nobackup/username/somefolder/\n\n\n\n\n\n\n\n\nNote\n\n\n\nusername and somefolder should be replaced with your real username and a real folder name.\n\n\nTo download the file to your local workspace type:\n\n\nLocal Terminal\n\nscp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/somefolder/results.txt .\n\nNote that the last . means that the file will keep the original name." + }, + { + "objectID": "topics/other/lab_download_files.html#upload-a-file-to-uppmax", + "href": "topics/other/lab_download_files.html#upload-a-file-to-uppmax", + "title": "Uppmax IO", + "section": "3 Upload a file to UPPMAX", + "text": "3 Upload a file to UPPMAX\nNow lets imagine that you have developed a script on your laptop and want to upload it to UPPMAX. The script is stored in your local workspace and is called “script.sh”. Type this in your local workspace to upload the file to UPPMAX:\n\n\n\n\n\n\nNote\n\n\n\nusername and somefolder should be replaced with your real username and a real folder name.\n\n\n\n\nLocal Terminal\n\nscp script.sh username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/somefolder/." + }, + { + "objectID": "topics/linux/lab_linux_permissions.html", + "href": "topics/linux/lab_linux_permissions.html", + "title": "File permissions", + "section": "", + "text": "Note\n\n\n\nIn code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window." + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#ownership-permissions", + "href": "topics/linux/lab_linux_permissions.html#ownership-permissions", + "title": "File permissions", + "section": "1 Ownership & Permissions", + "text": "1 Ownership & Permissions\nAs Linux can be a multi-user environment it is important that files and directories can have different owners and permissions to keep people from editing or executing your files.\n\n1.1 Owners\nThe permissions are defined separately for users, groups and others.\nThe user is the username of the person who owns the file. By default the user who creates a file will become its owner. The group is a group of users that co-own the file. They will all have the same permissions to the file. This is useful in any project where a group of people are working together. The others is quite simply everyone else’s permissions.\n\n\n1.2 Permissions\nThere are four permissions that a file or directory can have. Note the one character designations/flags, r,w,x and -.\nIn all cases, if the file or directory has the flag it means that it is enabled.\nRead: r\nFile: Whether the file can be opened and read.\nDirectory: Whether the contents of the directory can be listed.\nWrite: w\nFile: Whether the file can be modified. (Note that for renaming or deleting a file you need additional directory permissions.)\nDirectory: Whether the files in the directory can be renamed or deleted.\nExecute: x\nFile: Whether the file can be executed as a program or shell script.\nDirectory: Whether the directory can be entered using cd.\nNo permissions: -" + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#interpreting-permissions", + "href": "topics/linux/lab_linux_permissions.html#interpreting-permissions", + "title": "File permissions", + "section": "2 Interpreting permissions", + "text": "2 Interpreting permissions\nMake an empty directory we can work in and make a file.\n\n\n$ cd /proj/naiss2023-22-862/nobackup/username\n$ mkdir advlinux\n$ cd advlinux\n$ touch filename\n$ ls -lh\ntotal 0\n -rw-r--r-- 1 S_D staff 0B Sep 21 13:54 filename\n\n\n(-lh means long and human readable, displaying more information about the files or directories in a human understandable format)\nThis shows us a cryptic line for each file/folder, where the columns are as following:\n-rw-rw-r-- : permissions\n1 : number of linked hard-links\nS_D : owner of the file\nstaff : to which group this file belongs to\n0 : file size\nSep 21 13:54 : modification/creation date and time\nfilename : file/directory name\nThe first segment, -rw-r--r--, describes the ownerships and permissions of our newly created file. The very first character, in this case -, shows the file’s type. It can be any of these:\nd = directory - = regular file l = symbolic link s = Unix domain socket p = named pipe c = character device file b = block device file\nAs expected the file we have just created is a regular file. Ignore the types other than directory, regular and symbolic link as they are outside the scope of this course.\nThe next nine characters, in our case rw-r--r--, can be divided into three groups consisting of three characters in order from left to right. In our case rw-, r-- and r--. The first group designates the users permissions, the second the groups permissions and the third the others permissions. As you may have guessed the within group permissions are ordered, the first always designates read permissions, the second write and the third executability.\nThis translates our files permissions to say this -rw-r--r--:\n- It is a regular file.\n- The user has read & write permission, but not execute.\n- The group has read permission but not write and execute.\n- Everyone else (other), have read permission but not write and execute.\nAs another example, lets create a directory.\n$ mkdir directoryname\n$ ls -lh\ntotal 0\ndrwxr-xr-x 2 S_D staff 68B Sep 21 14:41 directoryname\n-rw-r--r-- 1 S_D staff 0B Sep 21 13:54 filename\nAs you can see the first character correctly identifies it as d, a directory, and all user groups have x, execute permissions, to enter the directory by default." + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#editing-ownership-permissions", + "href": "topics/linux/lab_linux_permissions.html#editing-ownership-permissions", + "title": "File permissions", + "section": "3 Editing Ownership & Permissions", + "text": "3 Editing Ownership & Permissions\nThe command to set file permission is chmod which means CHange MODe. Only the owner can set file permissions.\n\nFirst you decide which group you want to set permissions for. User, u, group, g, other, o, or all three, a.\nNext you either add, +, remove, -, or wipe out previous and add new, =, permissions.\nThen you specify the kind of permission: r,w,x, or -.\n\nLets revisit our example file and directory to test this.\n$ ls -lh\ntotal 0\ndrwxr-xr-x 2 S_D staff 68B Sep 21 14:41 directoryname\n-rw-r--r-- 1 S_D staff 0B Sep 21 13:54 filename\n$ chmod a=x filename\n$ ls -lh\ntotal 0\ndrwxr-xr-x 2 S_D staff 68B Sep 21 14:41 directoryname\n---x--x--x 1 S_D staff 0B Sep 21 13:54 filename\nAs you can see this affected all three, a, it wiped the previous permissions, =, and added an executable permission, x, to all three groups.\nTry some others both on the file and directory to get the hang of it.\n$ chmod g+r filename\n$ chmod u-x filename\n$ chmod ug=rx filename\n$ chmod a=- filename\n$ chmod a+w directoryname\n In no more than two commands, change the file permissions from\n----------\nto\n-rw-rw--wx\nNotice also that we here gave everyone writing permission to the file, that means that ANYONE can write to the file. Not very safe.\n\n\n$ chmod ug+rw filename \n$ chmod o=wx filename" + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#symbolic-links", + "href": "topics/linux/lab_linux_permissions.html#symbolic-links", + "title": "File permissions", + "section": "4 Symbolic links", + "text": "4 Symbolic links\n\n4.1 Files\nMuch like a windows user has a shortcut on his desktop to WorldOfWarcraft.exe, being able to create links to files or directories is good to know in Linux. An important thing to remember about symbolic links is that they are not updated, so if you or someone else moves or removes the original file/directory the link will stop working.\nMake sure you are standing in the directory /proj/naiss2023-22-862/nobackup/username/advlinux. Then remove our old file and directory.\n\n Danger\nrm -r * permanently removes all folder and subfolders from where you are standing. Be extremely careful when using this. Always double check current working directory or path.\n\n$ rm -r *\nNow that the directory is empty, let’s make a new folder and a new file in that folder.\n$ mkdir stuff\n$ touch stuff/linkfile\nLets put some information into the file, just put some text, anything, like “slartibartfast” or something.\n$ nano stuff/linkfile\nNow let’s create a link to this file in our original folder. ln stands for link and -s makes it symbolic. The other options are not in the scope of this course, but feel free to read about them on your own, https://stackoverflow.com/a/29786294\n$ ln -s stuff/linkfile\n$ ls -l\n\ntotal 8\nlrwxr-xr-x 1 S_D staff 14B Sep 21 15:38 linkfile -> stuff/linkfile\ndrwxr-xr-x 3 S_D staff 102B Sep 21 15:36 stuff\nNotice that we see the type of the file is l, for symbolic link, and that we have a pointer after the links name for where the link goes, -> stuff/linkfile.\nIf want you to change the information in the file using the link file, then you should change the information in the original file.\n Change the information using the original file, then check the link. Has the information changed in the original file and the linked file?\n Now move or delete the original file. What happens to the link? What information is there now if you open the link?\n Now create a new file in stuff/ with exactly the same name that your link file is pointing too with new information in it. What happens now? Is the link still broken? What is the content of the linked file now?\n\n\n4.2 Directories\nNow let’s create a link to a directory. Lets clean our workspace.\n$ rm -r *\nAnd create a directory three, arbitrarily, two directories away. The -p option to mkdir will make it create all 3 directories as needed. Without it, it would crash saying it can’t create three because the directory two does not exist.\n$ mkdir -p one/two/three\nNow let’s enter the directory and create some files there.\n$ cd one/two/three\n$ touch a b c d e\n$ ls -lh\n\ntotal 0\n-rw-r--r-- 1 S_D staff 0B Sep 21 16:11 a\n-rw-r--r-- 1 S_D staff 0B Sep 21 16:11 b\n-rw-r--r-- 1 S_D staff 0B Sep 21 16:11 c\n-rw-r--r-- 1 S_D staff 0B Sep 21 16:11 d\n-rw-r--r-- 1 S_D staff 0B Sep 21 16:11 e\nReturn to our starting folder and create a symbolic link to folder three.\n$ cd ../../..\n$ ln -s one/two/three\n$ ls -lh\n\ntotal 8\ndrwxr-xr-x 3 S_D staff 102B Sep 21 16:11 one\nlrwxr-xr-x 1 S_D staff 13B Sep 21 16:13 three -> one/two/three\nOnce again, we see that it is correctly identified as a symbolic link, l, that it’s default name is the same as the directory it is pointing to, same as the files link had the same name as the file by default previously, and that we have the additional pointer after the links name showing us where it’s going.\n Run ls and cd on the link. Does it act just as if you were standing in directory two/ performing the very same actions on three/?\n After entering the link directory using cd, go back one step using cd .., where do you end up?\nMoving, deleting or renaming the directory would, just like in the case with the file, break the link." + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#grep", + "href": "topics/linux/lab_linux_permissions.html#grep", + "title": "File permissions", + "section": "5 Grep", + "text": "5 Grep\nSome files can be so large that opening it in a program would be very hard on your computer. It could be a file containing biological data, it could be a log file of a transfer where we want check for any errors. No matter the reason, a handy tool to know is the grep command.\ngrep searches for a specific string in one or more files. Case sensitive/insensitive or regular expressions work as well.\nLet’s start, as always, by cleaning our directory.\n$ rm -r *\nThen let’s create a file with some text in it that we can work with. I have supplied some great text below.\n$ nano textfile\n\nCats sleep anywhere, any table, any chair.\nTop of piano, window-ledge, in the middle, on the edge.\nOpen draw, empty shoe, anybody's lap will do.\nFitted in a cardboard box, in the cupboard with your frocks.\nAnywhere! They don't care! Cats sleep anywhere.\nNow let’s see how the grep command works. The syntax is:\ngrep \"string\" filename/filepattern\nSome examples for you to try and think about:\n$ grep \"Cat\" textfile\n$ grep \"cat\" textfile\nAs you can see the last one did not return any results. Add a -i for case insensitive search.\n$ grep -i \"cat\" textfile\nNow let’s copy the file and check both of them together by matching a pattern for the filenames.\n$ cp textfile textcopy\n$ grep \"Cat\" text*\nThe * will ensure that any file starting with text and then anything following will be searched. This example would perhaps be more real if we had several text files with different texts and we were looking for a specific string in any of them.\nCopy the file sample_1.sam to your folder using the command below\n$ cp /sw/courses/ngsintro/linux/linux_additional-files/sample_1.sam .\n Use grep to search in the file for a specific string of nucleotides, for example:\n$ grep \"TACCACCGAAATCTGTGCAGAGGAGAACGCAGCTCCGCCCTCGCGGTGCTCTCCGGGTCTGTGCTGAGGAG\" sample_1.sam\n Try with shorter sequences. When do you start getting lots of hits? This file is only a fraction of a genome, you would have gotten many times more hits doing this to a complete many GB large sam file.\n Use grep to find all lines with chr1 in them. This output is too much to be meaningful. Send it to a file (>) where you have now effectively stored all the chromosome 1 information." + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#piping", + "href": "topics/linux/lab_linux_permissions.html#piping", + "title": "File permissions", + "section": "6 Piping", + "text": "6 Piping\nA useful tool in linux environment is the use of pipes. What they essentially do is connect the first command to the second command and the second command to the third command etc for as many commands as you want or need.\nThis is often used in UPPMAX jobs and other analysis as there are three major benefits. The first is that you do not have to stand in line to get a core or a node twice. The second is that you do not generate intermediary data which will clog your storage, you go from start file to result. The third is that it may actually be faster.\nThe pipe command has this syntax\ncommand 1 | command 2\nThe | is the pipe symbol (on mac keyboard alt+7), signifying that whatever output usually comes out of command 1 should instead be directly sent to command 2 and output in the manner that command 2 inputs.\nIn a hypothetical situation you have a folder with hundreds of files and you know the file you are looking for is very large but you can’t remember its name.\nLet’s do a ls -l in the /etc directory and pipe the output to be sorted by file size. -n means we are sorting numerically and not alphabetically, -k 5 says look at the fifth column of output, which happens to be the file size of ls command.\n$ ls -l /etc | sort -k 5 -n\nAn example use would be to align a file and directly send the now aligned file to be converted into a different format that may be required for another part of the analysis.\nThe next step requires us to use a bioinformatics software called samtools. To be able to use this program we first have to load the module for it. We will cover this in the UPPMAX lectures, so if you are a bit too fast for you own good, you will just have to type this command:\n$ module load bioinfo-tools samtools\nHere is an example where we convert the samfile to a bamfile (-Sb literally means the input is Sam and to output in bam) and pipe it to immediately get sorted, not even creating the unsorted bamfile intermediary. Notice that samtools is made to take the single - after samtools sort as the position of the piped data from samtools view.\n$ samtools view -bS sample_1.sam | samtools sort - -o outbam\nThis should have generated a file called outbam.bam in your current folder. We will have some more examples of pipes in the next section." + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#word-count", + "href": "topics/linux/lab_linux_permissions.html#word-count", + "title": "File permissions", + "section": "7 Word Count", + "text": "7 Word Count\nwc for Word Count is a useful command for counting the number of occurrences of a word in a file. This is easiest explained with an example.\nLet’s return to our sample_1.sam.\n$ wc sample_1.sam\n233288 3666760 58105794 sample_1.sam\nThis can be interpreted like this:\nNumber of lines = 233288\nNumber of words = 3666760\nNumber of characters = 58105794\nTo make this more meaningful, let’s use the pipes and grep command seen previously to see how many lines and how many times the string of nucleotides CATCATCAT exist in this file.\n$ grep \"CATCATCAT\" sample_1.sam | wc\n60 957 15074\nTo see only the line count you can add -l after wc and to count only characters -m.\n Output only the amount of lines that have chr1 in them from sample_1.sam.\n\n\n$ grep \"chr1\" sample_1.sam | wc -l\n\n\n Count the lines containing CATCATCAT in the outbam.bam file.\n\n\n$ samtools view outbam.bam | grep \"CATCATCAT\" | wc -l" + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#bonus-exercise-1", + "href": "topics/linux/lab_linux_permissions.html#bonus-exercise-1", + "title": "File permissions", + "section": "8 Bonus exercise 1", + "text": "8 Bonus exercise 1\nThese are some harder assignments, so don’t worry about it if you didn’t have time to do it.\nLets look at grep and use some regular expressions http://www.cheatography.com/davechild/cheat-sheets/regular-expressions/\n From file sample_1.sam find all lines that start with @ and put them in a file called at.txt.\n\n\n$ grep \"^@\" sample_1.sam > at.txt\n\n\n Find all the lines that end with at least 3 numbers from at.txt. Sometimes, you have to escape {} with \\{\\})\n\n\n$ grep \"[0-9]\\{3\\}$\" sample_1.sam" + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#bonus-exercise-2", + "href": "topics/linux/lab_linux_permissions.html#bonus-exercise-2", + "title": "File permissions", + "section": "9 Bonus exercise 2", + "text": "9 Bonus exercise 2\n[sed](http://www.grymoire.com/Unix/Sed.html) is a handy tool to replace strings in files.\n You have realized that all the chromosomes have been misnamed as chr3 when they should be chr4. Use sed to replace chr3 with chr4 in sample_1.sam and output it to sample_2.sam.\n The solution to this replaces the first instance on each line of chr3. What if we have multiple instances? What if we had wanted to replace chr1? This would effect chr10-19 as well! There are many things to consider :).\n\n\n$ sed \"s/chr1/chr2/\" sample_1.sam > sample_2.sam" + }, + { + "objectID": "topics/linux/lab_linux_permissions.html#bonus-exercise-3", + "href": "topics/linux/lab_linux_permissions.html#bonus-exercise-3", + "title": "File permissions", + "section": "10 Bonus exercise 3", + "text": "10 Bonus exercise 3\nBash loops are great for moving or renaming multiple files as well as many many other uses.\nCreate a couple of files as seen below\n$ touch one.bam two.sam three.bam four.sam five.bam six.sam\n All the files are actually in bam format. What a crazy mistake! Create a bash loop that changes all files ending in .sam to end with .bam instead.\n The bash loop syntax is this:\n$ for _variable_ in _pattern_; do _command with $variable_; done\n To rename file1 to file2 you write this:\n$ mv file1 file2\nwhich effectively is the same thing as\n$ cp file1 file2\n$ rm file1\n Ponder how this can be used to your advantage:\n$ i=filename\n$ echo ${i/name}stuff\nfilestuff\n\n\n$ for f in *.sam\ndo\n mv $f ${f/.sam}.bam;\ndone" + }, + { + "objectID": "topics/linux/lab_linux_filetypes.html", + "href": "topics/linux/lab_linux_filetypes.html", + "title": "Filetypes", + "section": "", + "text": "Note\n\n\n\nIn code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window." + }, + { + "objectID": "topics/linux/lab_linux_filetypes.html#connect-to-uppmax", + "href": "topics/linux/lab_linux_filetypes.html#connect-to-uppmax", + "title": "Filetypes", + "section": "1 Connect to UPPMAX", + "text": "1 Connect to UPPMAX\nThe first step of this lab is to open a ssh connection to UPPMAX. Please refer to Connecting to UPPMAX for instructions. Once connected to UPPMAX, return here and continue reading the instructions below." + }, + { + "objectID": "topics/linux/lab_linux_filetypes.html#logon-to-a-node", + "href": "topics/linux/lab_linux_filetypes.html#logon-to-a-node", + "title": "Filetypes", + "section": "2 Logon to a node", + "text": "2 Logon to a node\nUsually you would do most of the work in this lab directly on one of the login nodes at UPPMAX, but we have arranged for you to have one core each for better performance. This was covered briefly in the lecture notes.\n\n\nsalloc -A naiss2023-22-862 -t 07:00:00 -p core -n 1 --no-shell &\n\n\ncheck which node you got (replace username with your UPPMAX username)\n$ squeue -u username\nshould look something like this\ndahlo@rackham2 work $ squeue -u dahlo\n JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n 3132376 core sh dahlo R 0:04 1 r292\ndahlo@rackham2 work $\nwhere r292 is the name of the node I got (yours will probably be different). Note the numbers in the Time column. They show for how long the job has been running. When it reaches the time limit you requested (7 hours in this case) the session will shut down, and you will lose all unsaved data. Connect to this node from within UPPMAX.\n$ ssh -Y r292\n There is a UPPMAX specific tool called jobinfo that supplies the same kind of information as squeue that you can use as well ($ jobinfo -u username)." + }, + { + "objectID": "topics/linux/lab_linux_filetypes.html#copy-lab-files", + "href": "topics/linux/lab_linux_filetypes.html#copy-lab-files", + "title": "Filetypes", + "section": "3 Copy lab files", + "text": "3 Copy lab files\nNow you will need some files. To avoid all the course participants editing the same file all at once, undoing each other’s edits, each participant will get their own copy of the needed files. The files are located in the folder /sw/courses/ngsintro/linux/filetypes\nNext, copy the lab files from this folder. -r means recursively, which means all the files including sub-folders of the source folder. Without it, only files directly in the source folder would be copied, NOT sub-folders and files in sub-folders.\n Remember to use tab-complete to avoid typos and too much writing.\n\n\ncp -r <source> <destination>\ncp -r /sw/courses/ngsintro/linux/filetypes /proj/naiss2023-22-862/nobackup/username/\n\n\nHave a look in /proj/naiss2023-22-862/nobackup/username/.\n\n\ncd /proj/naiss2023-22-862/nobackup/username/filetypes\ntree\n\n\nThis will print a file tree, which gives you a nice overview of the folders where you are standing in. As you can see, you have a couple of files and a couple of empty folders. In the 0_ref folder you have a reference genome in fasta format and annotations for the genome in GTF format. In 0_seq you have a fastq file containing the reads we will align." + }, + { + "objectID": "topics/linux/lab_linux_filetypes.html#run-pipeline", + "href": "topics/linux/lab_linux_filetypes.html#run-pipeline", + "title": "Filetypes", + "section": "4 Run pipeline", + "text": "4 Run pipeline\nThe best way to see all the different file formats is to run a small pipeline and see which files we encounter along the way. The pipeline is roughly the same steps you’ll do in the variant-calling part of the course, so for now we’ll stick with the dummy pipeline which some of you might have encoutered in the extra material for the UPPMAX exercise.\nThe programs in the dummy pipeline does not actually do any analysis but they work the same way as the real deal, although slightly simplified, to get you familiar with how to work with analysis programs. The data is from a sequencing of the adenovirus genome, which is tiny compared to the human genome (36kb vs 3gb).\nThe starting point of the pipeline are fresh reads from the sequencing machine in fastq format, and a reference genome in fasta format. The goal of the exercise is to look at our aligned reads in a genome viewer together with the annotations of the adenovirus genome.\nFirst, let’s go through the steps of the pipeline:\n\nBuild an index for the reference genome. This will speed up the alignment process. Not possible to do the analysis without it.\nAlign the reads.\nConvert the SAM file to a BAM file. We want to use the space efficiently.\nSort the BAM file. We have to sort it to be able to index it.\nIndex the BAM file. We have to index it to make it fast to access the data in the file.\nView the aligned data together with the annotations.\n\nThe first thing you usually do is to load the modules for the programs you want to run. During this exercise we’ll only run my dummy scripts that don’t actually do any analysis, so they don’t have a module of their own. What we can do instead is to manually do what module loading usually does: to modify the $PATH variable.\nThe $PATH variable specifies directories where the computer should look for programs. For instance, when you type nano, how does the computer know which program to start? You gave it the name nano, but that could refer to any file named nano in the computer, yet it starts the correct one every time. The answer is that it looks in the directories stored in the $PATH variable.\nTo see which directories that are available by default, type\n$ echo $PATH\nIt should give you something like this, a list of directories, separated by colon signs:\ndahlo@rackham2 work $ echo $PATH\n/home/dahlo/perl//bin/:/home/dahlo/.pyenv/shims:/home/dahlo/.pyenv/bin:\n/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:\n/sbin:/opt/thinlinc/bin:/sw/uppmax/bin:/home/dahlo/usr/bin\nTry loading a module, and then look at the $PATH variable again. You’ll see that there are a few extra directories there now, after the module has been loaded.\ndahlo@rackham2 work $ module load bioinfo-tools samtools/1.10\ndahlo@rackham2 work $ echo $PATH\n/sw/apps/bioinfo/samtools/1.10/rackham/bin:/home/dahlo/perl/bin:/home/dahlo/.pyenv/shims:\n/home/dahlo/.pyenv/bin:/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:\n/usr/sbin:/sbin:/opt/thinlinc/bin:/sw/uppmax/bin:/home/dahlo/usr/bin\nTo pretend that we are loading a module, we will just add a the directory containing my dummy scripts to the $PATH variable, and it will be like we loaded the module for them.\n$ export PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts\nThis will set the $PATH variable to whatever it is at the moment, and add a directory at the end of it. Note the lack of a dollar sign in front of the variable name directly after export. You don’t use dollar sign when assigning values to variables, and you always use dollar signs when getting values from variables.\n\n Important\nThe export command affects only the terminal you type it in. If you have 2 terminals open, only the terminal you typed it in will have a modified path. If you close that terminal and open a new one, it will not have the modified path.\n\n\n4.1 Build index\n\nBuild an index for the reference genome.\nAlign the reads.\nConvert the SAM file to a BAM file.\nSort the BAM file.\nIndex the BAM file.\nView the aligned data together with the annotations.\n\nAll aligners will have to index the reference genome you are aligning your data against. This is only done once per reference genome, and then you reuse that index whenever you need it. All aligners have their own kind of index unfortunately, so you will have to build one index for each aligner you want to use. In this lab, we will use the dummy aligher called align_reads, and we will build a index using it’s indexing progam, called reference_indexer.\nFirst, have a look in the 0_ref folder\n$ ll 0_ref\nYou should see 2 files: the fasta file, the gtf file. Have a look at each of them with less, just to see how they look inside. To do the actual indexing of the genome:\n Run reference_indexer.\nSyntax: reference_indexer -r <name of the fasta file you want to index>\n\n\n$ reference_indexer -r 0_ref/ad2.fa\n\n\nSince the genome is so small this should only take a second or so. The human genome will probably take a couple of hours. Look in the 0_ref folder again and see if anything has changed.\n$ ll 0_ref\nThe new file you see is the index file created by reference_indexer. This index is in the same format as you would get from the real program samtools. Try viewing the index file with less and see how it looks. The samtools type of index contains one row per fasta record in the reference file. In this case, there is only one record for the adenovirus genome, and it’s called ad2 in the fasta file. The human reference genome typically have one record per chromosome, so a index of the human genome would then have 24 rows.\nThe numbers after the record name specifies how many bases the record has, how far into the file (in bytes) the record starts, the number of bases on each line in the record, and how many bytes each line takes up in the file. Using this information the program can quickly jump to the start location of each record, without having to read the file from the first row every time.\nOther aligners might use more complex indexing of the file to speed up the alignment process even further, e.g. creating an index over where it can find all possible “words” that you can form with 5 or so bases, making it easier to find possible matching sites for reads. If the read starts with ATGTT you can quickly look in the index and see all places in the geonome that contains this word and start looking if the rest of the read matches the area around the word.\nThis greatly decreases the number of places you have to look when looking for a match. These types of indexes usually take a long time to create (5+ hours maybe), but since you only have to do it once per reference genome it’s easily worth it, seeing how the alignment process probably would take 100s of hours without the index, instead of 6-12 hours.\nWe are now ready to align our reads.\n\n\n4.2 Align reads\n\nBuild an index for the reference genome.\nAlign the reads.\nConvert the SAM file to a BAM file.\nSort the BAM file.\nIndex the BAM file.\nView the aligned data together with the annotations.\n\n Align reads using align_reads, naming the output file ad2.sam, placed in the 1_alignment folder.\nSyntax: align_reads -r <reference genome> -i <fastq file with reads> -o <name of the output file>\n\n\n$ align_reads -r 0_ref/ad2.fa -i 0_seq/ad2.fq -o 1_alignment/ad2.sam\n\n\nThis will create a SAM file in 1_alignment called ad2.sam. Have a look at it with less. If you think the file looks messy, add a -S after less to make it stop wrapping long lines, less -S 1_alignment/ad2.sam and scroll sideways using the arrow keys. As you can see there is one row per aligned read in this file. Each row contains information about the read, like the name of the read, where in the reference genome it aligned, and also a copy of the reads sequence and quality score, among other things.\n\n\n4.3 SAM to BAM\n\nBuild an index for the reference genome.\nAlign the reads.\nConvert the SAM file to a BAM file.\nSort the BAM file.\nIndex the BAM file.\nView the aligned data together with the annotations.\n\n The next step is to convert the SAM file to a BAM file. This is more or less just compressing the file, like creating a zip file. To do that we will use the dummy program sambam_tools, telling it we want to convert a file to BAM (-f bam), which file we want to convert (-i), where it should save the resulting BAM file (-o). Save the BAM file in the 2_bam folder and name it ad2.bam.\nSyntax: sambam_tool -f bam -i <sam file> -o <bam>\n\n\n$ sambam_tool -f bam -i 1_alignment/ad2.sam -o 2_bam/ad2.bam\n\n\nHave a look in the 2_bam folder.\n$ ll 2_bam\nThe created BAM file is an exact copy of the SAM file, but stored in a much more efficient format. Aligners usually have an option to output BAM format directly, saving you the trouble to convert it yourself, but not all tools can do this (they really should though). Have a look at the difference in file size, though in this example it’s quite an extreme difference (2.9 MB vs 0.3 MB). The quality score of all reads is the same (BBBBBBBBB..), and files with less differences are easier to compress. Usually the BAM file is about 25% of the size of the SAM file.\nSince the BAM format is a binary format we can’t look at it with less. We would have to use a tool, like samtools which you will probably see later in the week, to first convert the file back to a SAM file before we can read it. In that case we can just look at the SAM file before converting it since they will be the same.\n\n\n4.4 Sort & index BAM\n\nBuild an index for the reference genome.\nAlign the reads.\nConvert the SAM file to a BAM file.\nSort the BAM file.\nIndex the BAM file.\nView the aligned data together with the annotations.\n\nA BAM file is taking up much less space than the SAM file, but we can still improve performance. An indexed BAM file is infinitely faster for programs to work with, but before we can index it, we have to sort it since it’s not possible to index an unsorted file in any meaningful way.\n To sort the BAM file we’ll use the sambam_tool again, but specifying a different function, -f sort instead. Tell it to store the sorted BAM file in the 3_sorted folder and name the file ad2.sorted.bam\nSyntax: sambam_tool -f sort -i <unsorted bam file> -o <sorted bam file>\n\n\n$ sambam_tool -f sort -i 2_bam/ad2.bam -o 3_sorted/ad2.sorted.bam\n\n\nThis will sort the ad2.bam file and create a new BAM file which is sorted, called ad2.sorted.bam.\n Now when we have a sorted BAM file, we can index it. Use the command\nSyntax: sambam_tool -f index -i <sorted bam file>\n\n\n$ sambam_tool -f index -i 3_sorted/ad2.sorted.bam\n\n\nThis will create an index named ad2.sorted.bam.bai in the same folder as the ad2.sorted.bam file is located. It’s nicer to have the .bam and .bai named to the same “prefix”, so rename the .bai file to not have the .bam in its name.\n$ mv 3_sorted/ad2.sorted.bam.bai 3_sorted/ad2.sorted.bai\n\n\n4.5 View in a genome viewer\n\nBuild an index for the reference genome.\nAlign the reads.\nConvert the SAM file to a BAM file.\nSort the BAM file.\nIndex the BAM file.\nView the aligned data together with the annotations.\n\nNow that we have to data aligned and prepared for easy access, we will view it in a genome viewer together with the annotations for the genome. Have a look at the annotations file with less.\n$ less -S 0_ref/ad2.gtf\nThe -S will tell less to not wrap the lines, and instead show one line per line. If the line is longer than the window, you can user the left and right arrow to scroll to the left and right. Many tabular files are much more readable when using the -S option. Try viewing the file without it and see the difference.\nTo view the file, we will use the program IGV (Integrated Genome Viewer). Before we can do this, we have to load the module for IGV.\n If you are using a Mac you might have to install the program XQuartz, if you have not already installed that program. By using -Y in your ssh command you enable graphical transfer over ssh, but you will also have to have a program able to receive the graphics in order to display it.\n$ module load bioinfo-tools IGV/2.4.2\nStart it by typing the following command (now we’ll find out if you used -Y in all your ssh connections!):\n$ igv.sh\n\n\n\n\n\n\nTip\n\n\n\nIf you notice that IGV over Xforwarding is excruciatingly slow, you can try to use the web based ThinLinc client instead. Unfortunately this requires you to have set up a two factor authentification (2FA) with UPPMAX, so it’s something you can try on your own. Instructions for setting up the 2FA at UPPMAX. When you are all set up, go to the address https://rackham-gui.uppmax.uu.se and login with your normal UPPMAX username and password together with your 2FA (described at the login screen). This will get you a remote desktop on one of the login nodes, and you can open a terminal and run IGV there instead. Once IGV is started, either using Xforwarding or the remote desktop in your web browser, we are ready to go.\n\n\nThere are 3 files we have to load in IGV.\nThe first is the reference genome. Press the menu button located at “Genomes - Load Genome from File…” and find your reference genome in 0_ref/ad2.fa. If you are having trouble finding your files, note that IGV always starts in your home directory. Use the dropdown menu at the top to navigate to /proj/naiss2023-22-862/nobackup/….\nThe second file you have to load is the reads. Press the menu button “File - Load from File…” and select your 3_sorted/ad2.sorted.bam.\nThe last file you have to load is the annotation data. Press “File - Load from File…” again and select you annotation file in 0_ref/ad2.gtf.\nThis will show you the reference genome, how all the reads are aligned to it, and all the annotation data. Try zooming in on an area and have a look at the reads and annotations. The figures you see in the picture are all derived from the data in the files you have given it.\nAt the top of the window you have the overview of the current chromosome you are looking at, which tells you the scale you are zoomed at for the moment. When you zoom in you will see a red rectangle apper which shows you which portion of the chromosome you are looking at. Just below the scale you’ll see the coverage graph, which tells you how many reads cover each position along the reference genome. The colored bands you see here and there are SNPs, i.e. positions where the reads of your sample does not match the reference genome.\nAll the reads, the larger area in the middle of the window, are drawn from the data in the BAM file using the chromosome name, the starting position and the ending position of each read. When you zoom in more you will be able to see individual reads and how they are aligned. The annotation in GTF format are all plotted using the data in the GTF file, visible just under all the reads, are shown as blue rectangles.\nThe reference genome, a fasta file containing the DNA sequence of the reference genome, is visible at the bottom of the window if you zoom to the smallest level so you can see the bases of the genome." + }, + { + "objectID": "topics/linux/lab_linux_filetypes.html#create-a-cram-file", + "href": "topics/linux/lab_linux_filetypes.html#create-a-cram-file", + "title": "Filetypes", + "section": "5 Create a CRAM file", + "text": "5 Create a CRAM file\nThe CRAM format is even more efficient than the BAM format. To create a CRAM file we’ll have to use samtools, so we will load the module for it.\n$ module load bioinfo-tools samtools/1.10\n Tell samtools that you want CRAM output (-C) and specify which reference genome it should use to do the CRAM conversion (-T)\nSyntax: samtools view -C -T <reference genome> -o <name of cram file> <bam file to convert>\n\n\n$ samtools view -C -T 0_ref/ad2.fa -o 4_cram/ad2.cram 3_sorted/ad2.sorted.bam\n\n\nCompare the sizes of the convered BAM file and the newly created CRAM file:\n$ ll -h 3_sorted/ad2.sorted.bam 4_cram/ad2.cram\nThis will list both the files, and print the file size in a human readable format (-h). The CRAM file is roughly 1/3 of the size of the BAM file. This is probably because all the reads in the simulated data has the same quality value (BBBBBBBBBB). Fewer types of quality values are easier to compress, hence this amazing compression ratio. Real data will have much more diverse quality scores, and the CRAM file would be pethaps 70-80% of the original BAM file.\n\n\n\n\n\n\nOptional\n\n\n\nIf you have been fast to finish this lab and you still have time left (or just can’t get enough of linux stuff), please have a look at the advanced linux tutorial where you can learn the basics in bash programming using variables, loops and control statements." + }, + { + "objectID": "index.html", + "href": "index.html", + "title": "", + "section": "", + "text": "Working on the Linux command line\nSequence data formats and QC\nDNA variant calling workflow\nRNA sequence analyses workflow\n\n\n\nUpdated: 13-11-2023 at 16:00:30." + }, + { + "objectID": "index.html#introduction-to-bioinformatics-using-ngs-data", + "href": "index.html#introduction-to-bioinformatics-using-ngs-data", + "title": "", + "section": "", + "text": "Working on the Linux command line\nSequence data formats and QC\nDNA variant calling workflow\nRNA sequence analyses workflow\n\n\n\nUpdated: 13-11-2023 at 16:00:30." + }, + { + "objectID": "home_schedule.html", + "href": "home_schedule.html", + "title": "Schedule", + "section": "", + "text": "Note\n\n\n\nCoffee breaks are planned for approximately 10:00 and 14:30 every day.\n\n\n\n\n\n\n\n\nTime\nTopic\nTeacher\nAssistant\n\n\n\n\n13-Nov-2023MonUppsala\n\n\n09:00 - 09:30\nWelcome and general introduction \nMartin Dahlö\n\n\n\n09:30 - 10:30\nIntro to Linux \nMartin Dahlö\n\n\n\n10:30 - 11:45\nIntro to Linux \nMartin Dahlö\nGDGuilherme Dias,LSLucile Soler\n\n\n11:45 - 13:00\nLunch\n\n\n\n\n13:00 - 14:00\nIntro to Uppmax \nMartin Dahlö\n\n\n\n14:00 - 17:00\nIntro to Uppmax \nMartin Dahlö\nGDGuilherme Dias\n\n\n14-Nov-2023TueUppsala\n\n\n09:00 - 09:30\nFile types in Bioinformatics \nMartin Dahlö\n\n\n\n09:30 - 11:00\nFile types in Bioinformatics \nMartin Dahlö\nMRMiguel Redondo,MPMartin Pippel\n\n\n11:00 - 11:45\nBetter terminal experience \nMartin Dahlö\n\n\n\n11:45 - 13:00\nLunch\n\n\n\n\n13:00 - 14:00\nQuality control  \nMalin Larsson\nGDGuilherme Dias,MPMartin Pippel\n\n\n14:00 - 15:00\nAdvanced Bash \nMartin Dahlö\n\n\n\n15:00 - 17:00\nAdvanced Bash \nMartin Dahlö\nKLKatarina Lejonlid,MPMartin Pippel\n\n\n15-Nov-2023WedUppsala\n\n\n09:00 - 10:15\nNGS tech & challenges \nAdam Ameur & Johanna Lagensjö\n\n\n\n10:15 - 11:00\nNGS tech & challenges\nAdam Ameur & Johanna Lagensjö\n\n\n\n11:00 - 11:45\nNGS Pipelines \nAdam Ameur\n\n\n\n12:00 - 13:00\nLunch\n\n\n\n\n13:00 - 14:00\nVariant-calling workflow \nMalin Larsson\n\n\n\n14:00 - 17:00\nVariant-calling workflow \nMalin Larsson\nJHJason Hill,MMMarkus Mayrhofer\n\n\n18:00 - 21:00\nCourse Dinner\n\n\n\n\n16-Nov-2023ThuUppsala\n\n\n09:00 - 09:30\nGATK best practices\nMalin Larsson\n\n\n\n09:30 - 11:45\nVariant-calling workflow\nMalin Larsson\nAJAnna Johansson,MMMarkus Mayrhofer\n\n\n11:45 - 13:00\nLunch\n\n\n\n\n13:00 - 14:00\nRNA-Seq workflow \nRoy Francis\n\n\n\n14:00 - 17:00\nRNA-Seq workflow \nRoy Francis\nMLMalin Larsson,VHVincent van Hoef\n\n\n17-Nov-2023FriUppsala\n\n\n09:00 - 11:45\nRNA-Seq workflow\nRoy Francis\nVHVincent van Hoef,MDMartin Dahlö\n\n\n11:45 - 13:00\nLunch\n\n\n\n\n13:00 - 14:00\nData management practices \nElin Kronander\n\n\n\n14:00 - 14:15\nNBIS \nElin Kronander\n\n\n\n\n\n\n\n\n Date Venue Slides Lab Video" + }, + { + "objectID": "home_info.html", + "href": "home_info.html", + "title": "Practical Info", + "section": "", + "text": "Uppsala\n\n\n\n\n\n\n\n\nRoom E10:1309 Entrance C11 Biomedicinskt centrum Uppsala University / ScilifeLab Husargatan 3 75237 Uppsala Sweden\nFew selected hotels are listed below ranked by distance from the venue.\n\nHotel von Kraemer (900 m, 11 min walk)\nAkademihotellet (1.7 Km, 21 min walk)\nCityStay Hotell (1.8 Km, 21 min walk)\nGrand Hotel Hörnan (1.9 Km, 23 min walk)\nHotell Centralstation (2.1 Km, 25 min walk)\nBest Western Svava (2.2 Km, 26 min walk)\n\nThe venue and hotels are also marked on the map.\nUse the UL website or the UL app for bus and train services around Uppsala. For buses from the Centralstation (Train/Bus), take Bus 4 (towards Gottsunda Centrum) or 8 (towards Sunnersta) and get off at the stop Uppsala Science Park. Bus tickets can be purchased in the app or directly from the driver using a credit card." + }, + { + "objectID": "home_info.html#location", + "href": "home_info.html#location", + "title": "Practical Info", + "section": "", + "text": "Uppsala\n\n\n\n\n\n\n\n\nRoom E10:1309 Entrance C11 Biomedicinskt centrum Uppsala University / ScilifeLab Husargatan 3 75237 Uppsala Sweden\nFew selected hotels are listed below ranked by distance from the venue.\n\nHotel von Kraemer (900 m, 11 min walk)\nAkademihotellet (1.7 Km, 21 min walk)\nCityStay Hotell (1.8 Km, 21 min walk)\nGrand Hotel Hörnan (1.9 Km, 23 min walk)\nHotell Centralstation (2.1 Km, 25 min walk)\nBest Western Svava (2.2 Km, 26 min walk)\n\nThe venue and hotels are also marked on the map.\nUse the UL website or the UL app for bus and train services around Uppsala. For buses from the Centralstation (Train/Bus), take Bus 4 (towards Gottsunda Centrum) or 8 (towards Sunnersta) and get off at the stop Uppsala Science Park. Bus tickets can be purchased in the app or directly from the driver using a credit card." + }, + { + "objectID": "home_info.html#contact", + "href": "home_info.html#contact", + "title": "Practical Info", + "section": "Contact", + "text": "Contact\nThis workshop is run by the National Bioinformatics Infrastructure Sweden (NBIS) in collaboration with National Genomics Infrastructure (NGI). Both, NGI and NBIS are platforms at SciLifeLab.\nIf you would like to get in touch with us regarding this workshop, please contact us at edu.intro-ngs [at] nbis.se." + }, + { + "objectID": "home_contents.html", + "href": "home_contents.html", + "title": "Contents", + "section": "", + "text": "Introduction to Linux\n\nIntroduction to Linux \n\n\n\nFile types in Linux\n\nFile types in Bioinformatics \n\nLinux file permissions \n\n\n\nUppmax\n\nIntroduction to UPPMAX \n\nUPPMAX Pipelines \n\n\n\nAdvanced Linux\n\nBetter terminal experience \nAdvanced Linux \n\n\n\nVariant-calling workflow\n\nVariant-calling \n\n\n\nRNA-Seq workflow\n\nRNA-Seq workflow \nSimon’s report \n\n\n\nNGS technologies\n\nNGS technologies and challenges \nNGS Pipelines \n\n\n\nOther\n\nQC of FastQ reads \nData management \n\n\n\nUseful resources\n\nConnecting to Uppmax \nUploading & downloading files from Uppmax \nWorking on Tetralith: The backup cluster \nLinux cheatsheet \nBash cheat sheet 1 \nBash cheat sheet 2 \nBash cheat sheet 3 \nUppmax cheatsheet \nMac keyboard" + }, + { + "objectID": "home_precourse.html", + "href": "home_precourse.html", + "title": "Precourse", + "section": "", + "text": "Remote computing cluster UPPMAX will be use for data analyses. A SUPR/NAISS account is needed to use these resources.\nIf you do not already have one, create an account at SUPR/NAISS. Then, Log in to SUPR/NAISS, preferably using the SWAMID.\n\n\n\n\n\nBefore proceeding with applying for project membership and user accounts, we have to accept the NAISS User Agreement. Do this by clicking the Personal Information link in the left sidebar menu. The scroll down a bit until you reach the section User Agreements. If you already have accepted it the State will be a green box with the text Accepted in it. If it is anything else, click it to start the accepting process.\n\n\n\n\n\n\nTip\n\n\n\nThis is where you might run into trouble if you don’t have a SWAMID connected account. You will not be able to accept the user agreement online without it, so you will have to send in your acceptance in paper form together with a copy of your passport. This process can take a week or more, so please make sure you can accept the user agreement in good time.\n\n\nAfter making sure you have an accepted user agreement, go to the SUPR/NAISS Projects page and request membership to the project ID: naiss2023-22-862\n\n\n\n\n\nOnce you are accepted to a project, you should see that project listed under your active projects.\n\n\n\n\n\nFinally you need to request login accounts to NSC and UPPMAX. These are the accounts you use to log in to the actual computers, so they are not the same as your SUPR account. Login to SUPR and go to the Accounts page. Under the Possible Resource Account Requests heading click on Request Account on Tetralith @ NSC and Request Account on Rackham @ UPPMAX button and confirm it on the next page. If either of them are missing from this page, it could be because you already have a login account created (only 1 account per person allowed), or that you have not yet gotten your project memberships approved.\n\n\n\n\n\nChecking your request and approving your account requires some manual work, so you might have to wait for some time (up to a working day) before the next step. When the account is ready to be created, you will receive an email to your registered email address (shown in your SUPR contact information) with information on how to proceed. You will get a one-time URL that you use to get the password (within seven days) to login to the cluster with. The link is only valid for 1 visit, so write down the password you get. When that has been done, the account ready for use within 15 minutes and you can then login using your password. Once you have logged into the cluster you can change your password by typing passwd in the terminal and follow the instuctions.\n\n\n\n\n\n\nNote\n\n\n\nYou will get one username & password for the account on UPPMAX, and one username and password for the account on NSC. Please keep track of both, we will tell you when to use which account during the workshop." + }, + { + "objectID": "home_precourse.html#uppmax", + "href": "home_precourse.html#uppmax", + "title": "Precourse", + "section": "", + "text": "Remote computing cluster UPPMAX will be use for data analyses. A SUPR/NAISS account is needed to use these resources.\nIf you do not already have one, create an account at SUPR/NAISS. Then, Log in to SUPR/NAISS, preferably using the SWAMID.\n\n\n\n\n\nBefore proceeding with applying for project membership and user accounts, we have to accept the NAISS User Agreement. Do this by clicking the Personal Information link in the left sidebar menu. The scroll down a bit until you reach the section User Agreements. If you already have accepted it the State will be a green box with the text Accepted in it. If it is anything else, click it to start the accepting process.\n\n\n\n\n\n\nTip\n\n\n\nThis is where you might run into trouble if you don’t have a SWAMID connected account. You will not be able to accept the user agreement online without it, so you will have to send in your acceptance in paper form together with a copy of your passport. This process can take a week or more, so please make sure you can accept the user agreement in good time.\n\n\nAfter making sure you have an accepted user agreement, go to the SUPR/NAISS Projects page and request membership to the project ID: naiss2023-22-862\n\n\n\n\n\nOnce you are accepted to a project, you should see that project listed under your active projects.\n\n\n\n\n\nFinally you need to request login accounts to NSC and UPPMAX. These are the accounts you use to log in to the actual computers, so they are not the same as your SUPR account. Login to SUPR and go to the Accounts page. Under the Possible Resource Account Requests heading click on Request Account on Tetralith @ NSC and Request Account on Rackham @ UPPMAX button and confirm it on the next page. If either of them are missing from this page, it could be because you already have a login account created (only 1 account per person allowed), or that you have not yet gotten your project memberships approved.\n\n\n\n\n\nChecking your request and approving your account requires some manual work, so you might have to wait for some time (up to a working day) before the next step. When the account is ready to be created, you will receive an email to your registered email address (shown in your SUPR contact information) with information on how to proceed. You will get a one-time URL that you use to get the password (within seven days) to login to the cluster with. The link is only valid for 1 visit, so write down the password you get. When that has been done, the account ready for use within 15 minutes and you can then login using your password. Once you have logged into the cluster you can change your password by typing passwd in the terminal and follow the instuctions.\n\n\n\n\n\n\nNote\n\n\n\nYou will get one username & password for the account on UPPMAX, and one username and password for the account on NSC. Please keep track of both, we will tell you when to use which account during the workshop." + }, + { + "objectID": "home_precourse.html#install-tools", + "href": "home_precourse.html#install-tools", + "title": "Precourse", + "section": "2 Install tools", + "text": "2 Install tools\n\n2.1 ThinLinc\n\n\n\n\n\nThinLinc allows graphical connection to UPPMAX. Download and install from https://www.cendio.com/thinlinc/download. It can be used directly from the browser but it is recommended to download and install the client for better copy/paste operation.\n\n\n2.2 XQuartz\n\n\n\n\n\nMac users will need to download and install XQuartz for X11 forwarding. ie; to forward remotely opened windows to local machine.\n\n\n2.3 MobaXterm (Optional)\n\n\n\n\n\nIf you are on a Windows system, and you want to open graphical applications from the terminal, we recommend MobaXterm. It is recommended that you INSTALL the program and not use the portable version. MobaXterm also has an integrated SFTP file browser.\n\n\n2.4 Filezilla (Optional)\n\n\n\n\n\nWhen you need to transfer data between the remote cluster and your computer, you can use the tools SCP or SFTP through the terminal. Windows users can use the SFTP browser available with MobaXterm. If you prefer a GUI to upload and download files from the remote cluster, we recommend installing FileZilla." + }, + { + "objectID": "home_precourse.html#connect-to-uppmax", + "href": "home_precourse.html#connect-to-uppmax", + "title": "Precourse", + "section": "3 Connect to UPPMAX", + "text": "3 Connect to UPPMAX\nSee Connecting to UPPMAX instructions listed on the Contents page.\n\n\n\n\n\n\nTip\n\n\n\nIf you want to get a primer on using the terminal, you can get started with the following Tutorial One at this link Unix tutorial for beginners. You can use https://scilifelab.github.io/courses/ngsintro/common/emu/ (or this mirror) to try the commands in the tutorial, so that you don’t mess up any real world system. If you have any questions regarding this tutorial contact: martin.dahlo [at] scilifelab.uu.se." + }, + { + "objectID": "home_precourse.html#create-a-user-folder", + "href": "home_precourse.html#create-a-user-folder", + "title": "Precourse", + "section": "4 Create a user folder", + "text": "4 Create a user folder\n\n\n\n\n\n\nNote\n\n\n\nWhere username is mentioned, change to your user name.\n\n\nOnce you have logged in to UPPMAX, run the following command.\n\n\n\n\nbash\n\nmkdir /proj/naiss2023-22-862/nobackup/username\n\n\n\nThis creates a directory with your user name. You will work inside this directory for the workshop. If you cannot write to the folder, the most likely reason is that you have not requested access to the workshop project via SUPR. This is described in step 1 above.\n\n\n\n\n\n\nNote\n\n\n\nIt may take an hour or so from request approval, before you can actually write to the folder. We will check before the workshop that all students have logged in and done this, so do not forget!" + }, + { + "objectID": "home_syllabus.html", + "href": "home_syllabus.html", + "title": "Syllabus", + "section": "", + "text": "SyllabusLearning outcomesEntry requirements\n\n\nThe syllabus for this workshop are as follows.\n\nWorking on the unix/linux command line\n\nCommand line navigation and related commands: cd, mkdir, rm, rmdir\nCommonly used linux tools: cp, mv, tar, less, more, head, tail, nano, grep, top, man\nWildcards\nOwnership and permissions\nSymbolic links\nPiping commands\n\nWorking on remote computing cluster\n\nLogging on to UPPMAX\nBooking resources\nJob templates, submission and queues\nModules\n\nCommonly used bioinformatic tools and pipelines\nWorking with integrated genome viewer\nVariant-calling workflow\n\nMapping reads to the reference genome\nVariant detection\nVCF file format\n\nRNA-Seq workflow\n\nRNA-Seq experimental design and considerations\nQC, mapping and gene expression counts\nDifferential gene expression analyses\n\nCurrent advances in NGS technologies\n\n\n\nAfter this workshop you should be able to:\n\nDescribe the basic principles of next generation sequencing.\nUse the Linux command line interface to manage simple file processing operations, and organise directory structures.\nConnect to and work on a remote compute cluster.\nApply programs in Linux for analysis of NGS data.\nSummarise the applications of current NGS technologies, including the weakness and strengths of the approaches and when it is appropriate to use which one of them.\nExplain common NGS file formats.\nInterpret quality control of NGS reads.\nExplain the steps involved in variant calling using whole genome sequencing data.\nIndependently perform a basic variant calling workflow on example data.\nExplain the steps involved in a differential gene expression workflow using RNA seq data.\nHands-on experience with handling of raw RNA sequencing data, QC and quantification of gene expression.\nConceptual understanding of differential gene expression analysis.\n\n\n\n\nThis is a national course open to PhD students, postdocs, group leaders and core facility staff.\nA background in genetics, cell biology, biomedicine, biochemistry, bioinformatics or comparable is desirable. To get the maximum benefit from the workshop we would like you to\nHave a research project where you are currently using next generation sequencing or are planning to use next generation sequencing. It is beneficial if you are directly performing analyses or if you have a support role and will be able to participate in a wide range of projects and transfer your knowledge to others.\nSelection criteria include correct entry requirements, motivation to attend the workshop as well as gender and geographical balance. Applicants affiliated to a Swedish institution are prioritized. International applicants are considered only if/when seats are available. Further prioritization: PhD scholars > Post-Docs, PIs, Healthcare staff > Master’s students).\nPlease note that NBIS training events do not provide any formal university credits. The training content is estimated to correspond to a certain number of credits, however the estimated credits are just guidelines. If formal credits are crucial, the student needs to confer with the home department before submitting a course application in order to establish whether the course is valid for formal credits or not." + }, + { + "objectID": "topics/linux/lab_linux_advanced.html", + "href": "topics/linux/lab_linux_advanced.html", + "title": "Advanced Linux", + "section": "", + "text": "Note\n\n\n\nIn code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window." + }, + { + "objectID": "topics/linux/lab_linux_advanced.html#connect-to-uppmax", + "href": "topics/linux/lab_linux_advanced.html#connect-to-uppmax", + "title": "Advanced Linux", + "section": "1 Connect to UPPMAX", + "text": "1 Connect to UPPMAX\nThe first step of this lab is to open a ssh connection to UPPMAX. Please refer to Connecting to UPPMAX for instructions. Once connected to UPPMAX, return here and continue reading the instructions below." + }, + { + "objectID": "topics/linux/lab_linux_advanced.html#logon-to-a-node", + "href": "topics/linux/lab_linux_advanced.html#logon-to-a-node", + "title": "Advanced Linux", + "section": "2 Logon to a node", + "text": "2 Logon to a node\nUsually you would do most of the work in this lab directly on one of the login nodes at UPPMAX, but we have arranged for you to have one core each for better performance. This was covered briefly in the lecture notes.\nCheck which node you got when you booked resources this morning (replace username with your UPPMAX username)\n$ squeue -u username\nshould look something like this\ndahlo@rackham2 work $ squeue -u dahlo\n JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n 3132376 core sh dahlo R 0:04 1 r292\ndahlo@rackham2 work $\nwhere r292 is the name of the node I got (yours will probably be different). Note the numbers in the Time column. They show for how long the job has been running. When it reaches the time limit you requested (7 hours in this case) the session will shut down, and you will lose all unsaved data. Connect to this node from within UPPMAX.\n$ ssh -Y r292\nIf the list is empty you can run the allocation command again and it should be in the list:\n\ncat(paste0(\"salloc -A \",upid,\" -t 03:30:00 -p core -n 1 --no-shell &\"))\n\nsalloc -A naiss2023-22-862 -t 03:30:00 -p core -n 1 --no-shell &\n\n\n There is a UPPMAX specific tool called jobinfo that supplies the same kind of information as squeue that you can use as well ($ jobinfo -u username)." + }, + { + "objectID": "topics/linux/lab_linux_advanced.html#first-things-first", + "href": "topics/linux/lab_linux_advanced.html#first-things-first", + "title": "Advanced Linux", + "section": "3 First things first", + "text": "3 First things first\nLet’s make sure nano has syntax highlighting enabled. What that will do is to paint the boring code in pretty colors, making it much easier to read it. See the difference for yourself by first looking at this file before you enable it:\n$ nano /sw/uppmax/bin/projplot\nClose down nano when you have seen how boing it looks without colors by pressing ctrl+x. Now, let’s enable syntax highlighting. To do this, we will simply tell nano to include the syntax highlighting instructions from a bunch of files that are already installed at uppmax. Run this command to do just that:\n$ find /usr/share/nano/ -iname \"*.nanorc\" -exec echo include {} \\; >> ~/.nanorc\nThis command will put one line per language instructions (~30 of them, located in /usr/share/nano), into the nano autostart file (~/.nanorc) and put the word ‘include’ infront of each file name. That will make nano include the instructions from each of those files whenever it starts. Now have a look at the same file as before and enjoy the colors:\n$ nano /sw/uppmax/bin/projplot\nThen close nano and continue with the lab." + }, + { + "objectID": "topics/linux/lab_linux_advanced.html#copy-files-for-lab", + "href": "topics/linux/lab_linux_advanced.html#copy-files-for-lab", + "title": "Advanced Linux", + "section": "4 Copy files for lab", + "text": "4 Copy files for lab\nNow, you will need some files. To avoid all the course participants editing the same file all at once, undoing each other’s edits, each participant will get their own copy of the needed files. The files are located in the folder /sw/courses/ngsintro/linux/linux_advanced/.\nIf you for some reason have problems copying the files, or if you are not on UPPMAX when running this lab, you can download these files here. You can unpack the file using the command tar -xzvf linux_advanced.tar.gz once you have downloaded it. After unpacking, continue the lab from step 4.\nNext, copy the lab files from this folder. -r means recursively, which means all the files including sub-folders of the source folder. Without it, only files directly in the source folder would be copied, NOT sub-folders and files in sub-folders.\n Remember to use tab-complete to avoid typos and too much writing.\n\n\ncp -r <source> <destination>\ncp -r /sw/courses/ngsintro/linux/linux_advanced /proj/naiss2023-22-862/nobackup/username\n\n\nHave a look in /proj/naiss2023-22-862/nobackup/username/linux_advanced.\n\n\ncd /proj/naiss2023-22-862/nobackup/username/linux_advanced\n\n\n$ ll\nIf you see files, the copying was successful." + }, + { + "objectID": "topics/linux/lab_linux_advanced.html#using-variables", + "href": "topics/linux/lab_linux_advanced.html#using-variables", + "title": "Advanced Linux", + "section": "5 Using variables", + "text": "5 Using variables\nVariables are like small notes you write stuff on. If you want to save the value of something to be able to use it later, variables is the way to go. Let’s try assigning values to some variables and see how we use them.\n$ a=5\nNow the values 5 is stored in the variable named a. To use the variable we have to put a $ sign in front of it so that bash knows we are referring to the variable a and not just typing the letter a. To see the result of using the variable, we can use the program echo, which prints whatever you give it to the terminal.\n$ echo print this text to the terminal\n$ echo \"you can use quotes if you want to\"\nAs you see, all the words you give it are printed just the way they are. Try putting the variable somewhere in the text.\n$ echo Most international flights leave from terminal $a at Arlanda airport\nBash will see that you have a variable there and will replace the variable name with the value the variable have before sending the text to echo. If you change the value of a and run the exact command again you will see that it changes.\n$ a=\"five\"\n$ echo Most international flights leave from terminal $a at Arlanda airport\nSo without changing anything in the echo statement, we can make it output different things, all depending on the value of the variable a. This is one of the main points of using variables, that you don’t have to change the code or script but you can still make it behave differently depending on the values of the variables.\nYou can also do mathematics with variables, but we have to tell bash that we want to do calculations first. We do this by wrapping the calculations inside a dollar sign (telling bash it’s a variable) and double parentheses, i.e. $((5+5)).\n$ a=4\n$ echo $a squared is $(($a*$a))\n Write a echo command that will print out the volume of a rectangular cuboid, with the side lengths specified by variables named x, y, and z. To see that it works correctly, the volume of a rectangular cuboid with sides 5,5,5 is 125, and for 4,5,10 is 200. Give it a couple of tries on your own first. If you get completely stuck you can see a suggested solution below.\n\n\n$ x=4\n$ y=5\n$ z=10\n$ echo The volume of the rectangular cuboid with the sides $x,$y,$z is $(($x*$y*$z))." + }, + { + "objectID": "topics/linux/lab_linux_advanced.html#exercises", + "href": "topics/linux/lab_linux_advanced.html#exercises", + "title": "Advanced Linux", + "section": "6 Exercises", + "text": "6 Exercises\nFirst off, let’s open another terminal to UPPMAX so that you have 2 of them open. Scripting is a lot easier if you have one terminal on the command line ready to run commands and test things, and another one with a text editor where you write the actual code. That way you will never have to close down the text editor when you want to run the script you are writing on, and then open it up again when you want to continue editing the code.\nSo open a new terminal window, connect it to UPPMAX and then connect it to the node you have booked. Make sure both terminals are in the /proj/naiss2023-22-862/nobackup/username/linux_advanced directory, and start editing a new file with gedit or nano where you write your script. Name the file whatever you want, but in the examples I will refer to it as loop_01.sh. Write your loops to this file (or create a new file for each new example) and test run it in the other terminal.\nNOTE: If you get error messages like (gedit:27463): dconf-WARNING **: 10:59:00.575: failed to commit changes to dconf: Failed to execute child process “dbus-launch” (No such file or directory), and if you can’t change any preferences, you can try starting gedit through the graphical menu in ThinLic instead. If you are using the Xfce desktop environment you should have a start-menu-like button at the top-left of the screen named Applications, or if you right-click somewhere on the desktop you should find it in the context menu that pops up. In the Applications menu, look in the category Accessories and you should find a program called Text editor which will start gedit *(hopefully without the errors).\nThe most simple loops are the ones that loop over a predefined list. You saw examples of this in the lecture slides, for example:\nfor i in \"Print these words\" one by one;\ndo\n echo $i\ndone\nwhich will print the value of $i in each iteration of the loop. Write this loop in the file you are editing with gedit/nano, save the file, and then run it in the other terminal you have open.\n$ bash loop_01.sh\nAs you see, the words inside the quotation marks are treated as a single unit, unlike the words after. You can also iterate over numbers, so erase the previous loop you wrote and try this instead:\nfor number in 1 2 3;\ndo\n echo $number\ndone\nIf everything worked correctly you should have gotten the numbers 1 2 3 printed to the screen. As you might guess, this way of writing the list of numbers to iterate over will not be usable once you have more than 10 or so numbers you want to loop over. Fortunately, the creators of bash (and most other computer languages) saw this problem coming a mile away and did something about it. To quickly create a list of numbers in bash, you can use something called a sequence expression to create the list for you.\nfor whatevernameyouwant in {12..72}; \ndo \n echo $whatevernameyouwant \ndone \n\n6.1 Exercise 1\n Let’s say it’s New Year’s Eve and you want to impress your friends with a computerized countdown of the last 10 seconds of the year (don’t we all?).\n\n\n\n\n\n\nTip\n\n\n\nStart off with getting a loop to count down from 10 to 0 first. Notice how fast the computer counts? That won’t do if it’s seconds we want to be counting down. Try looking the man page for the sleep command (man sleep) and figure out how to use it. The point of using sleep is to tell the computer to wait for 1 second after printing the number, instead of rushing to the next iteration in the loop directly. Try to implement this on your own.\n\n\n\n\n# declare the values the loop will loop over\nfor secondsToGo in {10..0};\ndo\n # print out the current number\n echo $secondsToGo\n\n # sleep for 1 second\n sleep 1\n\ndone\n\n# Declare the start of a new year in a festive manner\necho Happy New Year everyone!!\n\n\n\n\n6.2 Exercise 2\nLet’s try to do something similar to the example in the lecture slides, to run the same commands on multiple files. In the Introduction to UPPMAX, we learned how to use samtools to convert BAM files to SAM files so that humans can read them. In real life you will never do this, instead you will most likely always do it the other way around. SAM files take up ~4x more space on the hard drive compared to the same file in BAM format, so as soon as you see a SAM file you should convert it to a BAM file instead to conserve hard drive space. If you have many SAM files that needs converting you don’t want to sit there and type all the commands by hand like a pleb.\n Write a script that converts all the SAM files in a specified directory to BAM files. Incidentally, you can find 50 SAM files in need of conversion in the folder called sam in the folder you copied to your folder earlier in this lab (/proj/naiss2023-22-862/nobackup/username/linux_advanced/sam). Bonus points if you make the program take the specified directory as an argument, and another bonus point if you get the program to name the resulting BAM file to the same name as the SAM file but with a .bam ending instead.\n\n\n\n\n\n\nTip\n\n\n\nRemember that you have to load the samtools module to be able to run it. The way you get samtools to convert a SAM file to a BAM file is by typing the following command:\nsamtools view -bS sample_1.sam > sample_1.bam\nThe -b option tells samtools to output BAM format, and the -S option tells samtools that the input is in SAM format.\nRemember, Google is a good place to get help. If you get stuck, google “bash remove file ending” or “bash argument to script” and look for hits from StackOverflow/StackExchange or similar pages. There are always many different way to solve a problem. Try finding one you understand what they do and test if you can get them to work the way you want. If not, look for another solution and try that one instead.\n\n\nBasic, without bonus points:\n\n\n# load the modules needed for samtools\nmodule load bioinfo-tools samtools/1.3\n\n# move to the SAM files directory to start with\ncd sam\n\n# use ls to get the list to iterate over\nfor file in *.sam;\ndo\n # do the actual converting, just slapping on .bam at the end of the name\n samtools view -bS $file > $file.bam\ndone\n\n\nAdvanced, with bonus points:\n\n\n# load the modules needed for samtools\nmodule load bioinfo-tools samtools/1.3\n\n# move to the SAM files directory to start with.\n# $1 contains the first argument given to the program\ncd $1\n\n# use ls to get the list to iterate over.\nfor file in *.sam;\ndo\n\n # print a message to the screen so that the user knows what is happening.\n # $(basename $file .sam) means that it will take the file name and remove .sam\n # at the end of the name.\n echo \"Converting $file to $(basename $file .sam).bam\"\n\n # do the actual converting\n samtools view -bS $file > $(basename $file .sam).bam\ndone\n\n\n\n\n6.3 Exercise 3\nLet’s add a small thing to the exercise we just did. If there already exists a BAM file with the same name as the SAM file it’s not necessary to convert it again. Let’s use an if statement to check if the file already exists before we do the conversion.\nThe following if statement will check if a given filename exists, and prints a message depending on if it exists or not.\nFILE=$1\n\nif [ -f $FILE ];\nthen\n echo \"File $FILE exists.\"\nelse\n echo \"File $FILE does not exist.\"\nfi\nWhat we want to do is to check if the file doesn’t exists. The way to do that is to invert the answer of the check if the file does exist. To do that in bash, and many other languages, is to use the exclamation mark, !, which in these kinds of logical situations means NOT or the opposite of.\nFILE=$1\n\nif [ ! -f $FILE ];\nthen\n echo \"File $FILE does not exist.\"\nfi\n Now, modify the previous exercise to only do the conversion if a file with the intended name of the BAM file doesn’t already exists. i.e; if you have a.sam and want to create a BAM file named a.bam, first check if a.bam already exists and only do the conversion if it does not exist.\nBasic:\n\n\n# load the modules needed for samtools\nmodule load bioinfo-tools samtools/1.3\n\n# move to the SAM files directory to start with.\ncd sam\n\n# use ls to get the list to iterate over.\nfor file in *.sam;\ndo\n # check if the intended output file does not already exists\n if [ ! -f $file.bam ];\n then\n # do the actual converting, just slapping on .bam at the end of the name\n samtools view -bS $file > $file.bam\n fi\ndone\n\n\nAdvanced:\n\n\n# load the modules needed for samtools\nmodule load bioinfo-tools samtools/1.3\n\ncd $1\n\n# use ls to get the list to iterate over.\n# $1 contains the first argument given to the program\nfor file in *.sam;\ndo\n\n # basename will remove the path information to the file, and will also remove the .sam ending\n filename_bam=$(basename $file .sam)\n\n # add the .bam file ending to the filename\n filename_bam=$filename_bam.bam\n\n # check if the intended output file does not already exists.\n if [ ! -f $filename_bam ];\n then\n\n # print a message to the screen so that the user knows what is happening.\n echo \"Converting $file to $filename_bam\"\n\n # do the actual converting\n samtools view -bS $file > $filename_bam\n\n else\n # inform the user that the conversion is skipped\n echo \"Skipping conversion of $file as $filename_bam already exist\"\n fi\ndone\n\n\n\n\n6.4 Bonus exercise 1\nMaths and programming are usually a very good combination, so many of the examples of programming you’ll see involve some kind of maths. Now we will write a loop that will calculate the factorial of a number. As wikipedia will tell you, “the factorial of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n”, i.e. multiply all the integers, starting from 1, leading up to and including a number with each other.\nThe factorial of 5, written 5!, would be 1*2*3*4*5=120. Doing this by hand would start taking its time even after a couple of steps, but since we know how to loop that should not be a problem anymore.\n Write a loop that will calculate the factorial of a given number stored in the variable $n.\n\n\n\n\n\n\nTip\n\n\n\nA problem that you will encounter is that the sequence expression, {1..10}, from the previous exercise doesn’t handle variables. This is because of the way bash is built. The sequence expressions are handled before handling the variables so when bash tries to generate the sequence, the variable names have not yet been replaced with the values they contain. This leads to bash trying to create a sequence from 1 to $n, which of course doesn’t mean anything.\nTo get around this we can use a different way of generating sequences (there are always alternatives). There is a program called seq that does pretty much the same thing as the sequence expression, and since it is a program it will be executed after the variables have been handled. It’s as easy to use as the sequence expressions; instead of writing {1..10} just write $( seq 1 10 ).\nThe $() tells bash to run something in a subshell, which pretty much means it will run the command within the paratheses and then take whatever that command printed to the screen and replace the parantheses e xpression:\necho $(seq 1 5)\nbecomes\necho 1 2 3 4 5\n\n\n\n\n# set the number you want to calculate the factorial of\nn=10\n\n# you have to initialize a variable before you can start using it.\n# Leaving this empty would lead to the first iteration of the loop trying\n# to use a variable that has no value, which would cause it to crash\nfactorial=1\n\n# declare the values the loop will loop over (1 to whatever $n is)\nfor i in $( seq 1 $n );\ndo\n\n # set factorial to whatever factorial is at the moment, multiplied with the variable $i\n factorial=$(( $factorial * $i ))\n\n # an alternative solution which gives exactly the same result, but makes it a bit more readable maybe\n # temporary_sum=$(( $factorial * $i ))\n # factorial=$temporary_sum\n\ndone\n\n# print the result\necho The factorial of $n is $factorial\n\n\n\n\n6.5 Bonus exercise 2\nNow, let’s combine everything you’ve learned so far in this course.\n Write a script that runs the pipeline from the Bioinformatics filetypes lab for each fastq file in a specified directory, using the same reference genome as in the file type exercise. Navigate to the Linux 2: File types in Bioinformatics lab on the Contents page.\nIf that sounds too easy, make the script submit a slurm job for each sample that will run the pipeline for that sample on a calculation node (1 core, 5 minutes each). And if that is too easy, add that the pipeline will use the local hard drive on the calculation node for all files used in the analysis.\nWhen the analysis is done, only fastq files and sorted and indexed BAM files should be in your folder.\n Read more about the $SNIC_TMP variable in the disk storage guide on the UPPMAX homepage.\nThere is a bunch of fastq files in the directory /proj/naiss2023-22-862/nobackup/username/linux_advanced/fastq/ that is to be used for this exercise.\nBasic solution:\n\n\n# make the dummy pipeline available\nexport PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts\n\n# index the reference genome\nreference_indexer -r /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa\n\n# go to the input files\ncd $1\n\n# loop over all the fastq files\nfor file in *.fastq;\ndo\n\n # align the reads\n align_reads -r /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa -i $file -o $file.sam\n\n # convert the sam file to a bam file\n sambam_tool -f bam -i $file.sam -o $file.bam\n\n # sort the bam file\n sambam_tool -f sort -i $file.bam -o $file.sorted.bam\n\n # index the bam file\n sambam_tool -f index -i $file.sorted.bam\n\ndone\n\n\nAdvanced solution:\n\n\n# make the dummy pipeline available in this script\nexport PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts\n\n# index the reference genome once, only if needed\nif [ ! -f /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa.idx ];\nthen\n reference_indexer -r /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa\nfi\n\n\n# find out the absolute path to the input files\ncd $1\ninput_absolute_path=$(pwd)\n\n# go back to the previous directory now that the absolute path has been saved\ncd -\n\n\n\n# loop over all the fastq files\nfor file in $input_absolute_path/*.fastq;\ndo\n\n # print status report\n echo Processing $file\n\n # save the file name without the path information for convenience\n file_basename=$(basename $file)\n\n # save the file name without the file ending for convenience\n file_prefix=$(basename $file .fastq)\n\n # print a temporary script file that will be submitted to slurm\n echo \"#!/bin/bash -l\n\n #SBATCH -A naiss2023-22-862\n #SBATCH -p core\n #SBATCH -n 1\n #SBATCH -t 00:05:00\n #SBATCH -J $file_basename\n\n # make the dummy pipeline available on the calculation node\n echo \"Loading modules\"\n export PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts\n\n # copy the reference genome, index and sample file to the nodes local hard drive.\n # You have to escape the dollar sign in SNIC_TMP to keep bash from resolving\n # it to its value in the submitter script already.\n echo \"Copying data to node local hard drive\"\n cp /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa* $file $SNIC_TMP/\n\n # go the the nodes local hard drive\n echo \"Changing directory to node local hard drive\"\n cd $SNIC_TMP\n\n # align the reads\n echo \"Aligning the reads\"\n align_reads -r ad2.fa -i $file_basename -o $file_prefix.sam\n\n # convert the SAM file to a BAM file\n echo \"Converting sam to bam\"\n sambam_tool -f bam -i $file_prefix.sam -o $file_prefix.bam\n\n # sort the BAM file\n echo \"Sorting the bam file\"\n sambam_tool -f sort -i $file_prefix.bam -o $file_prefix.sorted.bam\n\n # index the BAM file\n echo \"Indexing the sorted bam file\"\n sambam_tool -f index -i $file_prefix.sorted.bam\n\n # copy back the files you want to keep\n echo \"Copying results back to network storage\"\n cp $file_prefix.sorted.bam $input_absolute_path/\n cp $file_prefix.sorted.bam.bai $input_absolute_path/$file_prefix.sorted.bai\n\n echo \"Finished\"\n \" > tmp.sbatch\n\n # submit the temporary script file\n sbatch tmp.sbatch\n\ndone\n\n# remove the temporary file now that everything has been submitted\nrm tmp.sbatch" + }, + { + "objectID": "topics/linux/lab_linux_intro.html", + "href": "topics/linux/lab_linux_intro.html", + "title": "Introduction To Linux", + "section": "", + "text": "Note\n\n\n\nIn code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window." + }, + { + "objectID": "topics/linux/lab_linux_intro.html#connect-to-uppmax", + "href": "topics/linux/lab_linux_intro.html#connect-to-uppmax", + "title": "Introduction To Linux", + "section": "1 Connect to UPPMAX", + "text": "1 Connect to UPPMAX\nThe first step of this lab is to open a ssh connection to UPPMAX. Please refer to Connecting to UPPMAX for instructions. Once connected to UPPMAX, return here and continue reading the instructions below." + }, + { + "objectID": "topics/linux/lab_linux_intro.html#logon-to-a-node", + "href": "topics/linux/lab_linux_intro.html#logon-to-a-node", + "title": "Introduction To Linux", + "section": "2 Logon to a node", + "text": "2 Logon to a node\nUsually you would do most of the work in this lab directly on one of the login nodes at UPPMAX, but we have arranged for you to have one core each for better performance. This was covered briefly in the lecture notes.\n\n\nsalloc -A naiss2023-22-862 -t 07:00:00 -p core -n 1 --no-shell &\n\n\ncheck which node you got (replace username with your UPPMAX username)\nsqueue -u username\nshould look something like this\ndahlo@rackham2 work $ squeue -u dahlo\n JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n 3132376 core sh dahlo R 0:04 1 r292\ndahlo@rackham2 work $\nwhere r292 is the name of the node I got (yours will probably be different). Note the numbers in the Time column. They show for how long the job has been running. When it reaches the time limit you requested (7 hours in this case) the session will shut down, and you will lose all unsaved data. Connect to this node from within UPPMAX.\n$ ssh -Y r292\n There is a UPPMAX specific tool called jobinfo that supplies the same kind of information as squeue that you can use as well ($ jobinfo -u username)." + }, + { + "objectID": "topics/linux/lab_linux_intro.html#navigation", + "href": "topics/linux/lab_linux_intro.html#navigation", + "title": "Introduction To Linux", + "section": "3 Navigation", + "text": "3 Navigation\nIt is good to know how to move around in the file system. I’m sure you all have experienced this using a graphical user interface (GUI) before, Windows Explorer in Windows and Finder in OSX. Using the command line can be confusing at first, but the more your do it, the easier it gets.\nWhen you connect to UPPMAX, you will start out in your home folder. The absolute path to your home folder is usually /home/username\nStart with looking at what you have in your home folder. The command for this ls, and it stand for LiSt (list).\n$ ls -l\nThis is how my home folder looks like, and yours should look somewhat similar:\n[12:56:32] dahlo@rackham1 ~ $ ls -l\ntotal 4384\ndrwxr-xr-x 3 dahlo b2014068 2048 Apr 27 2017 archive\n-rw-rw-r-- 1 dahlo dahlo 49042 Sep 23 2016 bad.png\ndrwxr-xr-x 2 dahlo dahlo 2048 Mar 18 2016 data\n-rw-rw-r-- 1 dahlo dahlo 60944 Sep 23 2016 good.png\ndrwxr-xr-x 4 dahlo b2014209 2048 Oct 30 2014 igv\ndrwxrwxr-x 5 dahlo dahlo 2048 Sep 20 2016 ngsintro\ndrwx--S--- 2 dahlo dahlo 2048 May 4 2010 private\ndrwxr-xr-x 26 dahlo dahlo 4096 May 18 10:43 uppmaxScripts\ndrwxrwxr-x 5 dahlo dahlo 2201600 May 14 14:02 work\n[12:57:36] dahlo@rackham1 ~ $\nWe can start off with moving to this workshop’s project folder. Each project has its own proj folder and nobackup folder that contains all the files that belong to the project. The proj folder is backed-up, so if a file is deleted by mistake it can be retrieved from the backups, and this is where only compressed raw data and scripts are usually stored. The nobackup folder is as the name implies not backed-up, and this is where all the other files belonging to the project is kept, like everything that is created by programs that you run. Backup is expensive, so we don’t want to waste it on temporary files generated by your analysis programs, which could be re-run. The nobackup folder is the folder you will keep most of your files in.\nAs seen in the lecture, the command for moving around is cd. The command stands for Change Directory and does exactly that. It is the equivalent of double clicking a folder in a GUI.\nTo enter the course project’s proj folder, simply type cd /proj/naiss2023-22-862.\nHave a look around and see which folders there are. This is the folder where all the non-replacable files belonging to a project would go, like the raw sequencing data that is delivered by the sequencing platforms. Since we’ll be creating a bunch of temporary files during these labs, we will have to do that in the nobackup folder.\nGo there using the cd command.\n$ cd nobackup\nWe can easily see that this is a relative path, since it does not start with a /. That means that this command will only work when you are standing in your project folder. If you are standing somewhere else and say that you want to enter a folder named nobackup, the computer will tell you that there is no folder named nobackup where you are located at the moment.\nThe absolute path to the course’s nobackup folder would be /proj/naiss2023-22-862/nobackup\nIt is the exact same thing as if you are using a GUI. If you are standing on your desktop, you can double click a folder which is located on your desktop. But if you are standing in another folder, you can’t double click on that same folder, because it is just not located there. You have to move to your desktop first, and then double click it.\nIf you look around in the nobackup folder, you probably only have a folder called private. This is how every nobackup folder looks before you start putting files there.\nTyping ls -l all the time is.. more annoying than one would think, so someone came up with the good idea to add a shortcut here. If you type ll, it is the same as typing ls -l. Use it from now on.\nNow we have practised moving around and looking at what we have in folders. The next step will show you how to do the same thing, but without the moving around part.\nIf we want to look at what we have in our home folder, while standing in the course’s project folder, we type ll /home/username/ and remember to substitute <username> with your own user name.\n$ ll /home/username\nSince most programmers are lazy (efficient), there is a shortcut to your home folder so that you don’t have to write it all the time. If you write ~/ it means the same as if you would write /home/<username>/\nTry using it with ls:\n$ ll /home/username\nor\n$ ll ~/" + }, + { + "objectID": "topics/linux/lab_linux_intro.html#copy-lab-files", + "href": "topics/linux/lab_linux_intro.html#copy-lab-files", + "title": "Introduction To Linux", + "section": "4 Copy lab files", + "text": "4 Copy lab files\nNow you will need some files. To avoid all the course participants editing the same file all at once, undoing each other’s edits, each participant will get their own copy of the needed files.\nThe files are located in the folder /sw/courses/ngsintro/linux/linux_tutorial\nor they can be downloaded if you are not on UPPMAX at the moment, files.tar.gz (instruction on how to download further down)\nFor structures sake, first create a folder with your username in the nobackup folder, and a folder called linux_tutorial inside that folder, where you can put all your lab files.\nThis can be done in 2 ways:\n\n\nmkdir /proj/naiss2023-22-862/nobackup/username\nmkdir /proj/naiss2023-22-862/nobackup/username/linux_tutorial\n\n\nor\n\n\nmkdir -p /proj/naiss2023-22-862/nobackup/username/linux_tutorial\n\n\nThe reason for this is that Linux will not like it if you try to create the folder linux_tutorial inside a folder (the one named like your username) that does not exist yet. Then, you have the choice to either first create the one named like your username (the first way), or to tell Linux to create it for you by giving it the -p option (the second way).\nNext, copy the lab files to this folder.\ncp -r <source-folder> <destination-folder>\n\n\ncp -r /sw/courses/ngsintro/linux/linux_tutorial/* /proj/naiss2023-22-862/nobackup/username/linux_tutorial\n\n\n-r denotes recursively, which means all the files including sub-folders of the source folder. Without it, only files directly in the source folder would be copied, NOT sub-folders and files in sub-folders.\n Remember to tab-complete to avoid typos and too much writing.\nIf you are unable to copy the files on UPPMAX, you can download the files from this link instead of copying them. This is done with the command wget (web get). It works kind of the same way as the cp command, but you give it a source URL instead of a source file, and you specify the destination by giving it a prefix, a path that will be appended in front on the file name when it’s downloaded.\ni.e; if you want to download the file http://somewhere.com/my.file and you give it the prefix ~/analysis/, the downloaded file will be saved as ~/analysis/my.file.\nEx: wget -P <destination prefix> <source URL>" + }, + { + "objectID": "topics/linux/lab_linux_intro.html#unpack-files", + "href": "topics/linux/lab_linux_intro.html#unpack-files", + "title": "Introduction To Linux", + "section": "5 Unpack files", + "text": "5 Unpack files\nGo to the folder you just copied and see what is in it.\n Remember to tab-complete to avoid typos and too much writing.\n\n\ncd /proj/naiss2023-22-862/nobackup/username/linux_tutorial\nll\n\n\ntar.gz is a file ending given to compressed files, something you will encounter quite often. Compression decreases the size of the files which is good when downloading, and it can take thousands of files and compress them all into a single compressed file. This is both convenient for the person downloading and speeds up the transfer more than you would think.\nTo unpack the files.tar.gz file use the following line while standing in the newly copied linux_tutorial folder.\n$ tar -xzvf files.tar.gz\nThe command will always be the same for all tar.gz files you want to unpack. -xzvf means eXtract from a Zipped file, Verbose (prints the name of the file being unpacked), from the specified File (f must always be the last of the letters).\nLook in the folder again and see what we just unpacked:\n[user@milou2 linux_tutorial]$ ls -la\ntotal 512\ndrwxrwsr-x 12 user g20XXXXX 2048 Sep 24 13:19 .\ndrwxrwsr-x 6 user g20XXXXX 2048 Sep 24 13:19 ..\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 a_strange_name\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 backed_up_proj_folder\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 external_hdd\n-rwxrwxr-x 1 user g20XXXXX 17198 Sep 24 13:19 files.tar.gz\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 important_results\ndrwxrwsr-x 2 user g20XXXXX 129024 Sep 19 2012 many_files\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 old_project\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 24 13:19 other_file.old\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 part_1\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 part_2\ndrwxrwsr-x 2 user g20XXXXX 2048 Jan 28 2012 this_has_a_file\ndrwxrwsr-x 2 user g20XXXXX 2048 Jan 28 2012 this_is_empty\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 useless_file" + }, + { + "objectID": "topics/linux/lab_linux_intro.html#copying-and-moving-files", + "href": "topics/linux/lab_linux_intro.html#copying-and-moving-files", + "title": "Introduction To Linux", + "section": "6 Copying and moving files", + "text": "6 Copying and moving files\nLet’s move some files. Moving files might be one of the more common things you do, after cd and ls. You might want to organize your files in a better way, or move important result files to the project folder, who knows?\nWe will start with moving our important result to a backed-up folder. When months of analysis is done, the last thing you want is to lose your files. Typically this would mean that you move the final results to your project folder.\nIn this example, we want to move the result files only, located in the folder important_results, to our fake project folder, called backed_up_proj_folder.\nThe syntax for the move command is:\n$ mv <source> <destination>\nFirst, take a look inside the important_results folder:\n[user@milou2 linux_tutorial]$ ll important_results/\ntotal 0\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 dna_data_analysis_result_file_that_is_important-you_should_really_use_tab_completion_for_file_names.bam\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 temp_file-1\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 temp_file-2\nYou see that there are some unimportant temporary files that you have no interest in. Just to demonstrate the move command, I will show you how to move one of these temporary files to your backed-up project folder:\n$ mv important_results/temp_file-1 backed_up_proj_folder/\n Now do the same, but move the important DNA data file!\nLook in the backed-up project folder to make sure you moved the file correctly.\n[user@milou2 linux_tutorial]$ ll backed_up_proj_folder/\ntotal 0\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 dna_data_analysis_result_file_that_is_important-you_should_really_use_tab_completion_for_file_names.bam\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 last_years_data\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 temp_file-1\nAnother use for the move command is to rename things. When you think of it, renaming is just a special case of moving. You move the file to a location and give the file a new name in the process. The location you move the file to can very well be the same folder the file already is in. To give this a try, we will rename the folder a_strange_name to a better name.\n$ mv a_strange_name a_better_name\nLook around to see that the name change worked.\n[user@milou2 linux_tutorial]$ mv a_strange_name a_better_name\n[user@milou2 linux_tutorial]$ ll\ntotal 448\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 a_better_name\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 24 13:40 backed_up_proj_folder\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 external_hdd\n-rwxrwxr-x 1 user g20XXXXX 17198 Sep 24 13:36 files.tar.gz\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 24 13:40 important_results\ndrwxrwsr-x 2 user g20XXXXX 129024 Sep 19 2012 many_files\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 old_project\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 24 13:36 other_file.old\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 part_1\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 part_2\ndrwxrwsr-x 2 user g20XXXXX 2048 Jan 28 2012 this_has_a_file\ndrwxrwsr-x 2 user g20XXXXX 2048 Jan 28 2012 this_is_empty\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 useless_file\nSometimes you don’t want to move things, you want to copy them. Moving a file will remove the original file, whereas copying the file will leave the original untouched. An example when you want to do this could be that you want to give a copy of a file to a friend. Imagine that you have a external hard drive that you want to place the file on. The file you want to give to your friend is data from last years project, which is located in your backed_up_project_folder, backed_up_proj_folder/last_years_data\nAs with the move command, the syntax is\n$ cp <source> <destination>\n$ cp backed_up_proj_folder/last_years_data external_hdd/\nTake a look in the external_hdd to make sure the file got copied.\n[user@milou2 linux_tutorial]$ cp backed_up_proj_folder/last_years_data external_hdd/\n[user@milou2 linux_tutorial]$ ll external_hdd/\ntotal 0\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 24 13:46 last_years_data" + }, + { + "objectID": "topics/linux/lab_linux_intro.html#deleting-files", + "href": "topics/linux/lab_linux_intro.html#deleting-files", + "title": "Introduction To Linux", + "section": "7 Deleting files", + "text": "7 Deleting files\nSometimes you will delete files. Usually this is when you know that the file or files are useless to you, and they only take up space on your hard drive or UPPMAX account.\nTo delete a file, we use the ReMove command, rm. Syntax:\n$ rm <file to remove>\nIf you want, you can also specify multiple files at once, as many as you want!\n$ rm <file to remove> <file to remove> <file to remove> <file to remove> <file to remove>\n\n Danger\nThere is no trash bin in Linux. If you delete a file, it is gone. So be careful when deleting stuff.\n\nTry it out by deleting the useless file in the folder you are standing in. First, look around in the folder to see the file.\n[user@milou2 linux_tutorial]$ ll\ntotal 448\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 a_better_name\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 24 13:40 backed_up_proj_folder\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 24 13:46 external_hdd\n-rwxrwxr-x 1 user g20XXXXX 17198 Sep 24 13:36 files.tar.gz\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 24 13:40 important_results\ndrwxrwsr-x 2 user g20XXXXX 129024 Sep 19 2012 many_files\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 old_project\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 24 13:36 other_file.old\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 part_1\ndrwxrwsr-x 2 user g20XXXXX 2048 Sep 19 2012 part_2\ndrwxrwsr-x 2 user g20XXXXX 2048 Jan 28 2012 this_has_a_file\ndrwxrwsr-x 2 user g20XXXXX 2048 Jan 28 2012 this_is_empty\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 useless_file\nNow remove it.\n$ rm useless_file\nSimilarly, folders can be removed too. There is even a special command for removing folders, rmdir. They work similar to rm, except that they can’t remove files. There are two folders, this_is_empty and this_has_a_file, that we now will delete.\n$ rmdir this_is_empty\n$ rmdir this_has_a_file\nIf you look inside this_has_a_file,\n[user@milou2 linux_tutorial]$ ll this_has_a_file\ntotal 0\n-rwxrwxr-x 1 user g20XXXXX 0 Jan 28 2012 file\nyou see that there is a file in there! Only directories that are completely empty can be deleted using rmdir. To be able to delete this_has_a_file, either delete the file manually and then remove the folder\n$ rm this_has_a_file/file\n$ rmdir this_has_a_file\nor delete the directory recursively, which will remove this_has_a_file and everything inside:\n$ rm -r this_has_a_file" + }, + { + "objectID": "topics/linux/lab_linux_intro.html#open-files", + "href": "topics/linux/lab_linux_intro.html#open-files", + "title": "Introduction To Linux", + "section": "8 Open files", + "text": "8 Open files\nSo what happens if you give your files bad names like file1 or results? You take a break in a project and return to it 4 months later, and all those short names you gave your files doesn’t tell you at all what the files actually contain.\nOf course, this never happens because you ALWAYS name your files so that you definitely know what they contain. But let’s say it did happen. Then the only way out is to look at the contents of the files and try to figure out if it is the file you are looking for.\n Now, we are looking for that really good script we wrote a couple of months ago in that other project. Look in the project’s folder, old_project and find the script.\n[user@milou2 linux_tutorial]$ ll old_project/\ntotal 96\n-rwxrwxr-x 1 user g20XXXXX 39904 Sep 19 2012 a\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 stuff_1\n-rwxrwxr-x 1 user g20XXXXX 1008 Sep 19 2012 the_best\nNot so easy with those names.. We will have to use less to look at the files and figure out which is which.\n$ less <filename>\n Press q to close it down, use arrows keys to scroll up/down.\nHave a look at the_best, that must be our script, right?\n$ less old_project/the_best\nI guess not. Carrot cakes might be the bomb, but they won’t solve bioinformatic problems. Have a look at the file a instead.\nThat’s more like it!\nNow imagine that you had hundreds of files with weird names, and you really needed to find it. Lesson learned: name your files so that you know what they are! And don’t be afraid to create folders to organise files.\nAnother thing to think about when opening files in Linux is which program should you open the file in? The programs we covered during the lectures are nano and less. The main difference between these programs in that less can’t edit files, only view them. Another difference is that less doesn’t load the whole file into the RAM memory when opening it.\nSo, why care about how the program works? I’ll show you why. This time we will be opening a larger file, located in the course’s project folder. It’s 65 megabytes, so it is a tiny file compared with bio-data. Normal sequencing files can easily be 100-1000 times larger than this.\nFirst, open the file with nano.\n$ nano <filename>\n$ nano /sw/courses/ngsintro/linux/linux_additional-files/large_file\n Press Ctrl+X to close it down, use arrows to scroll up/down).\nIs the file loaded yet? Now take that waiting time and multiply it with 100-1000. Now open the file with less. Notice the difference?\nhead and tail works the same was as less in this regard. They don’t load the whole file into RAM, they just take what they need.\nTo view the first rows of the large file, use head.\n$ head <filename>\n$ head /sw/courses/ngsintro/linux/linux_additional-files/large_file\nRemember how to view an arbitrary number of first rows in a file?\n$ head -n <number of rows to view> <filename>\n$ head -n 23 /sw/courses/ngsintro/linux/linux_additional-files/large_file\nThe same syntax for viewing the last rows of a file with tail:\n$ tail <filename>\n$ tail /sw/courses/ngsintro/linux/linux_additional-files/large_file\n$ tail -n <number of rows to view> <filename>\n$ tail -n 23 /sw/courses/ngsintro/linux/linux_additional-files/large_file" + }, + { + "objectID": "topics/linux/lab_linux_intro.html#wildcards", + "href": "topics/linux/lab_linux_intro.html#wildcards", + "title": "Introduction To Linux", + "section": "9 Wildcards", + "text": "9 Wildcards\nSometimes (most of the time really) you have many files. So many that it would take you a day just to type all their names. This is where wildcards saves the day. The wildcard symbol in Linux is the star sign, * , and it means literally anything. Say that you want to move all the files which has names starting with sample_1_ and the rest of the name doesn’t matter. You want all the files belonging to sample_1. Then you could use the wildcard to represent the rest of the name.\n DO NOT run this command, it’s just an example.\n$ mv sample_1_* my_other_folder\nWe can try it out on the example files I have prepared. There are two folders called part_1 and part_2. We want to collect all the .txt files from both these folders in one of the folders. Look around in both the folders to see what they contain.\n[user@milou2 linux_tutorial]$ ll part_1/\ntotal 0\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 file_1.txt\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 file_2.txt\n[user@milou2 linux_tutorial]$ ll part_2\ntotal 0\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 file_3.txt\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 file_4.txt\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 garbage.tmp\n-rwxrwxr-x 1 user g20XXXXX 0 Sep 19 2012 incomplete_datasets.dat\nWe see that part_1 only contains .txt files, and that part_2 contains some other files as well. The best option seems to be to move all .txt files from part_2 info part_1.\n$ mv part_2/*.txt part_1/\nThe wildcard works with most, if not all, Linux commands. We can try using wildcards with ls. Look in the folder many_files. Yes, there are hundreds of .docx files in there. But, there are a couple of .txt files in there as well. Find out how many .docx and .txt files exist.\n Try to figure out the solution on your own. Then check the answer below.\n\n\n$ ll many_files/*.docx\n$ ll many_files/*.txt" + }, + { + "objectID": "topics/linux/lab_linux_intro.html#utility-commands", + "href": "topics/linux/lab_linux_intro.html#utility-commands", + "title": "Introduction To Linux", + "section": "10 Utility commands", + "text": "10 Utility commands\nOk, the last 2 commands for now are top and man.\ntop can be useful when you want to look at which programs are being run on the computer, and how hard the computer is working. Type top and have a look.\n$ top\n Press q to exit.\nTasks: 376 total, 2 running, 290 sleeping, 0 stopped, 0 zombie\n%Cpu(s): 2.7 us, 1.3 sy, 0.0 ni, 95.3 id, 0.1 wa, 0.0 hi, 0.6 si, 0.0 st\nKiB Mem : 32590776 total, 16233548 free, 8394804 used, 7962424 buff/cache\nKiB Swap: 99999744 total, 99999744 free, 0 used. 22658832 avail Mem\n\n PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND \n 3286 roy 20 0 4557248 522400 170808 R 12.3 1.6 62:49.20 gnome-shell \n 3113 roy 20 0 1282356 385012 290540 S 8.0 1.2 42:00.49 Xorg \n22213 roy 20 0 5474576 544848 101592 S 5.6 1.7 102:55.33 zoom \n 6186 roy 20 0 710140 60504 35836 S 3.0 0.2 0:00.62 terminator \n 4248 roy 20 0 2737604 556212 140580 S 2.7 1.7 54:51.48 QtWebEngineProc \n 4632 roy 20 0 4866068 0.993g 281532 S 2.7 3.2 69:18.68 firefox \n 6548 roy 20 0 3703060 509340 189452 S 2.7 1.6 15:26.80 Web Content \n 9338 roy 20 0 4407324 846700 213324 S 2.7 2.6 15:53.71 Web Content \n 4776 roy 20 0 3310524 318364 102700 S 2.0 1.0 8:53.07 WebExtensions \n 6595 roy 20 0 4133152 992224 187540 S 1.3 3.0 18:51.05 Web Content \n 952 root -51 0 0 0 0 S 1.0 0.0 2:40.89 irq/51-SYNA2393 \n 7800 roy 20 0 1213744 238536 129392 S 1.0 0.7 11:15.74 atom \n 1 root 20 0 226080 9836 6692 S 0.7 0.0 2:07.87 systemd \n 6690 roy 20 0 3492596 560304 166588 S 0.7 1.7 8:08.77 Web Content \n12895 roy 20 0 3320332 294820 172212 S 0.7 0.9 7:05.93 Web Content \n 10 root 20 0 0 0 0 I 0.3 0.0 2:43.21 rcu_sched \n 1052 root 20 0 2505296 36228 22444 S 0.3 0.1 3:45.16 containerd \n 2631 gdm 20 0 4044492 198480 142328 S 0.3 0.6 1:55.32 gnome-shell\nEach row in top corresponds to one program running on the computer, and the column describe various information about the program. The right-most column shows you which program the row is about.\nThere are mainly 2 things that are interesting when looking in top. The column %CPU describes how much cpu is used by each program. If you are doing calculations, which is what bioinformatics is mostly about, the cpu usage should be high. The numbers in the column is how many percent of a core the program is running. If you have a computer with 8 cores, like the UPPMAX computers, you can have 8 programs using 100% of a core each running at the same time without anything slowing down. As soon as you start a 9th program, it will have to share a core with another program and those 2 programs will run at half-speed since a core can only work that fast. In the example above, program gnome-shell is using 12.3% of a core.\nThe column %MEM describes how much memory each program uses. The numbers mean how many percent of the total memory a program uses. In the example above, the program firefox is using 3.2% of the total memory.\nThe area in the top describes the overall memory usage. Total tells you how much memory the computer has, used tells you how much of the memory is being used at the moment, and free tells you how much memory is free at the moment.\nTotal = Used + Free\nA warning sign you can look for in top is when you are running an analysis which seems to take forever to complete, and you see that there is almost no cpu usage on the computer. That means that the computer is not doing any calculation, which could be bad. If you look at the memory usage at the same time, and see that it’s maxed out (used 100% of total), you can more or less abort the analysis.\nWhen the memory runs out, the computer more or less stops. Since it can’t fit everything into the RAM memory, it will start using the hard drive to store the things it can’t fit in the RAM. Since the hard drive is ~1000 times slower than the RAM, things will be going in slow-motion. The solution could be to either change the settings of the program you are running to decrease the memory usage (if the program has that functionality), or just get a computer with more memory.\nYou might wonder how the heck am I supposed to be able to remember all these commands, options and flags? The simple answer is that you won’t. Not all of them at least. You might remember ls, but was it -l or -a you should use to see hidden files? You might wish that there was a manual for these things.\nGood news everyone, there is a manual! To get all the nitty-gritty details about ls, you use the man command.\n$ man <command you want to look at>\n$ man ls\nLS(1) User Commands LS(1)\n\nNAME\n ls - list directory contents\n\nSYNOPSIS\n ls [OPTION]... [FILE]...\n\nDESCRIPTION\n List information about the FILEs (the current directory by default).\n Sort entries alphabetically if none of -cftuvSUX nor --sort is speci‐\n fied.\n\n Mandatory arguments to long options are mandatory for short options too.\n\n -a, --all\n do not ignore entries starting with .\n\n -A, --almost-all\n do not list implied . and ..\n\n --author\n with -l, print the author of each file\n\n -b, --escape\n print C-style escapes for nongraphic characters\n\n --block-size=SIZE\n scale sizes by SIZE before printing them; e.g., '--block-size=M'\n Manual page ls(1) line 1 (press h for help or q to quit)\nThis will open a less window (remember, q to close it down, arrows to scroll) with the manual page about ls. Here you will be able to read everything about ls. You’ll see which flag does what (-a is to show the hidden files, which in linux are files with a name starting with a dot .), which syntax the program has, etc. If you are unsure about how to use a command, look it up using man.\nThe man pages can be a bit tricky to understand at first, but you get used to it with time. If it is still unclear, try searching for it on the internet. You are bound to find someone with the exact same question as you, that has already asked on a forum, and gotten a good answer. 5 years ago.\n\n\n\n\n\n\nOptional\n\n\n\nIf you still have time left on the lab and you finished early, check out the Linux file permissions lab." + }, + { + "objectID": "topics/other/lab_connect.html", + "href": "topics/other/lab_connect.html", + "title": "Connecting to UPPMAX", + "section": "", + "text": "We will teach you two different ways to connect to UPPMAX. From UPPMAX point of view it doesn’t matter which one you use, and you can change whenever you want to or even use both ways simultaiously. The first one is a text-based SSH connection, and the other one is a graphical remote desktop. The latter one is useful if you need to view images or documents in GUI programs without having to first download the image/document to your own computer first. Since it is using graphics, it will require you to have an internet connection that is good and stable.\nThe reason we will teach you two ways is that some parts of this course will require you to view plots and images, and adding an additional download step would just unneccesarily complicate things." + }, + { + "objectID": "topics/other/lab_connect.html#ssh-connection", + "href": "topics/other/lab_connect.html#ssh-connection", + "title": "Connecting to UPPMAX", + "section": "1 SSH connection", + "text": "1 SSH connection\nLet’s look at the text-based SSH approach first. This type of connection work just fine even on slow internet connections since it only transmitts small amounts of text when you work with it. You will need an SSH program to do this, which fortunately is included in most major operating systems:\n\n Linux: Use Terminal (Included by default)\n OSX: Use Terminal (Included by default)\n Windows: Use Powershell or Command prompt, both should be installed by default\n\n\n\n\n\n\n\nNote\n\n\n\nWhere username is mentioned, change to your user name.\n\n\nFire up the available SSH program and enter the following:\n$ ssh username@rackham.uppmax.uu.se\nEnter your password when prompted. As you type, nothing will show on the screen. No stars, no dots. It is supposed to be that way. Just type the password and press enter, it will be fine.\nNow your screen should look something like this:\ndahlo@dahlo-xps ~ $ ssh dahlo@rackham.uppmax.uu.se\nLast login: Fri May 18 15:03:59 2018 from mi04.icm.uu.se\n _ _ ____ ____ __ __ _ __ __\n| | | | _ \\| _ \\| \\/ | / \\ \\ \\/ / | System: rackham4\n| | | | |_) | |_) | |\\/| | / _ \\ \\ / | User: dahlo\n| |_| | __/| __/| | | |/ ___ \\ / \\ |\n \\___/|_| |_| |_| |_/_/ \\_\\/_/\\_\\ |\n\n###############################################################################\n\n User Guides: http://www.uppmax.uu.se/support/user-guides\n FAQ: http://www.uppmax.uu.se/support/faq\n\n Write to support@uppmax.uu.se, if you have questions or comments.\n\n\ndahlo@rackham4 ~ $\nNow you are connected to UPPMAX and can start working." + }, + { + "objectID": "topics/other/lab_connect.html#remote-desktop", + "href": "topics/other/lab_connect.html#remote-desktop", + "title": "Connecting to UPPMAX", + "section": "2 Remote desktop", + "text": "2 Remote desktop\nYou can work on UPPMAX interactively through a graphical-user-interface (GUI) desktop environment using ThinLinc.\nWe have a ThinLinc server running at one of the login nodes which allows users to run a remote desktop. It can be reached from a web browser (Chrome and Firefox are the recommended web browsers) or from the ThinLink App. For more details please look here: https://uppmax.uu.se/support-sv/user-guides/thinlinc-graphical-connection-guide/\n\n2.1 Web browser\nTo be able to login via a web browser you will have to set up two-factor authentication first. Follow the instructions at the UPPMAX homepage, and once you are done you can continue below.\n\nGo to the login page, https://rackham-gui.uppmax.uu.se/\nEnter your UPPMAX username.\nEnter your UPPMAX password, followed by your current two-factor authentication code. Eg. if your password is hunter2 and your current two-factor authentication code is 123456 you will enter hunter2123456 as your password.\n\n\n\n\n\nIt will ask you which profile you want to use, so first press the Forward button. Then you can choose which desktop environment you want to use. Xfce is pretty straight-forward and easy to use, but feel free to try either of them. You get to choose every time you login so it’s not a permanent choice.\n\n\n\n\n\nOnce your desktop has been loaded, start a terminal either by clicking the black terminal icon at the bottom of the screen, or by pressing the Applications button in the top left corner and select Terminal Emulator.\n\n\n\n\n\n\n\n\n2.2 ThinLink App\n\nIf you haven’t already done so, download the ThinLinc client matching your local computer (i.e Windows, Linux, MacOS X or Solaris) from https://www.cendio.com/thinlinc/download and install it.\nLaunch the ThinLinc client. You should see a form where you can enter your username and password, and possibly a server name. If you only see this simple form as shown below, you can click Advanced to be able to set the server name.\n\n\n\n\n\nChange the Server setting to rackham-gui.uppmax.uu.se.\nChange the Name setting to your UPPMAX username.\nSet the Password setting to your UPPMAX password.\nYou do not need to change any other settings.\nYou will first come to the ThinLinc profile chooser. Press the Forward button to continue. Then you can choose which desktop environment you want to use. Xfce is pretty straight-forward and easy to use, but feel free to try either of them. You get to choose every time you login so it’s not a permanent choice.\nPress the Connect button.\nIf you connect for the first time you will see the “The server’s host key is not cached …” dialog.\n\n\n\n\n\nOnce your desktop has been loaded, start a terminal either by clicking the black terminal icon at the bottom of the screen, or by pressing the Applications button in the top left corner and select Terminal Emulator.\n\n\n\n\n\n\n\nTwo factor authentication: The ThinLinc client connects over SSH which means it may be required to present a two factor authentication code. If you need to use this when logging in with SSH you also need to use it when logging in with ThinLinc (it depends on where you connect from). The ThinLinc client does not know how to ask for the two factor code, so you will need to use the grace time feature. To do this, first you have to connect with regular SSH and present the required two factor code. Once you have logged in over SSH you can safely exit again. The login server will remember that you just logged in for a few minutes and will not ask for two factor authentication again, so make sure you do not wait too long to connect with the ThinLinc client." + }, + { + "objectID": "topics/other/lab_connect.html#after-connection-to-uppmax", + "href": "topics/other/lab_connect.html#after-connection-to-uppmax", + "title": "Connecting to UPPMAX", + "section": "3 After connection to UPPMAX", + "text": "3 After connection to UPPMAX\nFrom this point forward there is no difference between the two different ways of connection to UPPMAX. Both ways result in you having a terminal running on UPPMAX and from UPPMAX point of view they are the same." + }, + { + "objectID": "topics/other/lab_mac_keyboard.html", + "href": "topics/other/lab_mac_keyboard.html", + "title": "Keyboard Guide", + "section": "", + "text": "Normal\n\n\n\n\n\nHolding shift\n\n\n\n\n\nHolding alt\n\n\n\n\n\nHolding alt+shift" + }, + { + "objectID": "topics/other/lab_qc.html", + "href": "topics/other/lab_qc.html", + "title": "Read quality", + "section": "", + "text": "FastQC performes a series of quality control analyses, called modules. The output is a HTML report with one section for each module, and a summary evaluation of the results in the top. Entirely normal results are marked with a green tick, slightly abnormal results raise warnings (orange exclamation mark), and very unusual results raise failures (red cross).\nIt is important to stress that although the analyses appear to give a pass/fail result, these evaluations must be taken in the context of what you expect from your library. A ‘normal’ sample as far as FastQC is concerned is random and diverse. Some experiments may be expected to produce libraries which are biased in particular ways. You should treat the summary evaluations therefore as pointers to where you should concentrate your attention and understand why your library may not look random and diverse." + }, + { + "objectID": "topics/other/lab_qc.html#fastqc", + "href": "topics/other/lab_qc.html#fastqc", + "title": "Read quality", + "section": "", + "text": "FastQC performes a series of quality control analyses, called modules. The output is a HTML report with one section for each module, and a summary evaluation of the results in the top. Entirely normal results are marked with a green tick, slightly abnormal results raise warnings (orange exclamation mark), and very unusual results raise failures (red cross).\nIt is important to stress that although the analyses appear to give a pass/fail result, these evaluations must be taken in the context of what you expect from your library. A ‘normal’ sample as far as FastQC is concerned is random and diverse. Some experiments may be expected to produce libraries which are biased in particular ways. You should treat the summary evaluations therefore as pointers to where you should concentrate your attention and understand why your library may not look random and diverse." + }, + { + "objectID": "topics/other/lab_qc.html#data", + "href": "topics/other/lab_qc.html#data", + "title": "Read quality", + "section": "2 Data", + "text": "2 Data\nWe will run FastQC on three low-coverage whole genome sequencing (WGS) samples from the public 1000 Genomes project. To speed up the analysis we will only use data from a small genomic region. These are the exact same samples as will be used in the variant-calling workflow lab on Wednesday.\n\n\n\nSample\nDescription\n\n\n\n\nHG00097\nLow coverage WGS\n\n\nHG00100\nLow coverage WGS\n\n\nHG00101\nLow coverage WGS" + }, + { + "objectID": "topics/other/lab_qc.html#run-fastqc", + "href": "topics/other/lab_qc.html#run-fastqc", + "title": "Read quality", + "section": "3 Run FastQC", + "text": "3 Run FastQC\n\n3.1 Connect to Uppmax\nDuring this lab it is best to connect to UPPMAX via a remote desktop (ThinLinc). Instructions for this is available in Canvas under Contents > Additional content > Connecting to UPPMAX. Please follow the instructions in section 1.2 Remote desktop connection.\n\n\n3.2 Book a node\nTo be able to run analyses in the terminal you should book a compute node (or in this case just one core of a node). Make sure you only do this once each day because we have reserved one core per student for the course. If you haven’t already reserved a core today please use this command:\n\n\nsalloc -A naiss2023-22-862 -t 04:00:00 -p core -n 1 --no-shell &\n\n\nOnce your job allocation has been granted (should not take long) you can connect to the node using ssh. To find out the name of your node, use:\nsqueue -u username\nThe node name is found under nodelist header, you should only see one. Connect to that node:\nssh -Y <nodename>\n\n\n3.3 Create a workspace\nYou should work in your folder under the course’s nobackup folder, just like you have done during the previous labs. Start by creating a workspace for this exercise in your folder, and then move into it.\n\n\nmkdir /proj/naiss2023-22-862/nobackup/username/qc\ncd /proj/naiss2023-22-862/nobackup/username/qc\n\n\n\n\n3.4 Symbolic links to data\nThe raw data files are located in\n\n\n/sw/courses/ngsintro/reseq/data/fastq\n\n\nInstead of copying the files to your workspace you should create symbolic links (soft-links) to them. Soft-linking files and folders allows you to work with them as if they were in your current directory, but without multiplying them. Create symbolic links to the fastq files in your workspace:\n\n\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_2.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_2.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_2.fq\n\n\n\n\n3.5 Accessing FastQC\nFastQC is installed in the module system on UPPMAX. Modules must be loaded every time you login to Rackham, or when you connect to a new compute node.\nFirst load the bioinfo-tools module:\nmodule load bioinfo-tools\nThis makes it possible to load FastQC:\nmodule load FastQC/0.11.8\n\n\n3.6 Run FastQC\nRun FastQC on all fastq files:\nfastqc -q *.fq\nThe output is .html documents that shows quality scores along the reads, and other information. Please check what new files were generated with the command:\nls -lrt" + }, + { + "objectID": "topics/other/lab_qc.html#check-the-results", + "href": "topics/other/lab_qc.html#check-the-results", + "title": "Read quality", + "section": "4 Check the results", + "text": "4 Check the results\nThe output from FastQC is a HTML report that should be opened in a web browser. When you have connected to Uppmax via ThinLinc you can open it on Rackham with this command:\nfirefox --no-remote filename.html &\nWe have made the output files that you just created available through the links below, so that you can look at them via your local web-browser:\n\n\n\nSample\nRead 1\nRead 2\n\n\n\n\nHG00097\nHG00097_1.fq\nHG00097_2.fq\n\n\nHG00100\nHG00100_1.fq\nHG00100_2.fq\n\n\nHG00101\nHG00101_1.fq\nHG00101_2.fq\n\n\n\n\n4.1 Per Base Sequence Quality\nThis module shows the distribution of the quality scores at each position in the reads. The quality scores are represented by a Box and Whisker plot with the following elements:\n\nThe central red line is the median value.\nThe yellow box represents the inter-quartile range (25-75%).\nThe upper and lower whiskers represent the 10% and 90% points\nThe blue line represents the mean quality\n\nThe background of the graph divides the y axis into very good quality calls (green), calls of reasonable quality (orange), and calls of poor quality (red).\n\n4.1.1 Questions\n\nWhich positions in the reads have a median phred-score above 28 (very good quality calls) in each sample?\n\nDo any of the samples have warnings or failures in the Per Base Sequence Quality module?\nWhy? Please look in the documentation of this module.\n\n\n\n\n4.2 Sequence Length Distribution\nThis module shows the length distribution of the reads in the file.\n\n4.2.1 Questions\n\nHow long are the reads?\nDo any of the samples have warnings or failures in the Sequence Length Distribution module?\nWhy? Please look in the documentation of this module" + }, + { + "objectID": "topics/other/lab_qc.html#answers", + "href": "topics/other/lab_qc.html#answers", + "title": "Read quality", + "section": "5 Answers", + "text": "5 Answers\nWhen you have finished the exercise, please have a look at this document with answers to questions, and compare them with your answers." + }, + { + "objectID": "topics/other/lab_qc.html#documentation", + "href": "topics/other/lab_qc.html#documentation", + "title": "Read quality", + "section": "6 Documentation", + "text": "6 Documentation\n\nFastQC\nIf you want to learn more details about FastQC please have a look at this video by the Babraham Bioinformatics Institute." + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html", + "href": "topics/rnaseq/lab_rnaseq.html", + "title": "RNASeq Workflow", + "section": "", + "text": "RNA-seq has become a powerful approach to study the continually changing cellular transcriptome. Here, one of the most common questions is to identify genes that are differentially expressed between two conditions, e.g. controls and treatment. The main exercise in this tutorial will take you through a basic bioinformatic analysis pipeline to answer just that, it will show you how to find differentially expressed (DE) genes.\nMain exercise\n\n01 Check the quality of the raw reads with FastQC\n02 Map the reads to the reference genome using HISAT2\n03 Assess the post-alignment quality using QualiMap\n04 Count the reads overlapping with genes using featureCounts\n05 Find DE genes using DESeq2 in R\n\nRNA-seq experiment does not necessarily end with a list of DE genes. If you have time after completing the main exercise, try one (or more) of the bonus exercises. The bonus exercises can be run independently of each other, so choose the one that matches your interest. Bonus sections are listed below.\nBonus exercises\n\n01 Functional annotation of DE genes using GO/Reactome databases\n02 RNA-Seq figures and plots using R\n03 Visualisation of RNA-seq BAM files using IGV genome browser\n\n\n\n\n\n\n\nGeneral guide\n\n\n\n\nIn paths, remember to change username with your actual UPPMAX username.\nYou are welcome to try your own solutions to the problems, before checking the solution. Click the button to see the suggested solution. There is more than one way to complete a task. Discuss with person next to you and ask us when in doubt.\nInput code blocks are displayed like shown below.\n\n\ncommand" + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html#introduction", + "href": "topics/rnaseq/lab_rnaseq.html#introduction", + "title": "RNASeq Workflow", + "section": "", + "text": "RNA-seq has become a powerful approach to study the continually changing cellular transcriptome. Here, one of the most common questions is to identify genes that are differentially expressed between two conditions, e.g. controls and treatment. The main exercise in this tutorial will take you through a basic bioinformatic analysis pipeline to answer just that, it will show you how to find differentially expressed (DE) genes.\nMain exercise\n\n01 Check the quality of the raw reads with FastQC\n02 Map the reads to the reference genome using HISAT2\n03 Assess the post-alignment quality using QualiMap\n04 Count the reads overlapping with genes using featureCounts\n05 Find DE genes using DESeq2 in R\n\nRNA-seq experiment does not necessarily end with a list of DE genes. If you have time after completing the main exercise, try one (or more) of the bonus exercises. The bonus exercises can be run independently of each other, so choose the one that matches your interest. Bonus sections are listed below.\nBonus exercises\n\n01 Functional annotation of DE genes using GO/Reactome databases\n02 RNA-Seq figures and plots using R\n03 Visualisation of RNA-seq BAM files using IGV genome browser\n\n\n\n\n\n\n\nGeneral guide\n\n\n\n\nIn paths, remember to change username with your actual UPPMAX username.\nYou are welcome to try your own solutions to the problems, before checking the solution. Click the button to see the suggested solution. There is more than one way to complete a task. Discuss with person next to you and ask us when in doubt.\nInput code blocks are displayed like shown below.\n\n\ncommand" + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html#data-description", + "href": "topics/rnaseq/lab_rnaseq.html#data-description", + "title": "RNASeq Workflow", + "section": "2 Data description", + "text": "2 Data description\nThe data used in this exercise is from the paper: Poitelon, Yannick, et al. YAP and TAZ control peripheral myelination and the expression of laminin receptors in Schwann cells. Nature neuroscience 19.7 (2016): 879. In this study, YAP and TAZ genes were knocked-down in Schwann cells to study myelination, using the sciatic nerve in mice as a model.\nMyelination is essential for nervous system function. Schwann cells interact with neurons and the basal lamina to myelinate axons using receptors, signals and transcription factors. Hippo pathway is a conserved pathway involved in cell contact inhibition, and it acts to promote cell proliferation and inhibits apoptosis. The pathway integrates mechanical signals (cell polarity, mechanotransduction, membrane tension) and gene expression response. In addition to its role in organ size control, the Hippo pathway has been implicated in tumorigenesis, for example its deregulation occurs in a broad range of human carcinomas. Transcription co-activators YAP and TAZ are two major downstream effectors of the Hippo pathway, and have redundant roles in transcriptional activation.\nThe material for RNA-seq was collected from 2 conditions (Wt and KO), each with 3 biological replicates.\n\n\n\n\n\n\nAccession\nCondition\nReplicate\n\n\n\n\nSRR3222409\nKO\n1\n\n\nSRR3222410\nKO\n2\n\n\nSRR3222411\nKO\n3\n\n\nSRR3222412\nWt\n1\n\n\nSRR3222413\nWt\n2\n\n\nSRR3222414\nWt\n3\n\n\n\n\n\n\n\n\n\n\nNote\n\n\n\nFor the purpose of this tutorial, to shorten the time needed to run various bioinformatics steps, we have picked reads for a single chromosome (Chr 19) and downsampled the reads. We randomly sampled, without replacement, 25% reads from each sample, using fastq-sample from the toolset fastq-tools." + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html#main-exercise", + "href": "topics/rnaseq/lab_rnaseq.html#main-exercise", + "title": "RNASeq Workflow", + "section": "3 Main exercise", + "text": "3 Main exercise\nThe main exercise covers Differential Gene Expression (DGE) workflow from raw reads to a list of differentially expressed genes.\n\n3.1 Using Uppmax\n\n\n\n\n\n\nUse ThinLinc\n\n\n\nIf you have issues opening GUI windows from UPPMAX through the terminal, it is recommended to use ThinLinc.\n\n\nIf you are not on ThinLinc, connect to UPPMAX first. Remember to replace username.\n\nssh -Y username@rackham.uppmax.uu.se\n\nBook a node.\nFor the RNA-Seq part of the course, we will work on the Rackham cluster. A standard compute node on cluster Rackham has 128 GB of RAM and 20 cores. We will use 1 core per person for this session. Therefore, each core gives you 6.4 GB of RAM. The code below is valid to run at the start of the day. If you are running it in the middle of a day, you need to decrease the time (-t). Do not run this twice and also make sure you are not running computations on a login node.\nBook compute resources for RNA-Seq lab.\n\n\nsalloc -A naiss2023-22-862 -t 03:00:00 -p core -n 1 --no-shell\n\n\nCheck allocation. Remember to replace username.\nsqueue -u username\nOnce allocation is granted, log on to the compute node. Remember to replace nodename.\nssh -Y nodename\n\n3.1.1 Set-up directory\nSetting up the directory structure is an important step as it helps to keep our raw data, intermediate data and results in an organised manner. All work must be carried out at this location /proj/naiss2023-22-862/nobackup/username/ where username is your user name.\nCreate a directory named rnaseq. All RNA-Seq related activities must be carried out in this sub-directory named rnaseq.\n\nmkdir rnaseq\n\n Create the directory structure as shown below.\nusername/\nrnaseq/\n +-- 1_raw/\n +-- 2_fastqc/\n +-- 3_mapping/\n +-- 4_qualimap/\n +-- 5_dge/\n +-- 6_multiqc/\n +-- reference/\n | +-- mouse_chr19_hisat2/\n +-- scripts/\n +-- funannot/\n +-- plots\n\n\ncd rnaseq\nmkdir 1_raw 2_fastqc 3_mapping 4_qualimap 5_dge 6_multiqc reference scripts funannot plots\ncd reference\nmkdir mouse_chr19_hisat2\ncd ..\n\n\nThe 1_raw directory will hold the raw fastq files (soft-links). 2_fastqc will hold FastQC outputs. 3_mapping will hold the mapping output files. 4_qualimap will hold the QualiMap output files. 5_dge will hold the counts from featureCounts and all differential gene expression related files. 6_multiqc will hold MultiQC outputs. reference directory will hold the reference genome, annotations and aligner indices. The funannot and plots directory are optional for bonus steps.\n It might be a good idea to open an additional terminal window. One to navigate through directories and another for scripting in the scripts directory.\n\n\n3.1.2 Create symbolic links\nWe have the raw fastq files in this remote directory: /sw/courses/ngsintro/rnaseq/main/1_raw/. We are going to create symbolic links (soft-links) for these files from our 1_raw directory to the remote directory. We do this because fastq files tend to be large files and simply copying them would use up a lot of storage space. Soft-linking files and folders allows us to work with those files as if they were actually there.\nChange to 1_raw directory. Use pwd to check if you are standing in the correct directory.\n\n\ncd 1_raw\npwd\n\n\n\n\n/proj/naiss2023-22-862/nobackup/username/rnaseq/1_raw\n\n\nRun below to create softlinks. Note that the command ends in a space followed by a period.\n\n\nln -s /sw/courses/ngsintro/rnaseq/main/1_raw/*.gz .\n\n\nCheck if your files have linked correctly. You should be able to see as below.\n\nls -l\n\n\nSRR3222409-19_1.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222409-19_1.fq.gz\nSRR3222409-19_2.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222409-19_2.fq.gz\nSRR3222410-19_1.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222410-19_1.fq.gz\nSRR3222410-19_2.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222410-19_2.fq.gz\nSRR3222411-19_1.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222411-19_1.fq.gz\nSRR3222411-19_2.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222411-19_2.fq.gz\nSRR3222412-19_1.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222412-19_1.fq.gz\nSRR3222412-19_2.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222412-19_2.fq.gz\nSRR3222413-19_1.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222413-19_1.fq.gz\nSRR3222413-19_2.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222413-19_2.fq.gz\nSRR3222414-19_1.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222414-19_1.fq.gz\nSRR3222414-19_2.fq.gz -> /sw/courses/ngsintro/rnaseq/main/1_raw/SRR3222414-19_2.fq.gz\n\n\n\n\n3.2 FastQC\nQuality check using FastQC\nAfter receiving raw reads from a high throughput sequencing centre it is essential to check their quality. FastQC provides a simple way to do some quality control check on raw sequence data. It provides a modular set of analyses which you can use to get a quick impression of whether your data has any problems of which you should be aware before doing any further analysis.\n Change into the 2_fastqc directory. Use pwd to check if you are standing in the correct directory.\n\n\ncd ../2_fastqc\npwd\n\n\n\n\n/proj/naiss2023-22-862/nobackup/username/rnaseq/2_fastqc\n\n\nLoad Uppmax modules bioinfo-tools and FastQC FastQC/0.11.9.\n\nmodule load bioinfo-tools\nmodule load FastQC/0.11.9\n\nOnce the module is loaded, FastQC program is available through the command fastqc. Use fastqc --help to see the various parameters available to the program. We will use -o to specify the output directory path and finally, the name of the input fastq file to analyse. The syntax to run one file will look like below.\n Don’t run this. It’s just a template.\n\nfastqc -o . ../1_raw/filename.fq.gz\n\nBased on the above command, we will write a bash loop script to process all fastq files in the directory. Writing multi-line commands through the terminal can be a pain. Therefore, we will run larger scripts from a bash script file. Move to your scripts directory and create a new file named fastqc.sh.\n\n\ncd ../scripts\npwd\n\n\n\n\n/proj/naiss2023-22-862/nobackup/username/rnaseq/scripts\n\n\nThe command below creates a new file in the current directory.\n\ntouch fastqc.sh\n\nUse a text editor (nano,Emacs,gedit etc.) to edit fastqc.sh.\n gedit behaves like a regular text editor with a standard graphical interface.\n\ngedit fastqc.sh &\n\n Adding & at the end sends that process to the background, so that the console is free to accept new commands.\nThen add the lines below and save the file.\n\n#!/bin/bash\n\nmodule load bioinfo-tools\nmodule load FastQC/0.11.9\n\nfor i in ../1_raw/*.gz\ndo\n echo \"Running $i ...\"\n fastqc -o . \"$i\"\ndone\n\nThis script loops through all files ending in .gz. In each iteration of the loop, it executes fastqc on the file. The -o . flag to fastqc indicates that the output must be exported in this current directory (ie; the directory where this script is run).\nChange to the 2_fastqc directory. Use pwd to check if you are standing in the correct directory. Run the script file fastqc.sh\n\n\ncd ../2_fastqc\npwd\n\n\n\n\n/proj/naiss2023-22-862/nobackup/username/rnaseq/2_fastqc\n\n\n\nbash ../scripts/fastqc.sh\n\nAfter the fastqc run, there should be a .zip file and a .html file for every fastq file. The .html file is the report that you need. Download the .html files to your computer and open them in a web browser. You do not need to necessarily look at all files now. We will do a comparison with all samples when using the MultiQC tool.\n Run this step in a LOCAL terminal and NOT on Uppmax. Open a terminal locally on your computer, move to a suitable download directory and run the command below to download one html report.\n Remember to replace username (twice).\n\n\nscp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/2_fastqc/SRR3222409-19_1_fastqc.html .\n\n\nor download the whole directory.\n\n\nscp -r username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/2_fastqc .\n\n\n\n\n\n\n\n\nDownloading using a GUI\n\n\n\nYou can optionally use an SFTP browser like Filezilla or Cyberduck for a GUI interface. Those using MobaXterm, it has an embedded SFTP file browser to drag and drop.\n\n\n Go back to the FastQC website and compare your report with the sample report for Good Illumina data and Bad Illumina data.\n Discuss based on your reports, whether your data is of good enough quality and/or what steps are needed to fix it.\n\n\n3.3 HISAT2\nMapping reads using HISAT2\nAfter verifying that the quality of the raw sequencing reads is acceptable, we will map the reads to the reference genome. There are many mappers/aligners available, so it may be good to choose one that is adequate for your type of data. Here, we will use a software called HISAT2 (Hierarchical Indexing for Spliced Alignment of Transcripts) as it is a good general purpose splice-aware aligner. It is fast and does not require a lot of RAM. Before we begin mapping, we need to obtain genome reference sequence (.fasta file) and build an aligner index. Due to time constraints, we will build an index only on chromosome 19.\n\n3.3.1 Get reference\nIt is best if the reference genome (.fasta) and annotation (.gtf) files come from the same source to avoid potential naming conventions problems. It is also good to check in the manual of the aligner you use for hints on what type of files are needed to do the mapping. We will not be using the annotation (.gtf) during mapping, but we will use it during quantification.\n What is the idea behind building an aligner index? What files are needed to build one? Where do we take them from? Could one use an index that was generated for another project? Check out the HISAT2 manual indexer section for answers. Browse through Ensembl and try to find the files needed. Note that we are working with Mouse (Mus musculus).\n Move into the reference directory and download the Chr 19 genome (.fasta) file and the genome-wide annotation file (.gtf) from Ensembl.\nYou should be standing here to run this:\n\n\n/proj/naiss2023-22-862/nobackup/username/rnaseq/reference\n\n\nYou are most likely to use the latest version of ensembl release genome and annotations when starting a new analysis. For this exercise, we will choose ensembl version 99.\n\nwget ftp://ftp.ensembl.org/pub/release-99/fasta/mus_musculus/dna/Mus_musculus.GRCm38.dna.chromosome.19.fa.gz\nwget ftp://ftp.ensembl.org/pub/release-99/gtf/mus_musculus/Mus_musculus.GRCm38.99.gtf.gz\n\nDecompress the files for use.\n\ngunzip Mus_musculus.GRCm38.dna.chromosome.19.fa.gz\ngunzip Mus_musculus.GRCm38.99.gtf.gz\n\nFrom the full gtf file, we will also extract chr 19 alone to create a new gtf file for use later.\n\ncat Mus_musculus.GRCm38.99.gtf | grep -E \"^#|^19\" > Mus_musculus.GRCm38.99-19.gtf\n\n The grep command is set to use regular expression with the -E argument. And it’s looking for lines starting with # or 19. # fetches the header and comments while 19 denotes all rows with annotations for chromosome 19.\nCheck what you have in your directory.\n\nls -l\n\n\ndrwxrwsr-x 2 user gXXXXXXX 4.0K Jan 22 21:59 mouse_chr19_hisat2\n-rw-rw-r-- 1 user gXXXXXXX 26M Jan 22 22:46 Mus_musculus.GRCm38.99-19.gtf\n-rw-rw-r-- 1 user gXXXXXXX 771M Jan 22 22:10 Mus_musculus.GRCm38.99.gtf\n-rw-rw-r-- 1 user gXXXXXXX 60M Jan 22 22:10 Mus_musculus.GRCm38.dna.chromosome.19.fa\n\n\n\n3.3.2 Build index\nMove into the reference directory if not already there. Load module HISAT2. Remember to load bioinfo-tools if you haven’t done so already.\n\nmodule load bioinfo-tools\nmodule load HISAT2/2.1.0\n\n To search for the tool or other versions of a tool, use module spider hisat.\nCreate a new bash script in your scripts directory named hisat2_index.sh and add the following lines:\n\n#!/bin/bash\n\n# load module\nmodule load bioinfo-tools\nmodule load HISAT2/2.1.0\n\nhisat2-build \\\n -p 1 \\\n Mus_musculus.GRCm38.dna.chromosome.19.fa \\\n mouse_chr19_hisat2/mouse_chr19_hisat2\n\nThe above script builds a HISAT2 index using the command hisat2-build. It should use 1 core for computation. The paths to the FASTA (.fa) genome file is specified. And the output path is specified. The output describes the output directory and the prefix for output files. The output directory must be present before running this script. Check hisat2-build --help for the arguments and descriptions.\nUse pwd to check if you are standing in the correct directory. Then, run the script from the reference directory.\n\nbash ../scripts/hisat2_index.sh\n\nOnce the indexing is complete, move into the mouse_chr19_hisat2 directory and make sure you have all the files.\n\nls -l mouse_chr19_hisat2/\n\n\n-rw-rw-r-- 1 user gXXXXXXX 23M Sep 19 12:30 mouse_chr19_hisat2.1.ht2\n-rw-rw-r-- 1 user gXXXXXXX 14M Sep 19 12:30 mouse_chr19_hisat2.2.ht2\n-rw-rw-r-- 1 user gXXXXXXX 53 Sep 19 12:29 mouse_chr19_hisat2.3.ht2\n-rw-rw-r-- 1 user gXXXXXXX 14M Sep 19 12:29 mouse_chr19_hisat2.4.ht2\n-rw-rw-r-- 1 user gXXXXXXX 25M Sep 19 12:30 mouse_chr19_hisat2.5.ht2\n-rw-rw-r-- 1 user gXXXXXXX 15M Sep 19 12:30 mouse_chr19_hisat2.6.ht2\n-rw-rw-r-- 1 user gXXXXXXX 12 Sep 19 12:29 mouse_chr19_hisat2.7.ht2\n-rw-rw-r-- 1 user gXXXXXXX 8 Sep 19 12:29 mouse_chr19_hisat2.8.ht2\n\nThe index for the whole genome would be created in a similar manner. It just requires more time to run.\n\n\n3.3.3 Map reads\nNow that we have the index ready, we are ready to map reads. Move to the directory 3_mapping. Use pwd to check if you are standing in the correct directory.\nYou should be standing here to run this:\n\n\n/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping\n\n\nWe will create softlinks to the fastq files from here to make things easier.\n\ncd 3_mapping\nln -s ../1_raw/* .\n\nThese are the parameters that we want to specify for the mapping run:\n\nSpecify the number of threads\nSpecify the full genome index path\nSpecify a summary file\nIndicate read1 and read2 since we have paired-end reads\nDirect the output (SAM) to a file\n\nHISAT2 aligner arguments can be obtained by running hisat2 --help. We should end with a script that looks like below to run one of the samples.\n\nhisat2 \\\n -p 1 \\\n -x ../reference/mouse_chr19_hisat2/mouse_chr19_hisat2 \\\n --summary-file \"SRR3222409-19.summary\" \\\n -1 SRR3222409-19_1.fq.gz \\\n -2 SRR3222409-19_2.fq.gz \\\n -S SRR3222409-19.sam\n\nLet’s break this down a bit. -p options denotes that it will use 1 thread. In a real world scenario, we might want to use 8 to 12 threads. -x denotes the full path (with prefix) to the aligner index we built in the previous step. --summary-file specifies a summary file to write alignments metrics such as mapping rate etc. -1 and -2 specifies the input fastq files. Both are used here because this is a paired-end sequencing. -S denotes the output SAM file.\nBut, we will not run it as above. We will make some more changes to it. We want to make the following changes:\n\nRather than writing the output as a SAM file, we want to direct the output to another tool samtools to order alignments by coordinate and to export in BAM format\nGeneralise the above script to be used as a bash script to read any two input files and to automatically create the output filename.\n\n Now create a new bash script file named hisat2_align.sh in your scripts directory and add the script below to it.\n\n#!/bin/bash\n\nmodule load bioinfo-tools\nmodule load HISAT2/2.1.0\nmodule load samtools/1.8\n\n# get output filename prefix\nprefix=$( basename $1 | sed -E 's/_.+$//' )\n\nhisat2 \\\n -p 1 \\\n -x ../reference/mouse_chr19_hisat2/mouse_chr19_hisat2 \\\n --summary-file \"${prefix}.summary\" \\\n -1 $1 \\\n -2 $2 | samtools sort -O BAM > \"${prefix}.bam\"\n\nIn the above script, the two input fasta files are not hard coded, rather we use $1 and $2 because they will be passed in as arguments.\nThe output filename prefix is automatically created using this line prefix=$( basename $1 | sed -E 's/_.+$//' ) from input filename of $1. For example, a file with path /bla/bla/sample_1.fq.gz will have the directory stripped off using the function basename to get sample_1.fq.gz. This is piped (|) to sed where all text starting from _ to end of string (specified by this regular expression _.+$ matching _1.fq.gz) is removed and the prefix will be just sample. This approach will work only if your filenames are labelled suitably.\nLastly, the SAM output is piped (|) to the tool samtools for sorting and written in BAM format.\nNow we can run the bash script like below while standing in the 3_mapping directory.\n\nbash ../scripts/hisat2_align.sh sample_1.fq.gz sample_2.fq.gz\n\n Similarly run the other samples.\n\n\n\n\n\n\nOptional\n\n\n\nTry to create a new bash loop script (hisat2_align_batch.sh) to iterate over all fastq files in the directory and run the mapping using the hisat2_align.sh script. Note that there is a bit of a tricky issue here. You need to use two fastq files (_1 and _2) per run rather than one file. There are many ways to do this and here is one.\n\n## find only files for read 1 and extract the sample name\nlines=$(find *_1.fq.gz | sed \"s/_1.fq.gz//\")\n\nfor i in ${lines}\ndo\n ## use the sample name and add suffix (_1.fq.gz or _2.fq.gz)\n echo \"Mapping ${i}_1.fq.gz and ${i}_2.fq.gz ...\"\n bash ../scripts/hisat2_align.sh ${i}_1.fq.gz ${i}_2.fq.gz\ndone\n\nRun the hisat2_align_batch.sh script in the 3_mapping directory.\n\nbash ../scripts/hisat2_align_batch.sh\n\n\n\nAt the end of the mapping jobs, you should have the following list of output files for every sample:\n\nls -l\n\n\n-rw-rw-r-- 1 user gXXXXXXX 16M Sep 19 12:30 SRR3222409-19.bam\n-rw-rw-r-- 1 user gXXXXXXX 604 Sep 19 12:30 SRR3222409-19.summary\n\nThe .bam file contains the alignment of all reads to the reference genome in binary format. BAM files are not human readable directly. To view a BAM file in text format, you can use samtools view functionality.\n\nmodule load samtools/1.8\nsamtools view SRR3222409-19.bam | head\n\n\nSRR3222409.13658290 163 19 3084385 60 95M3S = 3084404 120 CTTTAAGATAAGTGCCGGTTGCAGCCAGCTGTGAGAGCTGCACTCCCTTCTCTGCTCTAAAGTTCCCTCTTCTCAGAAGGTGGCACCACCCTGAGCTG DB@D@GCHHHEFHIIG<CHHHIHHIIIIHHHIIIIGHIIIIIFHIGHIHIHIIHIIHIHIIHHHHIIIIIIHFFHHIIIGCCCHHHH1GHHIIHHIII AS:i:-3 ZS:i:-18 XN:i:0 XM:i:0 XO:i:0 XG:i:0 NM:i:0 MD:Z:95 YS:i:-6 YT:Z:CP NH:i:1\nSRR3222409.13658290 83 19 3084404 60 101M = 3084385 -120 TGCAGCCAGCTGTGAGAGCTGCACTCCCTTCTCTGCTCTAAAGTTCCCTCTTCTCAGAAGGTGGCACCACCCTGAGCTGCTGGCAGTGAGTCTGTTCCAAG IIIIHECHHH?IHHHIIIHIHIIIHEHHHCHHHIHIIIHHIHIIIHHHHHHIHEHIIHIIHHIIHHIHHIGHIGIIIIIIIHHIIIHHIHEHCHHG@<<BD AS:i:-6 ZS:i:-16 XN:i:0 XM:i:1 XO:i:0 XG:i:0 NM:i:1 MD:Z:76T24 YS:i:-3 YT:Z:CP NH:i:1\nSRR3222409.13741570 163 19 3085066 60 15M2I84M = 3085166 201 ATAGTACCTGGCAACAAAAAAAAAAAAGCTTTTGGCTAAAGACCAATGTGTTTAAGAGATAAAAAAAGGGGTGCTAATACAGAAGCTGAGGCCTTAGAAGA 0B@DB@HCCH1<<CGECCCGCHHIDD?01<<G1</<1<FH1F11<1111<<<<11<CGC1<G1<F//DHHI0/01<<1FG11111111<111<1D1<1D1< AS:i:-20 XN:i:0 XM:i:3 XO:i:1 XG:i:2 NM:i:5 MD:Z:40T19C27T10 YS:i:0 YT:Z:CP NH:i:1\n\n Can you identify what some of these columns are? SAM format description is available here. SAM output specifically from HISAT is described here, especially the tags.\n The summary file gives a summary of the mapping run. This file is used by MultiQC later to collect mapping statistics. Inspect one of the mapping log files to identify the number of uniquely mapped reads and multi-mapped reads.\n\ncat SRR3222409-19.summary\n\n\n156992 reads; of these:\n 156992 (100.00%) were paired; of these:\n 7984 (5.09%) aligned concordantly 0 times\n 147178 (93.75%) aligned concordantly exactly 1 time\n 1830 (1.17%) aligned concordantly >1 times\n ----\n 7984 pairs aligned concordantly 0 times; of these:\n 690 (8.64%) aligned discordantly 1 time\n ----\n 7294 pairs aligned 0 times concordantly or discordantly; of these:\n 14588 mates make up the pairs; of these:\n 5987 (41.04%) aligned 0 times\n 4085 (28.00%) aligned exactly 1 time\n 4516 (30.96%) aligned >1 times\n98.09% overall alignment rate\n\nNext, we need to index these BAM files. Indexing creates .bam.bai files which are required by many downstream programs to quickly and efficiently locate reads anywhere in the BAM file.\n Index all BAM files. Write a for-loop to index all BAM files using the command samtools index file.bam.\n\nmodule load samtools/1.8\n\nfor i in *.bam\n do\n echo \"Indexing $i ...\"\n samtools index $i\n done\n\nNow, we should have .bai index files for all BAM files.\n\nls -l\n\n\n-rw-rw-r-- 1 user gXXXXXXX 16M Sep 19 12:30 SRR3222409-19.bam\n-rw-rw-r-- 1 user gXXXXXXX 43K Sep 19 12:32 SRR3222409-19.bam.bai\n\n If you are running short of time or unable to run the mapping, you can copy over results for all samples that have been prepared for you before class. They are available at this location: /sw/courses/ngsintro/rnaseq/main/3_mapping/.\n\n\ncp -r /sw/courses/ngsintro/rnaseq/main/3_mapping/* /proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/\n\n\n\n\n\n\n3.4 QualiMap\nPost-alignment QC using QualiMap\nSome important quality aspects, such as saturation of sequencing depth, read distribution between different genomic features or coverage uniformity along transcripts, can be measured only after mapping reads to the reference genome. One of the tools to perform this post-alignment quality control is QualiMap. QualiMap examines sequencing alignment data in SAM/BAM files according to the features of the mapped reads and provides an overall view of the data that helps to the detect biases in the sequencing and/or mapping of the data and eases decision-making for further analysis.\nThere are other tools with similar functionality such as RNASeqQC or QoRTs.\n Read through QualiMap documentation and see if you can figure it out how to run it to assess post-alignment quality on the RNA-seq mapped samples.\n Load the QualiMap module version 2.2.1 and create a bash script named qualimap.sh in your scripts directory.\nAdd the following script to it. Note that we are using the smaller GTF file with chr19 only.\n\n#!/bin/bash\n\n# load modules\nmodule load bioinfo-tools\nmodule load QualiMap/2.2.1\n\n# get output filename prefix\nprefix=$( basename \"$1\" .bam)\n\nunset DISPLAY\n\nqualimap rnaseq -pe \\\n -bam $1 \\\n -gtf \"../reference/Mus_musculus.GRCm38.99-19.gtf\" \\\n -outdir \"../4_qualimap/${prefix}/\" \\\n -outfile \"$prefix\" \\\n -outformat \"HTML\" \\\n --java-mem-size=6G >& \"${prefix}-qualimap.log\"\n\nThe line prefix=$( basename \"$1\" .bam) is used to remove directory path and .bam from the input filename and create a prefix which will be used to label output. The export unset DISPLAY forces a ‘headless mode’ on the JAVA application, which would otherwise throw an error about X11 display. If that doesn’t work, one can also try export DISPLAY=:0 or export DISPLAY=\"\". The last part >& \"${prefix}-qualimap.log\" saves the standard-out as a log file.\n Create a new bash loop script named qualimap_batch.sh with a bash loop to run the qualimap script over all BAM files. The loop should look like below.\n\nfor i in ../3_mapping/*.bam\ndo\n echo \"Running QualiMap on $i ...\"\n bash ../scripts/qualimap.sh $i\ndone\n\nRun the loop script qualimap_batch.sh in the directory 4_qualimap.\n\nbash ../scripts/qualimap_batch.sh\n\nQualimap should have created a directory for every BAM file.\n\ndrwxrwsr-x 5 user gXXXXXXX 4.0K Jan 22 22:53 SRR3222409-19\n-rw-rw-r-- 1 user gXXXXXXX 669 Jan 22 22:53 SRR3222409-19-qualimap.log\n\nInside every directory, you should see:\n\nls -l\n\n\ndrwxrwsr-x 2 user gXXXXXXX 4.0K Jan 22 22:53 css\ndrwxrwsr-x 2 user gXXXXXXX 4.0K Jan 22 22:53 images_qualimapReport\n-rw-rw-r-- 1 user gXXXXXXX 12K Jan 22 22:53 qualimapReport.html\ndrwxrwsr-x 2 user gXXXXXXX 4.0K Jan 22 22:53 raw_data_qualimapReport\n-rw-rw-r-- 1 user gXXXXXXX 1.2K Jan 22 22:53 rnaseq_qc_results.txt\n\n Download the results.\n When downloading the HTML files, note that you MUST also download the dependency files (ie; css folder and images_qualimapReport folder), otherwise the HTML file may not render correctly. Remember to replace username (twice).\n\n\nscp -r username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/4_qualimap .\n\n\n Check the QualiMap report for one sample and discuss if the sample is of good quality. You only need to do this for one file now. We will do a comparison with all samples when using the MultiQC tool.\n If you are running out of time or were unable to run QualiMap, you can also copy pre-run QualiMap output from this location: /sw/courses/ngsintro/rnaseq/main/4_qualimap/.\n\n\ncp -r /sw/courses/ngsintro/rnaseq/main/4_qualimap/* /proj/naiss2023-22-862/nobackup/username/rnaseq/4_qualimap/\n\n\n\n\n\n3.5 featureCounts\nCounting mapped reads using featureCounts\nAfter ensuring mapping quality, we can move on to enumerating reads mapping to genomic features of interest. Here we will use featureCounts, an ultrafast and accurate read summarisation program, that can count mapped reads for genomic features such as genes, exons, promoter, gene bodies, genomic bins and chromosomal locations.\n Read featureCounts documentation and see if you can figure it out how to use paired-end reads using an unstranded library to count fragments overlapping with exonic regions and summarise over genes.\n Load the subread module on Uppmax. Create a bash script named featurecounts.sh in the directory scripts.\nWe could run featureCounts on each BAM file, produce a text output for each sample and combine the output. But the easier way is to provide a list of all BAM files and featureCounts will combine counts for all samples into one text file.\nBelow is the script that we will use:\n\n#!/bin/bash\n\n# load modules\nmodule load bioinfo-tools\nmodule load subread/2.0.0\n\nfeatureCounts \\\n -a \"../reference/Mus_musculus.GRCm38.99.gtf\" \\\n -o \"counts.txt\" \\\n -F \"GTF\" \\\n -t \"exon\" \\\n -g \"gene_id\" \\\n -p \\\n -s 0 \\\n -T 1 \\\n ../3_mapping/*.bam\n\nIn the above script, we indicate the path of the annotation file (-a \"../reference/Mus_musculus.GRCm38.99.gtf\"), specify the output file name (-o \"counts.txt\"), specify that that annotation file is in GTF format (-F \"GTF\"), specify that reads are to be counted over exonic features (-t \"exon\") and summarised to the gene level (-g \"gene_id\"). We also specify that the reads are paired-end (-p), the library is unstranded (-s 0) and the number of threads to use (-T 1).\nRun the featurecounts bash script in the directory 5_dge. Use pwd to check if you are standing in the correct directory.\nYou should be standing here to run this:\n\n\n/proj/naiss2023-22-862/nobackup/username/rnaseq/5_dge\n\n\n\nbash ../scripts/featurecounts.sh\n\nYou should have two output files:\n\nls -l\n\n\n-rw-rw-r-- 1 user gXXXXXXX 2.8M Sep 15 11:05 counts.txt\n-rw-rw-r-- 1 user gXXXXXXX 658 Sep 15 11:05 counts.txt.summary\n\n Inspect the files and try to make sense of them.\n\n\n\n\n\n\nImportant\n\n\n\nFor downstream steps, we will NOT use this counts.txt file. Instead we will use counts_full.txt from the back-up folder. This contains counts across all chromosomes. This is located here: /sw/courses/ngsintro/rnaseq/main/5_dge/. Copy this file to your 5_dge directory.\n Remember to replace username.\n\n\ncp /sw/courses/ngsintro/rnaseq/main/5_dge/counts_full.txt /proj/naiss2023-22-862/nobackup/username/rnaseq/5_dge/\n\n\n\n\n\n\n\n3.6 MultiQC\nCombined QC report using MultiQC\nWe will use the tool MultiQC to crawl through the output, log files etc from FastQC, HISAT2, QualiMap and featureCounts to create a combined QC report.\nMove to the 6_multiqc directory. You should be standing here to run this:\n\n\n/proj/naiss2023-22-862/nobackup/username/rnaseq/6_multiqc\n\n\nAnd run this in the terminal.\n\nmodule load bioinfo-tools\nmodule load MultiQC/1.11\n\nmultiqc --interactive ../\n\n\n /// MultiQC 🔍 | v1.11\n\n| multiqc | Search path : /crex/proj/XXXXXXX/nobackup/username/rnaseq\n| searching | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 298/298 \n| qualimap | Found 6 RNASeq reports\n| feature_counts | Found 6 reports\n| bowtie2 | Found 6 reports\n| fastqc | Found 12 reports\n| multiqc | Compressing plot data\n| multiqc | Report : multiqc_report.html\n| multiqc | Data : multiqc_data\n| multiqc | MultiQC complete\n\nThe output should look like below:\n\nls -l\n\n\ndrwxrwsr-x 2 user gXXXXXXX 4.0K Sep 6 22:33 multiqc_data\n-rw-rw-r-- 1 user gXXXXXXX 1.3M Sep 6 22:33 multiqc_report.html\n\n Download the MultiQC HTML report to your computer and inspect the report.\n Run this step in a LOCAL terminal and NOT on Uppmax. Remember to replace username (twice).\n\n\nscp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/6_multiqc/multiqc_report.html .\n\n\n\n\n\n3.7 DESeq2\nDifferential gene expression using DESeq2\nThe easiest way to perform differential expression is to use one of the statistical packages, within R environment, that were specifically designed for analyses of read counts arising from RNA-seq, SAGE and similar technologies. Here, we will use one such package called DESeq2. Learning R is beyond the scope of this course so we prepared basic ready to run R scripts to find DE genes between conditions KO and Wt.\nMove to the 5_dge directory and load R modules for use.\n\nmodule load R/4.0.0\nmodule load R_packages/4.0.0\n\nUse pwd to check if you are standing in the correct directory. Copy the following file to the 5_dge directory: /sw/courses/ngsintro/rnaseq/main/5_dge/dge.R\nMake sure you have the counts_full.txt. If not, you can copy this file too: /sw/courses/ngsintro/rnaseq/main/5_dge/counts_full.txt\n\n\ncp /sw/courses/ngsintro/rnaseq/main/5_dge/dge.R .\ncp /sw/courses/ngsintro/rnaseq/main/5_dge/counts_full.txt .\n\n\nNow, run the R script from the schell in 5_dge directory.\n\nRscript dge.R\n\nIf you are curious what’s inside dge.R, you are welcome to explore it using a text editor.\nThis should have produced the following output files:\n\nls -l\n\n\n-rw-rw-r-- 1 user gXXXXXXX 282K Jan 22 23:16 counts_vst_full.Rds\n-rw-rw-r-- 1 user gXXXXXXX 1.7M Jan 22 23:16 counts_vst_full.txt\n-rw-rw-r-- 1 user gXXXXXXX 727K Jan 22 23:16 dge_results_full.Rds\n-rw-rw-r-- 1 user gXXXXXXX 1.7M Jan 22 23:16 dge_results_full.txt\n\nEssentially, we have two outputs: dge_results_full and counts_vst_full. dge_results_full is the list of differentially expressed genes. This is available in human readable tab-delimited .txt file and R readable binary .Rds file. The counts_vst_full is variance-stabilised normalised counts, useful for exploratory analyses.\n Copy the results text file (dge_results_full.txt) to your computer and inspect the results. What are the columns? How many differentially expressed genes are present after adjusted p-value of 0.05? How many genes are upregulated and how many are down-regulated? How does this change if we set a fold-change cut-off of 1?\n Open in a spreadsheet editor like Microsoft Excel or LibreOffice Calc.\n If you do not have the results or were unable to run the DGE step, you can copy these two here which will be required for functional annotation (optional).\n\n\ncp /sw/courses/ngsintro/rnaseq/main/5_dge/dge_results_full.txt .\ncp /sw/courses/ngsintro/rnaseq/main/5_dge/dge_results_full.Rds .\ncp /sw/courses/ngsintro/rnaseq/main/5_dge/counts_vst_full.txt .\ncp /sw/courses/ngsintro/rnaseq/main/5_dge/counts_vst_full.Rds ." + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html#bonus-exercises", + "href": "topics/rnaseq/lab_rnaseq.html#bonus-exercises", + "title": "RNASeq Workflow", + "section": "4 Bonus exercises", + "text": "4 Bonus exercises\n\n\n\n\n\n\nOptional\n\n\n\nThese exercises are optional and to be run only if you have time and you want to explore this topic further.\n\n\n\n4.1 Functional annotation\nIn this part of the exercise we will address the question which biological processes are affected in the experiment; in other words we will functionally annotate the results of the analysis of differential gene expression (performed in the main part of the exercise). We will use Gene Ontology (GO) and Reactome databases.\nWhen performing this type of analysis, one has to keep in mind that the analysis is only as accurate as the annotation available for your organism. So, if working with non-model organisms which do have experimentally-validated annotations (computationally inferred), the results may not be fully reflecting the actual situation.\nThere are many methods to approach the question as to which biological processes and pathways are over-represented amongst the differentially expressed genes, compared to all the genes included in the DE analysis. They use several types of statistical tests (e.g. hypergeometric test, Fisher’s exact test etc.), and many have been developed with microarray data in mind. Not all of these methods are appropriate for RNA-seq data, which as you remember from the lecture, exhibit length bias in power of detection of differentially expressed genes (i.e. longer genes, which tend to gather more reads, are more likely to be detected as differentially expressed than shorter genes, solely because of the length).\nWe will use the R / Bioconductor package goseq, specifically designed to work with RNA-seq data. This package provides methods for performing Gene Ontology and pathway analysis of RNA-seq data, taking length bias into account.\nIn this part, we will use the same data as in the main workflow. The starting point of the exercise is the file with results of the differential expression produced in the main part of the exercise.\n\n4.1.1 Preparation\nChange to the funannot directory in your rnaseq directory.\n\ncd funannot\n\nCopy this file /sw/courses/ngsintro/rnaseq/bonus/funannot/annotate_de_results.R to your rnaseq/funannot directory.\n Remember to replace username.\n\n\ncp /sw/courses/ngsintro/rnaseq/bonus/funannot/annotate_de_results.R /proj/naiss2023-22-862/nobackup/username/rnaseq/funannot/\n\n\nWe need some annotation information, so we will copy this file /sw/courses/ngsintro/rnaseq/main/reference/mm-biomart99-genes.txt.gz to your rnaseq/reference directory.\n\n\ncp /sw/courses/ngsintro/rnaseq/main/reference/mm-biomart99-genes.txt.gz /proj/naiss2023-22-862/nobackup/username/rnaseq/reference/\n\n\nThen uncompress the file. gunzip ../reference/mm-biomart99-genes.txt.gz\nLoad R module and R packages\n\nmodule load R/4.0.0\nmodule load R_packages/4.0.0\n\nRun the functional annotation script from the linux terminal.\n\nRscript annotate_de_results.R\n\nIt will fetch dge_results_full.Rds from 5_dge/ and annotation files from reference/. When completed, you should find a directory named funannot_results.\n\nls -l\n\n\n-rw-rw-r-- 1 user gXXXXXXX 44K Jan 22 23:37 go_down.txt\n-rw-rw-r-- 1 user gXXXXXXX 15K Jan 22 23:37 go_up.txt\n-rw-rw-r-- 1 user gXXXXXXX 800 Jan 22 23:37 reactome_down.txt\n-rw-rw-r-- 1 user gXXXXXXX 794 Jan 22 23:37 reactome_up.txt\n\n\n\n4.1.2 Interpretation\nThe results are saved as tables in the directory funannot_results. There are four tables: GO terms for up-regulated genes (go_up.txt), GO terms for down-regulated genes (go_down.txt) and similarily, Reactome pathways for up-regulated genes (reactome_up.txt) and Reactome pathways for down-regulated genes (reactome_down.txt).\n Take a quick look at some of these files.\n\nhead go_down.txt\n\nThe columns of the results tables are:\n\n# go\ncategory over_represented_pvalue under_represented_pvalue numDEInCat numInCat term ontology\n# reactome\ncategory over_represented_pvalue under_represented_pvalue numDEInCat numInCat path_name\n\nYou can view the tables in a text editor (nano,gedit etc), and try to find GO terms and pathways relevant to the experiment using a word search functionality. You could download these files to your computer and import them into a spreadsheet program like MS Excel or LibreOffice Calc.\n Try to use grep to find a match using a keyword, say phosphorylation.\n\ncat go_down.txt | grep \"phosphorylation\"\n\n Have a look at the GO terms and see if you think the functional annotation reflects the biology of the experiments we have just analysed?\n\n\n\n4.2 RNA-Seq plots\nCreating high quality plots of RNA-seq analysis are most easily done using R. Depending on your proficiency in reading R code and using R, you can in this section either just call scripts from the command lines with a set of arguments or you can open the R script in a text editor, and run the code step by step from an interactive R session.\nCopy the R script files from the following directory: /sw/courses/ngsintro/rnaseq/bonus/plots/ to your plots directory.\n Remember to replace username.\n\n\ncp /sw/courses/ngsintro/rnaseq/bonus/plots/*.R /proj/naiss2023-22-862/nobackup/username/rnaseq/plots/\n\n\nYou should have the following files:\n\nls -l\n\n\n-rw-rw-r-- 1 user gXXXXXXX 2.0K Sep 20 2016 gene.R\n-rw-rw-r-- 1 user gXXXXXXX 842 Sep 22 2016 heatmap.R\n-rw-rw-r-- 1 user gXXXXXXX 282 Sep 22 2016 ma.R\n-rw-rw-r-- 1 user gXXXXXXX 340 Sep 22 2016 pca.R\n-rw-rw-r-- 1 user gXXXXXXX 669 Sep 22 2016 volcano.R\n\nIt is important that you load module R and R_packages.\n\nmodule load R/4.0.0\nmodule load R_packages/4.0.0\n\n\n4.2.1 PCA plot\nA popular way to visualise general patterns of gene expression in your data is to produce either PCA (Principal Component Analysis) or MDS (Multi Dimensional Scaling) plots. These methods aim at summarising the main patterns of expression in the data and display them on a two-dimensional space and still retain as much information as possible. To properly evaluate these kind of results is non-trivial, but in the case of RNA-seq data we often use them to get an idea of the difference in expression between treatments and also to get an idea of the similarity among replicates. If the plots shows clear clusters of samples that corresponds to treatment it is an indication of treatment actually having an effect on gene expression. If the distance between replicates from a single treatment is very large it suggests large variance within the treatment, something that will influence the detection of differentially expressed genes between treatments.\nMove to the plots/ directory. Then run the pca.R script like below.\n\nRscript pca.R\n\nThis generates a file named pca.png in the plots folder. To view it, use eog pca.png & or copy it to your local disk.\n\n\n\n\n\n\n\n\n\n Do samples cluster as expected? Are there any odd or mislabelled samples? Based on these results, would you expect to find a large number of significant DE genes?\n\n\n4.2.2 MA plot\nAn MA-plot plots the mean expression and estimated log-fold-change for all genes in an analysis.\nRun the ma.R script in the plots directory.\n\nRscript ma.R\n\nThis generates a file named ma.png in the plots folder. To view it, use eog ma.png & or copy it to your local disk.\n\n\n\n\n\n\n\n\n\n What do you think the blue dots represent?\n\n\n4.2.3 Volcano plot\nA related type of figure will instead plot fold change (on log2 scale) on the x-axis and -log10 p-value on the y-axis. Scaling like this means that genes with lowest p-value will be found at the top of the plot. In this example we will highlight (in blue) the genes that are significant (p-val 0.05 after correction for multiple testing).\nRun the script named volcano.R in the plots directory.\n\nRscript volcano.R\n\nThis generates a file named volcano.png in the plots folder. To view it, use eog volcano.png & or copy it to your local disk.\n\n\n\n\n\n\n\n\n\n Anything noteworthy about the patterns in the plot? Is there a general trend in the direction of change in gene expression as a consequence of the experiment?\n\n\n4.2.4 Heatmap\nAnother popular plots for genome-wide expression patterns is heatmap for a set of genes. If you run the script called heatmap.R, it will extract the top 50 genes that have the lowest p-value in the experiment and create a heatmap from these. In addition to color-coding the expression levels over samples for the genes it also clusters the samples and genes based on inferred distance between them.\nRun the script named heatmap.R in the plots directory.\n\nRscript heatmap.R\n\nThis generates a file named heatmap.png in the plots folder. To view it, use eog heatmap.png & or copy it to your local disk.\n\n\n\n\n\n\n\n\n\n Compare this plot to a similar plot in the paper behind the data.\n\n\n\n4.3 IGV browser\nData visualisation is important to be able to clearly convey results, but can also be very helpful as tool for identifying issues and note-worthy patterns in the data. In this part you will use the BAM files you created earlier in the RNA-seq lab and use IGV (Integrated Genomic Viewer) to visualise the mapped reads and genome annotations. In addition we will produce high quality plots of both the mapped read data and the results from differential gene expression.\nIf you are already familiar with IGV you can load the mouse genome and at least one BAM file from each of the treatments that you created earlier. The functionality of IGV is the same as if you look at genomic data, but there are a few of the features that are more interesting to use for RNA-seq data.\nIntegrated genomics viewer from Broad Institute is a nice graphical interface to view bam files and genome annotations. It also has tools to export data and some functionality to look at splicing patterns in RNA-seq data sets. Even though it allows for some basic types of analysis it should be used more as a nice way to look at your mapped data. Looking at data in this way might seem like a daunting approach as you can not check more than a few regions, but in in many cases it can reveal mapping patterns that are hard to catch with just summary statistics.\nFor this tutorial you can chose to run IGV directly on your own computer or on Uppmax . If you chose to run it on your own computer you will have to download some of the BAM files (and the corresponding index files) from Uppmax. If you have not yet installed IGV you also have to download the program.\n\n\n\n\n\n\nLocal \n\n\n\nCopy two BAM files (one from each experimental group, for example; SRR3222409-19 and SRR3222412-19) and the associated index (.bam.bai) files to your computer by running the below command in a LOCAL terminal and NOT on Uppmax.\n Remember to replace username.\n\n\nscp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/SRR3222409-19.bam ./\nscp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/SRR3222409-19.bam.bai ./\nscp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/SRR3222412-19.bam ./\nscp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/SRR3222412-19.bam.bai ./\n\n\nAlternatively, you can use an SFTP browser like Filezilla or Cyberduck for a GUI interface. Windows users can also use the MobaXterm SFTP file browser to drag and drop.\n\n\n\n\n\n\n\n\nUppmax \n\n\n\nFor Linux and Mac users, Log in to Uppmax in a way so that the generated graphics are exported via the network to your screen. This will allow any graphical interface that you start on your compute node to be exported to your computer. However, as the graphics are exported over the network, it can be fairly slow in redrawing windows and the experience can be fairly poor.\nLogin in to Uppmax with X-forwarding enabled:\n\nssh -Y username@rackham.uppmax.uu.se\nssh -Y computenode\n\nAn alternative method is to login through Rackham-GUI. Once you log into this interface you will have a linux desktop interface in a browser window. This interface is running on the login node, so if you want to do any heavy lifting you need to login to your reserved compute node also here. This is done by opening a terminal in the running linux environment and log on to your compute node as before. NB! If you have no active reservation you have to do that first.\nLoad necessary modules and start IGV\n\nmodule load bioinfo-tools\nmodule load IGV/2.8.13\nigv-core\n\nThis should start the IGV so that it is visible on your screen. If not please try to reconnect to Uppmax or consider running IGV locally as that is often the fastest and most convenient solution.\n\n\nOnce we have the program running, you select the genome that you would like to load. Choose Mouse mm10. Note that if you are working with a genome that are not part of the available genomes in IGV, one can create genome files from within IGV. Please check the manual of IGV for more information on that.\nTo open your BAM files, go to File > Load from file... and select your BAM file and make sure that you have a .bai index for that BAM file in the same folder. You can repeat this and open multiple BAM files in the same window, which makes it easy to compare samples. Then select Chr19 since we only have data for that one chromosome.\nFor every file you open a number of panels are opened that visualise the data in different ways. The first panel named Coverage summarises the coverage of base-pairs in the window you have zoomed to. The second panel shows the reads as they are mapped to the genome. If one right click with the mouse on the read panel there many options to group and color reads. The bottom panel named Refseq genes shows the gene models from the annotation.\nTo see actual reads you have to zoom in until the reads are drawn on screen. If you have a gene of interest you can also use the search box to directly go to that gene.\nHere is the list of top 30 differentially expressed genes on Chr19 ordered by absolute fold change. The adjusted p value is shown as padj, the average expression of the gene is shown as baseMean.\n ensembl_gene_id external_gene_name baseMean log2FoldChange padj gene_biotype\n1 ENSMUSG00000117896 AA387883 59.94083 -2.7846887 1.943690e-17 lncRNA\n2 ENSMUSG00000024799 Tm7sf2 947.63388 -2.0385744 1.677171e-44 protein_coding\n3 ENSMUSG00000025172 Ankrd2 59.28633 1.7519899 1.261004e-08 protein_coding\n4 ENSMUSG00000049134 Nrap 220.59983 1.6993887 1.067822e-08 protein_coding\n5 ENSMUSG00000024935 Slc1a1 63.82987 1.6821634 1.652208e-09 protein_coding\n6 ENSMUSG00000037071 Scd1 6678.59981 -1.4473717 2.961722e-14 protein_coding\n7 ENSMUSG00000024665 Fads2 3269.79425 -1.4152150 3.134559e-29 protein_coding\n8 ENSMUSG00000024747 Aldh1a7 65.81205 -1.3544431 1.002599e-06 protein_coding\n9 ENSMUSG00000025216 Lbx1 26.03640 1.3356124 1.328372e-04 protein_coding\n10 ENSMUSG00000056290 Ms4a4b 23.27050 1.3299845 5.015617e-05 protein_coding\n11 ENSMUSG00000025221 Kcnip2 34.13675 -1.3165310 1.463369e-04 protein_coding\n12 ENSMUSG00000032648 Pygm 1129.47092 1.2452572 2.736196e-04 protein_coding\n13 ENSMUSG00000043639 Rbm20 51.36261 1.1816554 7.774718e-04 protein_coding\n14 ENSMUSG00000118032 Gm50147 39.53043 -1.1797580 3.794393e-04 lncRNA\n15 ENSMUSG00000036278 Macrod1 244.02353 1.0824415 4.984802e-07 protein_coding\n16 ENSMUSG00000025203 Scd2 44054.03491 -1.0504733 1.874759e-11 protein_coding\n17 ENSMUSG00000010663 Fads1 4074.38868 -1.0503935 1.470460e-18 protein_coding\n18 ENSMUSG00000060675 Plaat3 5284.36470 -1.0462725 2.114719e-13 protein_coding\n19 ENSMUSG00000016496 Cd274 35.91671 1.0175443 5.632932e-03 protein_coding\n20 ENSMUSG00000024673 Ms4a1 25.80723 1.0130356 6.294275e-03 protein_coding\n21 ENSMUSG00000032773 Chrm1 76.11444 0.9262597 7.665519e-04 protein_coding\n22 ENSMUSG00000067279 Ppp1r3c 162.14777 0.9018589 3.672613e-04 protein_coding\n23 ENSMUSG00000025013 Tll2 108.20333 -0.9012959 1.249858e-03 protein_coding\n24 ENSMUSG00000006457 Actn3 1322.01659 0.8988003 1.352229e-02 protein_coding\n25 ENSMUSG00000075289 Carns1 1003.91026 -0.8819988 4.982949e-10 protein_coding\n26 ENSMUSG00000075010 AW112010 56.94897 0.8128744 4.027595e-02 lncRNA\n27 ENSMUSG00000025227 Mfsd13a 107.55434 -0.8126676 1.107050e-03 protein_coding\n28 ENSMUSG00000067242 Lgi1 506.42577 -0.7842945 2.570293e-06 protein_coding\n29 ENSMUSG00000024812 Tjp2 1478.96029 -0.7627251 9.004722e-07 protein_coding\n30 ENSMUSG00000047368 Abhd17b 1562.07350 -0.7625545 5.750875e-07 protein_coding\nHave a look at few of the interesting genes on Chr19 using the external_gene_name identifier. Look into gene Tm7sf2 or Ankrd2. You might have to right-click and change option to Squished to see more reads.\n Do you expect these genes to be differentially expressed?\nTo see some genes with large number of reads, see Scd1 or Scd2.\n IGV view of gene Tm7sf2 across 6 samples.\n\n\n\n\n\nIGV view of gene Ankrd2 across 6 samples.\n\n\n\n\n\nIGV view of gene Scd1 across 6 samples.\nFor more detailed information on the splice reads you can instead of just looking at the splice panel right click on the read panel and select Sashimi plots. This will open a new window showing in an easy readable fashion how reads are spliced in mapping and you will also be able to see that there are differences in between what locations reads are spliced. This hence gives some indication on the isoform usage of the gene.\n Do you think the reads are from a stranded or unstranded library?\n One can visualise all genes in a given pathway using the gene list option under Regions in the menu. If you need hints for how to proceed, see Gene List tutorial at Broad. But, we only have data from one chromosome, so this is not that useful now." + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html#sbatch", + "href": "topics/rnaseq/lab_rnaseq.html#sbatch", + "title": "RNASeq Workflow", + "section": "5 sbatch", + "text": "5 sbatch\n\n\n\n\n\n\nNote\n\n\n\nYou are not required to run anything practically in this section. This is just to read and understand.\n\n\nWe have throughout this tutorial written bash scripts and run them from the terminal directly. Remember that we are not running on the login node. We have pre-allocated resources, then logged in to a compute node to run tasks. This is called working interactively on Uppmax. This is fine for tutorials and testing purposes. But, if you were to actually work on Uppmax, you would follow a slightly different approach.\nThe standard workflow on Uppmax is to login to the login node and then submit tasks as jobs to something called a Slurm queue. We haven’t used this option, because it involves waiting for an unpredictable amount of time for your submitted job to execute. In this section, we will take a look at how to modify a standard bash script to work with Slurm job submission.\nThis is how our standard bash script for mapping looks like:\n\n#!/bin/bash\n\n# load modules\nmodule load bioinfo-tools\nmodule load HISAT2/2.1.0\nmodule load samtools/1.8\n\n# create output filename prefix\nprefix=$( basename \"$1\" | sed -E 's/_.+$//' )\n\nhisat2 \\\n-p 8 \\\n-x ../reference/mouse_chr19_hisat2/mouse_chr19_hisat2 \\\n--summary-file \"${prefix}.summary\" \\\n-1 $1 \\\n-2 $2 | samtools sort -O BAM > \"${prefix}.bam\"\n\nWe add SBATCH commands to the above script. The new script looks like this:\n\n\n#!/bin/bash\n#SBATCH -A naiss2023-22-862\n#SBATCH -p core\n#SBATCH -n 8\n#SBATCH -t 3:00:00\n#SBATCH -J hisat2-align\n\n# load modules\nmodule load bioinfo-tools\nmodule load HISAT2/2.1.0\nmodule load samtools/1.8\n\n# create output filename prefix\nprefix=$( basename \"$1\" | sed -E \"s/_.+$//\" )\n\nhisat2 \\\n -p 8 \\\n -x ../reference/mouse_chr19_hisat2/mouse_chr19_hisat2 \\\n --summary-file \"${prefix}-summary.txt\" \\\n -1 $1 \\\n -2 $2 | samtools sort -O BAM > \"${prefix}.bam\"\n\n\nThe SBATCH commands in the above script is specifying the account name to use resources from, the required number of cores, the time required for the job and a job name.\n If you run this as a normal bash script like this ./hisat2_align.sh ... or bash ./hisat2_align.sh ..., the SBATCH comments have no effect (they are treated as comments) and the contents of the script will immediately start executing. But if you run this as script as sbatch ./hisat2_align.sh ..., the script is submitted as a job to the Uppmax Slurm queue. In this case, the SBATCH lines are interpreted and used by Slurm. At some point, your submitted job will reach the top of the queue and then the script will start to be executed.\nYou can check your jobs in the queue by running the following command.\n\njobinfo -u user\n\nAnd this gives a list like this:\n\nCLUSTER: rackham\nRunning jobs:\n JOBID PARTITION NAME USER ACCOUNT ST START_TIME TIME_LEFT NODES CPUS NODELIST(REASON)\n 5006225 core (null) user gXXXXXXX R 2018-09-12T14:00:03 44:31 1 1 r169\n 5006229 core (null) user gXXXXXXX R 2018-09-12T14:00:03 44:31 1 1 r169\n 5006352 core (null) user gXXXXXXX R 2018-09-12T14:04:14 48:42 1 1 r178\n 5006355 core (null) user gXXXXXXX R 2018-09-12T14:05:17 49:45 1 1 r169\n 5006356 core (null) user gXXXXXXX R 2018-09-12T14:06:08 50:36 1 5 r179\n\nIf the job is pending, then you will see PD in the ST column. If your job is running, you should see R. Once your job starts running, you will see a file named slurm-XXXX.out in the directory in which you submitted the job. This is the standard-out from that job. ie; everything that you would normally see printed to your screen when running locally, is printed to this file when running as a job. Once the job is over, one would inspect the slurm output file.\n\nhead slurm-XXXX.out\ntail slurm-XXXX.out\ncat slurm-XXXX.out" + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html#nextflow", + "href": "topics/rnaseq/lab_rnaseq.html#nextflow", + "title": "RNASeq Workflow", + "section": "6 Nextflow", + "text": "6 Nextflow\n\n\n\n\n\n\nNote\n\n\n\nYou are not required to run anything practically in this section. This is just to read and understand.\n\n\nEverything you have done today and more is easily done using structured pipelines. Nextflow is a popular framework for creating bioinformatic pipelines and nf-core is a collection of curated analyses pipelines. Here, we will discuss the steps for analysing our current dataset using the nf-core rnaseq pipeline for bulk RNA-Seq. The nf-core website and pipeline specific pages are good sources of information on what the pipeline does and what parameters can be changed.\n\n\n\n\n\nWe need a samplesheet.csv to define our samples. In this case, the full size samples are used. For single-end reads, fastq_2 column is left empty.\nsample,fastq_1,fastq_2,strandedness\nko_1,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222409_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222409_2.fq.gz,unstranded\nko_2,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222410_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222410_2.fq.gz,unstranded\nko_3,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222411_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222411_2.fq.gz,unstranded\nwt_1,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222412_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222412_2.fq.gz,unstranded\nwt_2,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222413_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222413_2.fq.gz,unstranded\nwt_3,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222414_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222414_2.fq.gz,unstranded\nWe need a params.config file to define parameters such as input, output, genome, annotation etc.\nparams.input = \"samplesheet.csv\"\nparams.outdir = \"results\"\nparams.aligner = \"star_salmon\"\n\nparams.fasta = \"/sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa\"\nparams.gtf = \"/sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf\"\ngene_bed = \"/sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed\"\nstar_index = \"/sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/version2.7.x/\"\nAnd lastly we have a nextflow.sh which will be our bash script for launching the job.\n\n\n#!/bin/bash\n\n#SBATCH -A naiss2023-22-862\n#SBATCH -p core\n#SBATCH -n 1\n#SBATCH -t 4:00:00\n#SBATCH -J nf-core\n\nmodule load bioinfo-tools\nmodule load Nextflow/21.10.6\nmodule load nf-core/2.1\nNXF_HOME=.\n\nnextflow run nf-core/rnaseq -r 3.7 -c params.config -profile uppmax --project naiss2023-22-862 -resume\n\n\nNotice that we use -profile uppmax since this is run on Uppmax. The job is then submitted by simply running sbatch nextflow.sh.\nThe slurm output from this job looks like this:\nNote that NXF_HOME is set to $HOME/.nextflow\nPlease change NXF_HOME to a place in your project directory (export NXF_HOME=yourprojectfolder)\n\nN E X T F L O W ~ version 21.10.6\nLaunching `nf-core/rnaseq` [happy_sammet] - revision: e0dfce9af5 [3.7]\n\n\n------------------------------------------------------\n ,--./,-.\n ___ __ __ __ ___ /,-._.--~'\n |\\ | |__ __ / ` / \\ |__) |__ } {\n | \\| | \\__, \\__/ | \\ |___ \\`-._,-`-,\n `._,._,'\n nf-core/rnaseq v3.7\n------------------------------------------------------\nCore Nextflow options\n revision : 3.7\n runName : happy_sammet\n containerEngine : singularity\n launchDir : /crex/course_data/ngsintro/rnaseq/main_full/nextflow\n workDir : /crex/course_data/ngsintro/rnaseq/main_full/nextflow/work\n projectDir : ./assets/nf-core/rnaseq\n userName : royfranc\n profile : uppmax\n configFiles : /crex/course_data/ngsintro/rnaseq/main_full/nextflow/assets/nf-core/rnaseq/nextflow.config, /crex/course_data/ngsintro/rnaseq/main_full/nextflow/params.config\n\nInput/output options\n input : samplesheet.csv\n outdir : results\n\nReference genome options\n fasta : /sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa\n gtf : /sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf\n save_reference : true\n igenomes_base : /sw/data/igenomes/\n\nInstitutional config options\n config_profile_description: UPPMAX (Rackham) cluster profile provided by nf-core/configs.\n config_profile_contact : Phil Ewels (@ewels)\n config_profile_url : https://www.uppmax.uu.se/\n\nMax job request options\n max_cpus : 20\n max_memory : 970 GB\n max_time : 10d\n\nGeneric options\n tracedir : null/pipeline_info\n\n!! Only displaying parameters that differ from the pipeline defaults !!\n------------------------------------------------------\nIf you use nf-core/rnaseq for your analysis please cite:\n\n* The pipeline\n https://doi.org/10.5281/zenodo.1400710\n\n* The nf-core framework\n https://doi.org/10.1038/s41587-020-0439-x\n\n* Software dependencies\n https://github.com/nf-core/rnaseq/blob/master/CITATIONS.md\n------------------------------------------------------\n[- ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -\n\n[- ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:INPUT_... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:CAT_FASTQ -\n[- ] process > NFCORE_RNASEQ:RNASEQ:FASTQC... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:FASTQC... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:ALIGN_... -\n[- ] process > NFCORE_RNASEQ:RNASEQ:ALIGN_... -\n\n...\nskipping many lines here\n...\n\n[3d/d294eb] process > NFCORE_RNASEQ:RNASEQ:CUSTOM... [100%] 1 of 1 ✔\n[de/a03037] process > NFCORE_RNASEQ:RNASEQ:MULTIQ... [100%] 1 of 1 ✔\n-[nf-core/rnaseq] 6/6 samples passed STAR 5% mapped threshold:\n 90.41%: ko_2\n 89.8%: ko_3\n 87.15%: ko_1\n 89.7%: wt_2\n 90.29%: wt_3\n 91.02%: wt_1\n ..see pipeline reports for full list\n-\n-[nf-core/rnaseq] Pipeline completed successfully-\nCompleted at: 13-Jan-2023 14:39:08\nDuration : 1h 45m 30s\nCPU hours : 90.4\nSucceeded : 207\nThe output results directory looks like this:\nresults/\n├── fastqc\n├── genome\n│ ├── genes.bed\n│ ├── genome.fa.fai\n│ ├── genome.fa.sizes\n│ ├── genome_genes.gtf\n│ ├── genome.transcripts.fa\n│ ├── index\n│ └── rsem\n├── multiqc\n│ └── star_salmon\n├── pipeline_info\n│ ├── samplesheet.valid.csv\n│ └── software_versions.yml\n├── star_salmon\n│ ├── bigwig\n│ ├── deseq2_qc\n│ ├── dupradar\n│ ├── featurecounts\n│ ├── ko_1\n│ ├── ko_1.markdup.sorted.bam\n│ ├── ko_1.markdup.sorted.bam.bai\n│ ├── ko_2\n│ ├── ko_2.markdup.sorted.bam\n│ ├── ko_2.markdup.sorted.bam.bai\n│ ├── ko_3\n│ ├── ko_3.markdup.sorted.bam\n│ ├── ko_3.markdup.sorted.bam.bai\n│ ├── log\n│ ├── picard_metrics\n│ ├── preseq\n│ ├── qualimap\n│ ├── rseqc\n│ ├── salmon.merged.gene_counts_length_scaled.rds\n│ ├── salmon.merged.gene_counts_length_scaled.tsv\n│ ├── salmon.merged.gene_counts.rds\n│ ├── salmon.merged.gene_counts_scaled.rds\n│ ├── salmon.merged.gene_counts_scaled.tsv\n│ ├── salmon.merged.gene_counts.tsv\n│ ├── salmon.merged.gene_tpm.tsv\n│ ├── salmon.merged.transcript_counts.rds\n│ ├── salmon.merged.transcript_counts.tsv\n│ ├── salmon.merged.transcript_tpm.tsv\n│ ├── salmon_tx2gene.tsv\n│ ├── samtools_stats\n│ ├── stringtie\n│ ├── wt_1\n│ ├── wt_1.markdup.sorted.bam\n│ ├── wt_1.markdup.sorted.bam.bai\n│ ├── wt_2\n│ ├── wt_2.markdup.sorted.bam\n│ ├── wt_2.markdup.sorted.bam.bai\n│ ├── wt_3\n│ ├── wt_3.markdup.sorted.bam\n│ └── wt_3.markdup.sorted.bam.bai\n└── trimgalore\nThis pipeline takes you from raw reads to counts including read QC, mapping, mapping QC and quantification as well as a complete collated overview of all steps as a MultiQC report (multiqc/star_salmon/multiqc_report.html). The star_salmon/salmon.merged.gene_counts.tsv is the counts file that you would use for downstream differential gene expression using DESeq2.\nFor standard analyses steps, it is recommended to use a pipeline as the tools are up-to-date and the analyses steps are reproducible using exactly the same versions of tools." + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html#simons-analysis", + "href": "topics/rnaseq/lab_rnaseq.html#simons-analysis", + "title": "RNASeq Workflow", + "section": "7 Simon’s analysis", + "text": "7 Simon’s analysis\nWe had Simon Andrews from the Babraham institute with us on one of the workshops and he did his own exploration into the dataset from this paper using his tool SeqMonk. It’s an excellent read and highly recommended. His report is available on the Contents page." + }, + { + "objectID": "topics/rnaseq/lab_rnaseq.html#conclusion", + "href": "topics/rnaseq/lab_rnaseq.html#conclusion", + "title": "RNASeq Workflow", + "section": "8 Conclusion", + "text": "8 Conclusion\nWe hope that you enjoyed getting your hands wet working on some real-ish data. In this tutorial, we have covered the most important data processing steps that may be enough when the libraries are good. If not, there are plenty of troubleshooting procedures to try before discarding the data. And once the count table are in place, the biostatistics and data mining begins. There are no well-defined solutions here, all depends on the experiment and questions to be asked, but we strongly advise learning R. Not only to use the specifically designed statistical packages to analyse NGS count data, but also to be able to handle the data and results as well as to generate high-quality plots. There are many available tools and well-written tutorials with examples to learn from.\nFor those interested in RNA-Seq analysis, SciLifeLab offers a more advanced course in RNA-Seq analysis each semester. For more information, see SciLifeLab events." + }, + { + "objectID": "topics/uppmax/intro/lab_uppmax_intro.html", + "href": "topics/uppmax/intro/lab_uppmax_intro.html", + "title": "Uppmax Introduction", + "section": "", + "text": "Note\n\n\n\nIn code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window." + }, + { + "objectID": "topics/uppmax/intro/lab_uppmax_intro.html#the-devel-queue", + "href": "topics/uppmax/intro/lab_uppmax_intro.html#the-devel-queue", + "title": "Uppmax Introduction", + "section": "9.1 The devel queue", + "text": "9.1 The devel queue\nIf it is a really big job, it might be in the queue for a day or two before it starts, so it is important to know that the first thing it does is not crashing because you made a typo on line 7. One way to test this is to open a new connection to UPPMAX, and line by line try your code. Copy-paste (Ctrl+Shift+c and Ctrl+Shift+v in the terminal window) to make sure it’s really the code in the script you are trying.\nIf your script is longer than a couple of lines, this approach can be tiring. There are 12 nodes at UPPMAX that are dedicated to do quick test runs, which have a separate queue called devel. They are available for use more or less all the time since not very many are using them. To avoid people abusing the free nodes for their analysis, there is a 1 hour time limit for jobs on them. To submit jobs to this short testing queue, change -p to devel instead of node or core, and make sure -t is set to maximum 01:00:00. Try submitting the samtools sbatch file we used earlier to the devel queue and run it again." + }, + { + "objectID": "topics/uppmax/intro/lab_uppmax_intro.html#info-about-finished-jobs", + "href": "topics/uppmax/intro/lab_uppmax_intro.html#info-about-finished-jobs", + "title": "Uppmax Introduction", + "section": "9.2 Info about finished jobs", + "text": "9.2 Info about finished jobs\nIf you want information about jobs you have run in the past, you can use the tool finishedjobinfo. It will print information about the jobs you have run lately.\nFun things to look for in this information is jobstate which will tell you if the program reported any error while running. If so, jobstate will be FAILED and you could suspect that something didn’t go according to the plan, and you should check the output from that job run (the slurm-.out file) and see if you can solve the error.\nOther good things to look for could be:\n\nmaxmemory_in_GiB: tells you how much memory the program used at most.\nruntime: tells you how long time the program ran before it finished/failed" + }, + { + "objectID": "topics/uppmax/intro/lab_uppmax_intro.html#time-and-space", + "href": "topics/uppmax/intro/lab_uppmax_intro.html#time-and-space", + "title": "Uppmax Introduction", + "section": "9.3 Time and space", + "text": "9.3 Time and space\nRemember the commands uquota (show how much of your storage space you are using) and projinfo (shows you how much of your allocated time you have used) from the lecture? Try running them and see how you are doing.\n\n\n\n\n\n\nOptional\n\n\n\nThis optional material on uppmax pipelines will teach you the basics in creating pipelines. Continue with this if you finish the current lab ahead of time. Navigate to the exercise Uppmax Pipelines lab." + }, + { + "objectID": "topics/vc/lab_vc.html", + "href": "topics/vc/lab_vc.html", + "title": "Variant Calling", + "section": "", + "text": "Whole genome sequencing (WGS) is a comprehensive method for analyzing entire genomes. This workshop will take you through the process of calling germline short variants (SNVs and INDELs) in WGS data from three human samples.\n\nThe first part of the workshop will guide you through a basic variant calling workflow in one sample. The goals are that you should get familiar with the bam and vcf file formats, and be able to interpret vcf files in Integrative Genomics Viewer (IGV).\nIf you have time, the next part of the workshop will show you how to perform joint variant calling in three samples. The goals here are that you should be able to interpret multi-sample vcf files and explain the differences between the g.vcf and vcf file formats.\nIf you have time, the last part of the workshop will take you through the GATK best practices for germline short variant detection in three samples. The goal here is that you should learn how to use GATK’s documentation so that you can analyze your own samples in the future.\n\n\n\n\n\n\n\nGeneral guide\n\n\n\n\nYou will work on the computing cluster Rackham at UPPMAX\nIf you change the node you are working on you will need to reload the tool modules.\nPlease type commands in the terminal instead of copying and pasting them which often result in formatting errors.\nUse tab completion.\nIn paths, please replace username with your actual UPPMAX username.\nIn commands, please replace parameter with the correct parameter, for example your input file name, output file name, directory name, etc.\nA line starting with # is a comment\nRunning a command without parameters will often return a help message on how to run the command.\nAfter a command is completed, please check that the desired output file was generated and that it has a reasonable size (use ls -l).\nGoogle errors, someone in the world has run into EXACTLY the same problem you had and asked about it on a forum somewhere." + }, + { + "objectID": "topics/vc/lab_vc.html#samples", + "href": "topics/vc/lab_vc.html#samples", + "title": "Variant Calling", + "section": "Samples", + "text": "Samples\nThe 1000 Genomes Project ran between 2008 and 2015, creating the largest public catalogue of human variation and genotype data. In this workshop we will use low coverage whole genome sequence data from three individuals, generated in the first phase of the 1000 Genomes Project.\n\n\n\nSample\nPopulation\nSequencing technology\n\n\n\n\nHG00097\nBritish in England and Scotland\nLow coverage WGS\n\n\nHG00100\nBritish in England and Scotland\nLow coverage WGS\n\n\nHG00101\nBritish in England and Scotland\nLow coverage WGS" + }, + { + "objectID": "topics/vc/lab_vc.html#Genomicregion", + "href": "topics/vc/lab_vc.html#Genomicregion", + "title": "Variant Calling", + "section": "Genomic region", + "text": "Genomic region\nThe LCT gene on chromosome 2 encodes the enzyme lactase, which is responsible for the metabolism of lactose in mammals. Most mammals can not digest lactose as adults, but some humans can. Genetic variants upstream of the LCT gene causes lactase persistence, which means that lactase is expressed also in adulthood and the carrier can continue to digest lactose. The variant rs4988235, located at position chr2:136608646 in the GRCh37 reference genome, has been shown to lead to lactose persistence. The alternative allele (A on the forward strand and T on the reverse strand) creates a new transcription factor binding site that enables continued expression of the gene after weaning.\nIn this workshop we will detect genetic variants in the region chr2:136545000-136617000 in the three samples listed above, and check if they carry the allele for lactase persistence.\nFor those interested in the details of the genetic bases for lactose tolerance, please read the first three pages of Lactose intolerance: diagnosis, genetic, and clinical factors by Mattar et al. The variant rs4988235 is here referred to as LCT-13910C>T." + }, + { + "objectID": "topics/vc/lab_vc.html#Data", + "href": "topics/vc/lab_vc.html#Data", + "title": "Variant Calling", + "section": "Data folder on UPPMAX", + "text": "Data folder on UPPMAX\nAll input data for this exercise is located in this folder on Rackham:\n\n\n/sw/courses/ngsintro/reseq/data\n\n\nThe fastq files are located in this folder:\n\n\n/sw/courses/ngsintro/reseq/data/fastq\n\n\nReference files, such as the reference genome in fasta format, are located in this folder:\n\n\n/sw/courses/ngsintro/reseq/data/ref" + }, + { + "objectID": "topics/vc/lab_vc.html#preparelaptop", + "href": "topics/vc/lab_vc.html#preparelaptop", + "title": "Variant Calling", + "section": "Laptop", + "text": "Laptop\nThis lab will be done completely on UPPMAX and the instructions assume that you connect via ThinLinc. However, if you prefer to connect to UPPMAX via ssh you can instead copy some of the resulting files to your laptop and work on them there. , install IGV, and run all the IGV steps on your laptop. If so, please create a local workspace on your laptop, for example a folder called ngsworkflow on your desktop. You need to have write permission in this folder. If you connect to UPPMAX via ThinLinc you don’t have to crete a local workspace." + }, + { + "objectID": "topics/vc/lab_vc.html#uppmax", + "href": "topics/vc/lab_vc.html#uppmax", + "title": "Variant Calling", + "section": "UPPMAX", + "text": "UPPMAX\n\nConnect to UPPMAX\nDuring this lab it is best to connect to UPPMAX with ThinLinc, which gives you a graphical remote desktop. Instructions for this is available at Connecting to UPPMAX. Please follow the instructions in section 1.2 Remote desktop connection.\n\n\nLogon to a node\nThis lab should be done on a compute node (not the login node). First check if you already have an active job allocation using this command:\nsqueue -u username\nWhere username should be replaced with your username. If no jobs are listed you should allocate a job for this lab. If you already have an active job allocation please proceed to Connect to the node below.\nUse this code to allocate a job on day 1 of variant-calling:\n\n\nsalloc -A naiss2023-22-862 -t 04:00:00 -p core -n 1 --no-shell\n\n\nUse this code to allocate a job on day 2 of variant-calling:\n\n\nsalloc -A naiss2023-22-862 -t 04:00:00 -p core -n 1 --no-shell\n\n\nOnce your job allocation has been granted (should not take long) please check the allocation again using:\nsqueue -u username\nYou should now see that you have an active job allocation. The node name for your job is listed under the nodelist header.\nConnect to the node:\nssh -Y nodename\n\n\nWorkspace on UPPMAX\nYou should work in your folder under the course’s nobackup folder, just like you have done during the previous labs.\nStart by going there using this command:\n\n\ncd /proj/naiss2023-22-862/nobackup/username\n\n\nWhere username should be replaced with your real username. Create a folder for this exercise and move into it:\nmkdir ngsworkflow\ncd ngsworkflow\nMake sure you are located in\n\n\n/proj/naiss2023-22-862/nobackup/username/ngsworkflow\n\n\nfor the rest of this lab.\n\n\nSymbolic links to data\nThe raw data files are located in the Data folder described above.\nCreate a symbolic link to the reference genome (in this case chromosome 2 in GRCh37) in your workspace:\n\n\nln -s /sw/courses/ngsintro/reseq/data/ref/human_g1k_v37_chr2.fasta\n\n\nDo the same with the fastq files:\n\n\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_2.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_2.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_2.fq\n\n\n\n\nAccessing programs\nLoad the modules that are needed during this workshop. Remember that these modules must be loaded every time you login to Rackham, or when you connect to a new compute node.\nFirst load the bioinfo-tools module:\nmodule load bioinfo-tools\nThis makes it possible to load the individual programs:\nmodule load FastQC/0.11.8\nmodule load bwa/0.7.17\nmodule load samtools/1.10\nmodule load GATK/4.1.4.1\nAlthough you don’t have to specify which versions of the tools to use, it is recommended to do so for reproducibility if you want to rerun the exact same analyses later. When loading the module GATK/4.1.4.1 you will get a warning message about the fact that GATK commands have been updated since the previous version of GATK. This is fine and you don’t have to do anything about it." + }, + { + "objectID": "topics/vc/lab_vc.html#index-the-genome", + "href": "topics/vc/lab_vc.html#index-the-genome", + "title": "Variant Calling", + "section": "Index the genome", + "text": "Index the genome\nTools that compare short reads with a large reference genome needs indexes of the reference genome to work efficiently. You therefore need to create index files for each tool.\nFirst check if you are standing in the correct directory:\npwd\nShould return\n\n\n/proj/naiss2023-22-862/nobackup/username/ngsworkflow\n\n\nGenerate BWA index files:\nbwa index -a bwtsw human_g1k_v37_chr2.fasta\nCheck that several new files have been created using ls -l. Then Generate a samtools index:\nsamtools faidx human_g1k_v37_chr2.fasta\nCheck to see what file(s) were created using ls -lrt. Then Generate a GATK sequence dictionary:\ngatk --java-options -Xmx7g CreateSequenceDictionary -R human_g1k_v37_chr2.fasta -O human_g1k_v37_chr2.dict\nAgain, check what file(s) were created using ls -lrt." + }, + { + "objectID": "topics/vc/lab_vc.html#aligning-reads", + "href": "topics/vc/lab_vc.html#aligning-reads", + "title": "Variant Calling", + "section": "1.1 Aligning reads", + "text": "1.1 Aligning reads\n\n1.1.1 BWA mem\nYou should use BWA mem to align the reads to the reference genome.\nIn the call to BWA mem you need to add something called a read group, which contains information about how the reads were generated. This is required by HaplotypeCaller. Since we don’t know exactly how the reads in the 1000 Genomes Project were generated we will assume that each pair of fastq files was generated from one library preparation (libraryx), derived from one biological sample (HG00097), and run on one lane (lanex) of a flowcell (flowcellx) on the Illumina machine, and define a toy read group with this information. The code for adding this read group is\n-R “(RG?)\\tID:HG00097\\tPU:lanex_flowcellx\\tSM:HG00097\\tLB:libraryx\\tPL:illumina”.\n\n\n\n\n\n\nNote\n\n\n\nWhen running BWA for another sample later on you have to replace HG00097 in the read group with the new sample name. To learn more about read groups please read this article at GATK forum.\n\n\nYou also need to specify how many threads the program should use (should be the same as the number of cores you have access to and is defined by the code -t 1 below) and what reference genome file to use. The output from BWA should be parsed to samtools sort, which sorts the sam file according to chromosome position and then converts the sam file to the binary bam format. Finally, use a file redirect > so that the output ends up in a file and not on your screen.\nFirst make sure that you are standing in the workspace you created on UPPMAX for this lab:\npwd\nShould return\n\n\n/proj/naiss2023-22-862/nobackup/username/ngsworkflow\n\n\nThen use this command to align the reads, add the read group, sort the reads and write them to a bam file:\nbwa mem \\\n-R \"@RG\\tID:readgroup_HG00097\\tPU:lanex_flowcellx\\tSM:HG00097\\tLB:libraryx\\tPL:illumina\" \\\n-t 1 human_g1k_v37_chr2.fasta HG00097_1.fq HG00097_2.fq | samtools sort > HG00097.bam\nPlease check that the expected output file was generated and that it has content using ls -lrt.\nNext you need to index the generated bam file so that programs can randomly access the sorted data without reading the whole file. This command creates an index file with the same name as the input bam file, except with a .bai extension:\nsamtools index HG00097.bam\nPlease check what output file was generated this time.\n\n\n1.1.2 Check bam with samtools\nThe bam file is binary so we cannot read it directly, but we can view it with the program samtools view. The header section of the bam file can be viewed separately with the -H flag:\nsamtools view -H HG00097.bam\n\nQuestion\n\nThe (SQ?) tag of the bam header contains information about reference sequence. What do you think SN:2 and LN:243199373 in this tag means?\n\nThe aligned reads can be viewed with samtools view without the -H. This will display the entire bam file which is quite large, so if you just want to look at the first 5 lines (for example) you can combine samtools view with head:\nsamtools view HG00097.bam | head -n 5\n\n\nQuestion\n\nWhat is the leftmost mapping position of the first read in the bamfile?\n\nPlease have a look at the Sequence Alignment/Map Format Specification for more information about bam files.\n\n\n\n1.1.3 Check bam in IGV\nTo use IGV on UPPMAX we recommend that you are connected via ThinLinc. Alternatively you can install IGV on your local computer, download the files using scp, and look at them locally. The instructions below assume that you have logged in to UPPMAX via ThinLinc.\nFirst use pwd to check if you are standing in the correct directory:\npwd\nShould return\n\n\n/proj/naiss2023-22-862/nobackup/username/ngsworkflow\n\n\nTo start IGV please type this in the terminal:\nmodule load IGV/2.8.13\nigv.sh &\nIn IGV:\nIn the upper left dropdown menu choose Human hg19 (which is the same as GRCh37).\nIn the File menu, select Load from File and select HG00097.bam, which should then appear in the tracks window.\nZoom in to see the reads. You can either select a region by click and drag, or by typing a region or a gene name in the text box at the top. Remember that we have data for the region chr2:136545000-136617000.\nIGV can be closed by selecting exit in the File menu or by clicking x in the upper right corner of the IGV window, but you can keep it open for the rest of the lab.\n\nQuestions\n\nWhat is the read length?\nApproximately how many reads cover an arbitrary position in the genomic region we are looking at?\nWhich RefSeq Genes are located within the region chr2:136545000-136617000?" + }, + { + "objectID": "topics/vc/lab_vc.html#variant-calling", + "href": "topics/vc/lab_vc.html#variant-calling", + "title": "Variant Calling", + "section": "1.2 Variant Calling", + "text": "1.2 Variant Calling\n\n1.2.1 HaplotypeCaller\nNow we will detect short variants in the bam file using GATK’s HaplotypeCaller. First use pwd to check if you are standing in the correct directory:\npwd\nShould return\n\n\n/proj/naiss2023-22-862/nobackup/username/ngsworkflow\n\n\nThen run:\ngatk --java-options -Xmx7g HaplotypeCaller \\\n-R human_g1k_v37_chr2.fasta \\\n-I HG00097.bam \\\n-O HG00097.vcf\nCheck what new files were generated with ls -lrt.\n\n\n1.2.2 Explore the vcf file\nNow you have your first vcf file containing the raw variants in the region chr2:136545000-136617000 in sample HG00097. Please look at the vcf file with less and try to understand its structure.\nVcf files contains meta-information lines starting with ##, a header line starting with #CHROM, and then data lines each containing information about one variant position in the genome. The header line defines the columns of the data lines, and to view the header line you can type this command:\ngrep '#CHROM' HG00097.vcf\n\nQuestion\n\nWhat column of the VCF file contains genotype information for the sample HG00097?\n\nThe meta-information lines starting with ##INFO defines how the data in the INFO column is encoded, and the meta-information lines starting with ##FORMAT defines how the data in the FORMAT column is encoded.\nTo view the meta-information lines describing the INFO column use:\ngrep '##INFO' HG00097.vcf\nTo view the meta-information lines describing the FORMAT column use:\ngrep '##FORMAT' HG00097.vcf\n\n\nQuestion\n\nWhat does GT in the FORMAT column of the data lines mean?\nWhat does AD in the FORMAT column of the data lines mean?\n\nTo look at the details of one specific genetic variant at position 2:136545844 use:\ngrep '136545844' HG00097.vcf\n\n\nQuestions\n\nWhat genotype does the sample HG00097 have at position 2:136545844?\nWhat are the allelic depths for the reference and alternative alles in sample HG00097 at position 2:136545844?\n\nThe following command can be used to count the data lines (i.e. number of lines that don’t start with “#”) in the vcf file:\ngrep -v \"#\" HG00097.vcf | wc -l\n\n\nQuestion\n\nHow many genetic variants was detected in HG00097?\n\nFor more detailed information about vcf files please have a look at The Variant Call Format specification.\n\n\n\n1.2.3 Check vcf in IGV\nWe assume that you have logged in to UPPMAX via ThinLinc.\nIf you have closed IGV please open it again as described above.\nLoad the file HG00097.vcf into tracks window of IGV as you did with the HG00097.bam file earlier (load the bam file as well if it is not already loaded). You will now see all the variants called in HG00097.\nYou can view variants in the LCT gene by typing the gene name in the search box, and you can look specifically at the variant at position chr2:136545844 by typing that position in the search box.\nPlease use IGV to answer the questions below.\n\nQuestions\n\nHover the mouse over the upper row of the vcf track. What is the reference and alternative alleles of the variant at position chr2:136545844?\nHover the mouse over the lower row of the vcf track and look under “Genotype Information”. What genotype does HG00097 have at position chr2:136545844? Is this the same as you found by looking directly in the vcf file in question 10?\nLook in the bam track and count the number of reads that have “G” and “C”, respectively, at position chr2:136545844. How is this information captured under “Genotype Attributes”? (Again, hoover the mouse over the lower row of the vcf track.)" + }, + { + "objectID": "topics/vc/lab_vc.html#bwa_joint", + "href": "topics/vc/lab_vc.html#bwa_joint", + "title": "Variant Calling", + "section": "2.1 BWA mem", + "text": "2.1 BWA mem\nRun BWA mem for all three samples in the data set. BWA mem should be run exactly as above, but with the new sample names. You also need to adjust the read group information so that it matches each new sample name. \nFirst use pwd to check if you are standing in the correct directory:\npwd\nShould return\n\n\n/proj/naiss2023-22-862/nobackup/username/ngsworkflow\n\n\nThen use this command for every sample to align the reads, add the read group, sort the reads and write them to a bam file:\nbwa mem -R \"@RG\\tID:readgroup_<sample>\\tPU:lanex_flowcellx\\tSM:<sample>\\tLB:libraryx\\tPL:illumina\" \\\n-t 1 human_g1k_v37_chr2.fasta sample_1.fq sample_2.fq | samtools sort > sample.bam\nWhere sample should be replaced with the real samples name, i.e. HG00097, HG00100 and HG00101. Please check that the expected output files were generated and have content using ls -lrt. You also need to index each output bam file:\nsamtools index <sample>.bam\nPlease check what output file was generated this time. If you run out of time you can click below to get paths to precomputed bam files.\n\n\n/sw/courses/ngsintro/reseq/data/bam/HG00097.bam\n/sw/courses/ngsintro/reseq/data/bam/HG00100.bam\n/sw/courses/ngsintro/reseq/data/bam/HG00101.bam" + }, + { + "objectID": "topics/vc/lab_vc.html#generategvcf", + "href": "topics/vc/lab_vc.html#generategvcf", + "title": "Variant Calling", + "section": "2.2 Generate g.vcf files", + "text": "2.2 Generate g.vcf files\nHaplotypeCaller should also be run for all three samples, but this time the output for each sample needs to be in g.vcf format. This is accomplished with a small change in the HaploteypCaller command. First use pwd to check if you are standing in the correct directory:\npwd\nShould return\n\n\n/proj/naiss2023-22-862/nobackup/username/ngsworkflow\n\n\nThen:\ngatk --java-options -Xmx7g HaplotypeCaller \\\n-R human_g1k_v37_chr2.fasta \\\n-ERC GVCF \\\n-I sample.bam \\\n-O sample.g.vcf\nPlease replace sample with the real sample names.\nIf you run out of time you can click below to get paths to the precomputed g.vcf files.\n\n\n/sw/courses/ngsintro/reseq/data/vcf/HG00097.g.vcf\n/sw/courses/ngsintro/reseq/data/vcf/HG00100.g.vcf\n/sw/courses/ngsintro/reseq/data/vcf/HG00101.g.vcf" + }, + { + "objectID": "topics/vc/lab_vc.html#jointgenotyping", + "href": "topics/vc/lab_vc.html#jointgenotyping", + "title": "Variant Calling", + "section": "2.3 Joint genotyping", + "text": "2.3 Joint genotyping\nOnce you have the g.vcf files for all samples you should perform joint genotype calling. To do this you first need to combine all individual .g.vcf files to one file using CombineGVCFs.\nFirst use pwd to check if you are standing in the correct directory:\npwd\nShould return\n\n\n/proj/naiss2023-22-862/nobackup/username/ngsworkflow\n\n\nThen:\ngatk --java-options -Xmx7g CombineGVCFs \\\n-R human_g1k_v37_chr2.fasta \\\n-V sample1.g.vcf \\\n-V sample2.g.vcf \\\n-V sample3.g.vcf \\\n-O cohort.g.vcf\nPlease replace sample1, sample2, sample3 with the real sample names. Then run GATK’s GenoteypeGVC to generate a vcf file:\ngatk --java-options -Xmx7g GenotypeGVCFs \\\n-R human_g1k_v37_chr2.fasta \\\n-V cohort.g.vcf \\\n-O cohort.vcf\nIf you run out of time you can click below to get paths to the precomputed cohort.g.vcf and cohort.vcf files.\n\n\n/sw/courses/ngsintro/reseq/data/vcf/cohort.g.vcf\n/sw/courses/ngsintro/reseq/data/vcf/cohort.vcf\n\n\n\nQuestions\n\nHow many data lines do the cohort.g.vcf file have? You can use the Linux command grep -v \"#\" cohort.g.vcf to extract all lines in “cohort.g.vcf” that don’t start with “#”, then |, and then wc -l to count those lines.\nHow many data lines do the cohort.vcf file have?\nExplain the difference in number of data lines.\nLook at the header line of the cohort.vcf file. What columns does it have?\nWhat is encoded in the last three columns of the data lines?" + }, + { + "objectID": "topics/vc/lab_vc.html#check-combined-vcf-file-in-igv", + "href": "topics/vc/lab_vc.html#check-combined-vcf-file-in-igv", + "title": "Variant Calling", + "section": "2.4 Check combined vcf file in IGV", + "text": "2.4 Check combined vcf file in IGV\nAgain we assume that you have logged in to UPPMAX via ThinLinc.\nIf you have closed IGV please open it again as described above.\nLoad the files cohort.vcf, HG00097.bam, HG00100.bam and HG00101.bam into IGV as described earlier.\nThis time lets look closer at the variant rs4988235, located at position chr2:136608646 in the HG19 reference genome. This is the variant that has been shown to lead to lactase persistence.\nPlease use IGV to answer the questions below.\n\nQuestions\n\nWhat is the reference and alternative alleles at chr2:136608646?\nWhat genotype do the three samples have at chr2:136608646? Note how genotypes are color coded in IGV.\nShould any of the individuals avoid drinking milk?\nNow compare the data shown in IGV with the data in the VCF file. Extract the row for the chr2:136608646 variant in the cohort.vcf file, for example using grep '136608646' cohort.vcf. What columns of the vcf file contain the information shown in the upper part of the vcf track in IGV?\nWhat columns of the vcf file contain the information shown in the lower part of the vcf track?\nZoom out so that you can see the MCM6 and LCT genes. Is the variant at chr2:136608646 locate within the LCT gene?\n\nIf you are interested in how this variant affects lactose tolerance please read the article by Mattar et al presented above, or in OMIM." + }, + { + "objectID": "topics/vc/lab_vc.html#bwa-mem", + "href": "topics/vc/lab_vc.html#bwa-mem", + "title": "Variant Calling", + "section": "3.1 BWA mem", + "text": "3.1 BWA mem\nThe first step in GATK’s best pracice variant calling workflow is to run BWA mem for each sample exactly as you did in Variant calling in cohort. You have already done this step, so please use the bam files that you generated in step 2.1 for the steps below." + }, + { + "objectID": "topics/vc/lab_vc.html#mark-duplicates", + "href": "topics/vc/lab_vc.html#mark-duplicates", + "title": "Variant Calling", + "section": "3.2 Mark Duplicates", + "text": "3.2 Mark Duplicates\nSometimes the same DNA fragment is sequenced multiple times, which leads to multiple reads from the same fragment in the fastq file. This can occur due to PCR amplification in the library preparation, or if one read cluster is incorrectly detected as multiple clusters by the sequencing instrument. If a duplicated read contains a genetic variant, the ratio of the two alleles might be obscured, which can lead to incorrect genotyping. It is therefore recommended (in most cases) to mark duplicate reads so that they are counted as one during genotyping.\nPlease read about Picard’s MarkDuplicates here. Picard’s MarkDuplicates has recently been incorporated into the GATK suite, but the usage example in GATKs documentation describes how to call it via the stand alone Picard program. To learn how to use it as part of the GATK module, please call MarkDuplicates without input parameters like this:\ngatk --java-options -Xmx7g MarkDuplicates\nPlease run MarkDuplicates on all three bam files generated in step 2.1. Here is the code for running MarkDuplicates on the sample HG00097:\ngatk --java-options -Xmx7g MarkDuplicates \\\n -I HG00097.bam \\\n -O HG00097.md.bam \\\n -M HG00097_mdmetrics.txt" + }, + { + "objectID": "topics/vc/lab_vc.html#recalibrate-base-quality-scores", + "href": "topics/vc/lab_vc.html#recalibrate-base-quality-scores", + "title": "Variant Calling", + "section": "3.3 Recalibrate Base Quality Scores", + "text": "3.3 Recalibrate Base Quality Scores\nAnother source of error is systematic biases in the assignment of base quality scores by the sequencing instrument. This can be corrected by GATK’s Base Quality Score Recalibration. In short, you first use BaseRecalibrator to build a recalibration model, and then ApplyBQSR to recalibrate the base qualities in your bam file.\nBaseRecalibrator requires a file with known SNPs as input. This file is available in the data folder on UPPMAX:\n\n\n/sw/courses/ngsintro/reseq/data/ref/1000G_phase1.snps.high_confidence.b37.chr2.vcf\n\n\nPlease recalibrate the base quality scores in all the bam files generated in the previous step. Below is our example solution for sample HG00097. First run BaseRecalibrator:\n\n\ngatk --java-options -Xmx7g BaseRecalibrator \\\n -R human_g1k_v37_chr2.fasta \\\n -I HG00097.md.bam \\\n --known-sites /sw/courses/ngsintro/reseq/data/ref/1000G_phase1.snps.high_confidence.b37.chr2.vcf \\\n -O HG00097.recal.table\n\n\nThen run ApplyBQSR:\ngatk --java-options -Xmx7g ApplyBQSR \\\n -R human_g1k_v37_chr2.fasta \\\n -I HG00097.md.bam \\\n --bqsr-recal-file HG00097.recal.table \\\n -O HG00097.recal.bam" + }, + { + "objectID": "topics/vc/lab_vc.html#generate-g.vcf-files", + "href": "topics/vc/lab_vc.html#generate-g.vcf-files", + "title": "Variant Calling", + "section": "3.4 Generate g.vcf files", + "text": "3.4 Generate g.vcf files\nHaplotypeCaller should also be run for all three samples, and the output should be in g.vcf exactly as described above. This time use recalibrated bam files as input." + }, + { + "objectID": "topics/vc/lab_vc.html#joint-genotyping", + "href": "topics/vc/lab_vc.html#joint-genotyping", + "title": "Variant Calling", + "section": "3.5 Joint genotyping", + "text": "3.5 Joint genotyping\nOnce you have the g.vcf files for all samples you should perform joint genotype calling. This should be done with the commands CombineGVCFs and GenotypeGVCFs exactly as described above, but you should use the g.vcf files generated from the recalibrated bam files as input." + }, + { + "objectID": "topics/vc/lab_vc.html#variant-filtering", + "href": "topics/vc/lab_vc.html#variant-filtering", + "title": "Variant Calling", + "section": "3.6 Variant Filtering", + "text": "3.6 Variant Filtering\nHaplotypeCaller is designed to be very sensitive, which is good because it minimizes the chance of missing real variants. However, it means that the number of false positives can be quite large, so we need to filter the raw callset. GATK offers two ways to filter variants:\n\nThe variant quality score recalibration (VQSR) method uses machine learning to identify variants that are likely to be real. This is the best method if you have a lot of data, for example one whole genome sequence sample or several whole exome samples.\n\nIf you have less data you can use hard filters as described here.\n\nSince we have very little data we will use hard filters. The parameters are slightly different for SNVs and INDELs, so you need to first select all SNVs using SelectVariants and filter them using VariantFiltration with the parameters suggested for SNVs. Then select all INDELs and filter them with the parameters suggested for INDELs. Finally merge the SNVs and INDELs to get all variants in one file using MergeVCFs.\nAn explanation of what the hard filters do can be found here.\nExample solution for filtering SNVs:\ngatk --java-options -Xmx7g SelectVariants \\\n -R human_g1k_v37_chr2.fasta \\\n -V cohort.vcf \\\n --select-type-to-include SNP \\\n -O cohort.snvs.vcf\n\ngatk --java-options -Xmx7g VariantFiltration \\\n -R human_g1k_v37_chr2.fasta \\\n -V cohort.snvs.vcf \\\n -O cohort.snvs.filtered.vcf \\\n --filter-name QDfilter --filter-expression \"QD < 2.0\" \\\n --filter-name MQfilter --filter-expression \"MQ < 40.0\" \\\n --filter-name FSfilter --filter-expression \"FS > 60.0\"\nExample solution for filtering INDELs:\ngatk --java-options -Xmx7g SelectVariants \\\n -R human_g1k_v37_chr2.fasta \\\n -V cohort.vcf \\\n --select-type-to-include INDEL \\\n -O cohort.indels.vcf\n\ngatk --java-options -Xmx7g VariantFiltration \\\n -R human_g1k_v37_chr2.fasta \\\n -V cohort.indels.vcf \\\n -O cohort.indels.filtered.vcf \\\n --filter-name QDfilter --filter-expression \"QD < 2.0\" \\\n --filter-name FSfilter --filter-expression \"FS > 200.0\"\nExample solution for merging filtered SNVs and INDELs:\ngatk --java-options -Xmx7g MergeVcfs \\\n -I cohort.snvs.filtered.vcf \\\n -I cohort.indels.filtered.vcf \\\n -O cohort.filtered.vcf\nOpen your filtered vcf with less and page through it. It still has all the variant lines, but the FILTER column that was blank before is now filled in, with PASS or a list of the filters it failed. Note also that the filters that were run are described in the header section.\n\nPrecomputed files\nIf you run out of time, please click below to get the path to precomputed bam and vcf files for the GATK’s best practices section.\n\n\nPath to intermediary and final bam files: /sw/courses/ngsintro/reseq/data/best_practise_bam\nPath to intermediary and final vcf files: /sw/courses/ngsintro/reseq/data/best_practise_vcf\n\n\n\n\nQuestions\n\nCheck how many variants in total that are present in the cohort.filtered.vcf file and how many that have passed the filters. Is the difference big?\nLook at the variants that did not pass the filters using grep -v 'PASS' cohort.filtered.vcf. Try to understand why these variants didn’t pass the filter." + }, + { + "objectID": "topics/vc/lab_vc.html#variant-calling-in-cohort", + "href": "topics/vc/lab_vc.html#variant-calling-in-cohort", + "title": "Variant Calling", + "section": "Variant calling in cohort", + "text": "Variant calling in cohort\nBelow is a skeleton script that can be used as a template for running variant calling in a cohort. Please modify it to run all the steps in part two of this workshop.\n#!/bin/bash\n#SBATCH -A sens2022-22-123\n#SBATCH -p core\n#SBATCH -n 1\n#SBATCH -t 1:00:00\n#SBATCH -J jointGenotyping\n\nmodule load bioinfo-tools\nmodule load bwa/0.7.17\nmodule load samtools/1.10\nmodule load GATK/4.1.4.1\n\n## loop through the samples:\nfor sample in HG00097 HG00100 HG00101;\ndo\n echo \"Now analyzing: \"${sample}\n #Fill in the code for running bwa-mem for each sample here\n #Fill in the code for samtools index for each sample here\n #Fill in the code for HaplotypeCaller for each sample here\ndone\n#Fill in the code for CombineGVCFs for all samples here\n#Fill in the code for GenotypeGVCFs here\nPlease save the sbatch script in your UPPMAX folder and call it “joint_genotyping.sbatch” or similar. Make the script executable by this command:\nchmod u+x joint_genotyping.sbatch\nTo run the sbatch script in the SLURM queue, use this command:\nsbatch joint_genotyping.sbatch\nIf you have an active node reservation you can run the script as a normal bash script:\n./joint_genotyping.sbatch\nIf you would like more help with creating the sbatch script, please look at our example solution:\n\n\n#!/bin/bash\n#SBATCH -A naiss2023-22-862\n#SBATCH -p core\n#SBATCH -n 1\n#SBATCH -t 2:00:00\n#SBATCH -J jointGenotyping\n\nmodule load bioinfo-tools\nmodule load bwa/0.7.17\nmodule load samtools/1.10\nmodule load GATK/4.1.4.1\n\nfor sample in HG00097 HG00100 HG00101;\ndo\n echo \"Now analyzing: \"${sample}\n bwa mem -R \\\n \"@RG\\tID:${sample}\\tPU:flowcellx_lanex\\tSM:${sample}\\tLB:libraryx\\tPL:illumina\" \\\n -t 1 human_g1k_v37_chr2.fasta \"${sample}_1.fq\" \"${sample}_2.fq\" | samtools sort > \"${sample}.bam\"\n\n samtools index \"${sample}.bam\"\n\n gatk --java-options -Xmx7g HaplotypeCaller \\\n -R human_g1k_v37_chr2.fasta \\\n -ERC GVCF -I \"${sample}.bam\" \\\n -O \"${sample}.g.vcf\"\n\ndone\n\ngatk --java-options -Xmx7g CombineGVCFs \\\n-R human_g1k_v37_chr2.fasta \\\n-V HG00097.g.vcf \\\n-V HG00100.g.vcf \\\n-V HG00101.g.vcf \\\n-O cohort.g.vcf\n\ngatk --java-options -Xmx7g GenotypeGVCFs \\\n-R human_g1k_v37_chr2.fasta \\\n-V cohort.g.vcf \\\n-O cohort.vcf" + }, + { + "objectID": "topics/vc/lab_vc.html#gatk-best-practices", + "href": "topics/vc/lab_vc.html#gatk-best-practices", + "title": "Variant Calling", + "section": "GATK best practices", + "text": "GATK best practices\nNow please try to incorporate the additional steps from GATK’s best practices into the workflow. If you run out of time you can sneak peek at our example solution below.\n\n\n#!/bin/bash\n#SBATCH -A naiss2023-22-862\n#SBATCH -p core\n#SBATCH -n 1\n#SBATCH -t 2:00:00\n#SBATCH -J BestPractise\n\n## load modules\nmodule load bioinfo-tools\nmodule load bwa/0.7.17\nmodule load samtools/1.10\nmodule load GATK/4.1.4.1\n\n# define path to reference genome\nref=\"/sw/courses/ngsintro/reseq/data/ref\"\n\n# make symbolic links\nln -s /sw/courses/ngsintro/reseq/data/ref/human_g1k_v37_chr2.fasta\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_2.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_2.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_2.fq\n\n# index reference genome\nbwa index -a bwtsw human_g1k_v37_chr2.fasta\nsamtools faidx human_g1k_v37_chr2.fasta\ngatk --java-options -Xmx7g CreateSequenceDictionary \\\n-R human_g1k_v37_chr2.fasta \\\n-O human_g1k_v37_chr2.dict\n\n## loop through the samples:\nfor sample in HG00097 HG00100 HG00101;\ndo\n echo \"Now analyzing: ${sample}\"\n # map the reads\n bwa mem \\\n -R \"@RG ID:${sample} PU:flowcellx_lanex SM:${sample} LB:libraryx PL:illumina\" \\\n -t 1 human_g1k_v37_chr2.fasta \\\n \"${sample}_1.fq\" \"${sample}_2.fq\" | samtools sort > \"${sample}.bam\"\n\n samtools index $sample\".bam\"\n # mark duplicates\n gatk --java-options -Xmx7g MarkDuplicates \\\n -I \"${sample}.bam\" \\\n -O \"${sample}.md.bam\" \\\n -M \"${sample}_mdmetrics.txt\"\n\n # base quality score recalibration\n gatk --java-options -Xmx7g BaseRecalibrator \\\n -R human_g1k_v37_chr2.fasta \\\n -I \"${sample}.md.bam\" \\\n --known-sites \"${ref}/1000G_phase1.snps.high_confidence.b37.chr2.vcf\" \\\n -O \"${sample}.recal.table\"\n\n gatk --java-options -Xmx7g ApplyBQSR \\\n -R human_g1k_v37_chr2.fasta \\\n -I \"${sample}.md.bam\" \\\n --bqsr-recal-file \"${sample}.recal.table\" \\\n -O \"${sample}.recal.bam\"\n\n # haplotypeCaller in -ERC mode\n gatk --java-options -Xmx7g HaplotypeCaller \\\n -R human_g1k_v37_chr2.fasta \\\n -ERC GVCF \\\n -I \"${sample}.bam\" \\\n -O \"${sample}.g.vcf\"\ndone\n\n# joint genotyping\ngatk --java-options -Xmx7g CombineGVCFs \\\n-R human_g1k_v37_chr2.fasta \\\n-V HG00097.g.vcf \\\n-V HG00100.g.vcf \\\n-V HG00101.g.vcf \\\n-O cohort.g.vcf\n\ngatk --java-options -Xmx7g GenotypeGVCFs \\\n-R human_g1k_v37_chr2.fasta \\\n-V cohort.g.vcf \\\n-O cohort.vcf\n\n# variant filtration SNPs\ngatk --java-options -Xmx7g SelectVariants \\\n-R human_g1k_v37_chr2.fasta \\\n-V cohort.vcf \\\n--select-type-to-include SNP \\\n-O cohort.snvs.vcf\n\ngatk --java-options -Xmx7g VariantFiltration \\\n-R human_g1k_v37_chr2.fasta \\\n-V cohort.snvs.vcf \\\n--filter-name QDfilter --filter-expression \"QD < 2.0\" \\\n--filter-name MQfilter --filter-expression \"MQ < 40.0\" \\\n--filter-name FSfilter --filter-expression \"FS > 60.0\" \\\n-O cohort.snvs.filtered.vcf\n\n# variant filtration indels\ngatk --java-options -Xmx7g SelectVariants \\\n-R human_g1k_v37_chr2.fasta \\\n-V cohort.vcf \\\n--select-type-to-include INDEL \\\n-O cohort.indels.vcf\n\ngatk --java-options -Xmx7g VariantFiltration \\\n-R human_g1k_v37_chr2.fasta \\\n-V cohort.indels.vcf \\\n--filter-name QDfilter --filter-expression \"QD < 2.0\" \\\n--filter-name FSfilter --filter-expression \"FS > 200.0\" \\\n-O cohort.indels.filtered.vcf\n\n# merge filtered SNPs and indels\ngatk --java-options -Xmx7g MergeVcfs \\\n-I cohort.snvs.filtered.vcf \\\n-I cohort.indels.filtered.vcf \\\n-O cohort.filtered.vcf" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html", + "href": "topics/vc/lab_vc_tetralith.html", + "title": "Variant Calling Workflow", + "section": "", + "text": "Whole genome sequencing (WGS) is a comprehensive method for analyzing entire genomes. This workshop will take you through the process of calling germline short variants (SNVs and INDELs) in WGS data from three human samples.\n\nThe first part of the workshop will guide you through a basic variant calling workflow in one sample. The goals are that you should get familiar with the bam and vcf file formats, and learn how to interpret the results of variant calling in Integrative Genomics Viewer (IGV).\nIf you have time, the next part of the workshop will show you how to perform joint variant calling in three samples. The goals here is that you should be able to interpret multi-sample vcf files and explain the differences between the g.vcf and vcf file formats. Also, if you are interested in programming, another goal is that you should learn to combine individual Linux commands into an SBATCH script.\n\nIf you have time, the last part of the workshop will take you through the GATK best practices for germline short variant detection in three samples. The goal here is that you should learn how to use GATK’s documentation so that you can analyze your own samples in the future.\n\nGeneral guide\n\n\n\n\n\n\nNote\n\n\n\n\nIn this workshop you will work on the computing cluster Tetralith at NSC.\nYou will use a singularity container (a virtual computer) that mimics the UPPMAX environment.\nIn paths, please replace <nsc_username> with your NSC username.\nIn commands, please replace <parameter> with the correct parameter, for example your input file name, output file name, directory name, etc.\nDo not copy and paste commands from the exercise to terminal, as this can result in formatting errors.\nUse tab completion.\nA line starting with # is a comment\nRunning a command without parameters will often return a help message on how to run the command.\nAfter a command is completed, please check that the desired output file was generated and that it has a reasonable size (use ls -l).\nA common mistake is to attempt to load input files that do not exist, or create output files where you don’t have permission to write.\nUse output file names that describes what was done in the command.\nIf you change the node you are working on you will need to reload the tool modules.\nGoogle errors, someone in the world has run into EXACTLY the same problem you had and asked about it on a forum somewhere." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#samples", + "href": "topics/vc/lab_vc_tetralith.html#samples", + "title": "Variant Calling Workflow", + "section": "Samples", + "text": "Samples\nThe 1000 Genomes Project ran between 2008 and 2015, creating the largest public catalogue of human variation and genotype data. In this workshop we will use low coverage whole genome sequence data from three individuals, generated in the first phase of the 1000 Genomes Project.\n\n\n\nSample\nPopulation\nSequencing technology\n\n\n\n\nHG00097\nBritish in England and Scotland\nLow coverage WGS\n\n\nHG00100\nBritish in England and Scotland\nLow coverage WGS\n\n\nHG00101\nBritish in England and Scotland\nLow coverage WGS" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#Genomicregion", + "href": "topics/vc/lab_vc_tetralith.html#Genomicregion", + "title": "Variant Calling Workflow", + "section": "Genomic region", + "text": "Genomic region\nThe LCT gene on chromosome 2 encodes the enzyme lactase, which is responsible for the metabolism of lactose in mammals. Most mammals can not digest lactose as adults, but some humans can. Genetic variants upstream of the LCT gene lead to lactase persistence, which means that lactase is expressed also in adulthood and the carrier can continue to digest lactose. The variant rs4988235, located at position chr2:136608646 in the HG19 reference genome, has been shown to lead to lactose persistence. The alternative allele (A on the forward strand and T on the reverse strand) creates a new transcription factor binding site that enables continued expression of the gene after weaning.\nIn this workshop we will use sequencing data for the region chr2:136545000-136617000 chr2:136,039,147-136,662,073 in the 3 samples listed above to illustrate variant calling in NGS data. We will use chromosome 2 from hg19 as reference genome.\nFor those interested in the details of the genetic bases for lactose tolerance, please read the first three pages of Lactose intolerance: diagnosis, genetic, and clinical factors by Mattar et al. The variant rs4988235 is here referred to as LCT-13910C>T." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#Data", + "href": "topics/vc/lab_vc_tetralith.html#Data", + "title": "Variant Calling Workflow", + "section": "Data folder on UPPMAX", + "text": "Data folder on UPPMAX\nAll input data for this exercise is located in this folder:\n\n\n/sw/courses/ngsintro/reseq/data\n\n\nThe fastq files are located in this folder:\n\n\n/sw/courses/ngsintro/reseq/data/fastq\n\n\nReference files, such as the reference genome in fasta format, are located in this folder:\n\n\n/sw/courses/ngsintro/reseq/data/ref" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#preparelaptop", + "href": "topics/vc/lab_vc_tetralith.html#preparelaptop", + "title": "Variant Calling Workflow", + "section": "Local workspace", + "text": "Local workspace\nThe majority of the analyses in this workshop will be done on the computing cluster, but you will copy some of the resulting files to your laptop. Therefore, please start by creating a folder for this workshop on your laptop. It is up to you where you want to put this, but it can for example be a folder called ngsworkflow on Desktop. You need to have write permission in this folder. The folder you create here will be referred to as local workspace throughout this workshop." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#the-nsc-cluster", + "href": "topics/vc/lab_vc_tetralith.html#the-nsc-cluster", + "title": "Variant Calling Workflow", + "section": "The NSC cluster", + "text": "The NSC cluster\nPlease connect to the Tetralith cluster at NSC using ssh:\n$ ssh -Y nsc_username@tetralith.nsc.liu.se\n\n\n\n\n\n\nNote\n\n\n\nNote that your terminal prompt changed to something like nsc_username@tetralith1 $ which means that you have entered Tetralith.\n\n\n\nInteractive session\nOn Tetralith you enter the login node, which is not intended for compute intensive tasks. You should therefore book a compute node, or in this case three cores:\n\n\ntetralith1$ interactive -A naiss2023-22-862 -t 04:00:00 -n 3\n\n\n\n\n\n\n\n\nNote\n\n\n\nYour terminal prompt changed to something like <nsc_username>@n424 $ (or another node name), which means that you are now running on one of the compute nodes.\n\n\n\n\nUPPMAX singularity container\nWe will use a singularity container (a virtual computer) that mimics the UPPMAX computing environment. Once you have started the singularity container your environment will look exactly as on UPPMAX, and the software used in this workshop will be available through the module system.\nUse this command to start the singularity container:\n\n\nn424$ singularity shell -B /proj/naiss2023-22-862/users:/proj/naiss2023-22-862/nobackup /proj/naiss2023-22-862/ngsintro.sif\n\n\n\n\n\n\n\n\nNote\n\n\n\nNote that your terminal prompt changed to something like <nsc_username>@offline-uppmax$. This means that you have moved into a “virtual computer” that mimics the UPPMAX environment.\n\n\nIn the singularity container type this to make modules based on Java to load properly:\n\n\nsource /uppmax_init\n\n\nTo close the singularity container later on just type exit in the terminal, but don’t do that now.\n\n\nCluster workspace\nWhile running the UPPMAX singularity container, create a workspace folder for this exercise and move into it:\n\n\noffline-uppmax$ mkdir /proj/naiss2023-22-862/nobackup/<nsc_username>/ngsworkflow\noffline-uppmax$ cd /proj/naiss2023-22-862/nobackup/<nsc_username>/ngsworkflow\n\n\nThe folder you just created will be referred to as your cluster workspace throughout this workshop.\nThe cluster workspace can be reached also from outside of the UPPMAX singularity container, in this folder on Tetralith:\n\n\ntetralith$ /proj/naiss2023-22-862/users/<nsc_username>/ngsworkflow\n\n\nThis is the path you must use when downloading files to your local workspace later on.\n\n\n\n\n\n\n\nNote\n\n\n\nNote: The rest of the instructions assumes that you are running the UPPMAX singularity container from an interactive session on Tetralith, and that you are located in your cluster workspace, unless noted otherwise.\n\n\n\n\nSymbolic links to data\nThe raw data files are located in the Data folder described above. Instead of copying the files to your workspace you should create symbolic links (soft-links) to them. Soft-linking files and folders allows you to work with them as if they were in your current directory, but without multiplying them.\nCreate a symbolic link to the reference genome in your workspace:\n\n\noffline-uppmax$ ln -s /sw/courses/ngsintro/reseq/data/ref/human_g1k_v37_chr2.fasta\n\n\nDo the same with the fastq files:\n\n\noffline-uppmax$ ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_1.fq\noffline-uppmax$ ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_2.fq\noffline-uppmax$ ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_1.fq\noffline-uppmax$ ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_2.fq\noffline-uppmax$ ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_1.fq\noffline-uppmax$ ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_2.fq\n\n\n\n\nAccessing programs\nWe will use several programs that are installed in the module system on UPPMAX. These modules must be loaded every time you start the singularity container.\nFirst load the bioinfo-tools module:\noffline-uppmax$ module load bioinfo-tools\nThis makes it possible to load the individual programs:\noffline-uppmax$ module load FastQC/0.11.8\noffline-uppmax$ module load bwa/0.7.17\noffline-uppmax$ module load samtools/1.10\noffline-uppmax$ module load GATK/4.1.4.1\n\n\n\n\n\n\nNote\n\n\n\nYou don’t have to specify which versions of the tools to use, but is recommended to do so for reproducibility if you want to rerun the exact same analyses later.\n\n\nWhen loading the module GATK/4.1.4.1 you may get a warning message about the fact that GATK commands have been updated since the previous version of GATK. This is fine and you don’t have to do anything about it." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#index-the-genome", + "href": "topics/vc/lab_vc_tetralith.html#index-the-genome", + "title": "Variant Calling Workflow", + "section": "Index the genome", + "text": "Index the genome\nTools that compare short reads with a large reference genome needs indexes of the reference genome to work efficiently. You therefore need to create index files for each tool.\nGenerate BWA index files:\noffline-uppmax$ bwa index -a bwtsw human_g1k_v37_chr2.fasta\nCheck to see that several new files have been created using ls -l.\nGenerate a samtools index:\noffline-uppmax$ samtools faidx human_g1k_v37_chr2.fasta\nCheck to see what file(s) were created using ls -lrt.\nGenerate a GATK sequence dictionary:\noffline-uppmax$ gatk --java-options -Xmx7g CreateSequenceDictionary -R human_g1k_v37_chr2.fasta -O human_g1k_v37_chr2.dict\nAgain, check what file(s) were created using ls -lrt." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#aligning-reads", + "href": "topics/vc/lab_vc_tetralith.html#aligning-reads", + "title": "Variant Calling Workflow", + "section": "1.1 Aligning reads", + "text": "1.1 Aligning reads\n\n1.1.1 BWA mem\nIn the Cluster workspace you should now use BWA mem to align the reads to the reference genome.\nAt the same time, you should add something called read groups to the reads in the fastq files. Read groups allow us to trace various technical features, such as which flow cell was used to generate the reads, and this is needed in order to perform variant calling with HaplotypeCaller. You are not expected to learn all the details of read groups here, but if you are interested in more information please read this article at GATK-forum. The samples in this workshop come from the 1000 Genomes project, and we don’t know how these reads were generated. Let’s assume that each fastq file was generated from one library preparation (called libraryx), derived from one biological sample (called HG00097), that was run on one lane of a flow cell (called lanex_flowcellx) in the Illumina machine, and create a read group with id readgroupx that contains this information.\nThe output from BWA should be parsed to samtools sort, which sorts the sam file according to chromosome position and then converts the sam file to the binary bam format. This saves space since no intermediary sam file is created.\nPlease use this command for all of this:\noffline-uppmax$ bwa mem -R \"@RG\\\\tID:readgroupx\\\\tPU:lanex_flowcellx\\\\tSM:HG00097\\\\tLB:libraryx\\\\tPL:illumina\" -t 1 human_g1k_v37_chr2.fasta HG00097_1.fq HG00097_2.fq | samtools sort > HG00097.bam\nWhere -t 1 is the number of threads, which should be equal to the number of cores you booked. If you would have analysed the entire genome more threads would have been necessary.\nYou have to use a file redirect > for the output, otherwise it will be written to stdout (your screen).\nPlease check that the expected output file was generated and that it has content using ls -lrt.\nNext you need to index the output bam file so that programs can randomly access the sorted data without reading the whole file. This command creates an index file with the same name as the input bam file, except with a .bai extension:\noffline-uppmax$ samtools index HG00097.bam\nPlease check what output file was generated this time.\n\n\n1.1.2 Check bam with samtools\nThe bam file is binary so we cannot read it, but we can view it with samtools view. The header section of the bam file can be viewed separately with the -H flag:\noffline-uppmax$ samtools view -H HG00097.bam \nTo look at the reads in the bam file just use samtools view without the -H. This will display the entire bam file which is quite large, so if you just want to look at the first 5 lines (for example) you can combine samtools view with head:\noffline-uppmax$ samtools view HG00097.bam | head -n 5 \nFor help with interpreting the bam file, please look at the sam/bam format definition at Sequence Alignment/Map Format Specification.\n\n\n1.1.3 Questions\n\nWhat does “SO:coordinate” in the “(HD?)” tag on the first line of the bam file mean?\n\nWhat does “SN:2” and “LN:243199373” in the “(SQ?) tag mean?\nWhat is encoded in the (RG?) tag?\n\nWhat is the leftmost mapping position of the first read in the bamfile?\n\n\n\n1.1.4 Check bam in IGV\nInstall IGV\nIntegrated Genomics Viewer (IGV) provides an interactive visualisation of the reads in a bam file. Here we will show you how to run IGV on your laptop. If you have not used IGV on your laptop before, then go to the IGV download page, and follow the instructions to download it. It will prompt you to fill in some information and agree to license. Launch the viewer through web start. The 1.2 Gb version should be sufficient for our data.\nDownload the bam file\nOpen a new terminal window on your laptop and navigate to your local workspace, but do not log in to NSC. Download the .bam and .bam.bai files you just generated with this command:\n\n\nscp <nsc_username>@tetralith.nsc.uu.se:/proj/naiss2023-22-862/users/<nsc_username>/ngsworkflow/HG00097.bam* .\n\n\nCheck that the files are now present in your local workspace using ls -lrt.\nLook at the bam file in IGV\n\nIn IGV, go to the popup menu in the upper left and set it to Human hg19.\n\nIn the Tools menu, select Run igvtools. Choose the command Count and then use the Browse button next to the Input File line to select the bam file (not the bai) that you just downloaded. It will autofill the output file. Hit the Run button. This generates a .tdf file that allows you to see the coverage value for our bam file even at zoomed out views. Close the igvtools window.\n\nIn the File menu, select Load from File and select your BAMs (not the .bai or the .tdf), which should appear in the tracks window. You will have to zoom in before you can see any reads. You can either select a region by click and drag, or by typing a region or a gene name in the text box at the top. Remember that we have data for the region chr2:136545000-136617000.\n\n\n\n1.1.5 Questions\n\nWhat is the read length?\n\nHow can you estimate the coverage at a specific position in IGV?\nWhich RefSeq Genes are located within the region chr2:136545000-136617000?" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#variant-calling", + "href": "topics/vc/lab_vc_tetralith.html#variant-calling", + "title": "Variant Calling Workflow", + "section": "1.2 Variant Calling", + "text": "1.2 Variant Calling\n\n1.2.1 HaplotypeCaller\nNow we will detect short variants in the bam file using GATK’s HaplotypeCaller. Go to your Cluster workspace and run:\noffline-uppmax$ gatk --java-options -Xmx7g HaplotypeCaller -R human_g1k_v37_chr2.fasta -I HG00097.bam -O HG00097.vcf \nCheck what new files were generated with ls -lrt.\n\n\n1.2.2 Explore the vcf file\nNow you have your first vcf file containing the raw variants in the region chr2:136545000-136617000 in sample HG00097. Please look at the vcf file with less and try to understand its structure.\nVCF files contains meta-information lines starting with ##, a header line starting with #CHROM, and then data lines each containing information about one variant position in the genome. The header line defines the columns of the data lines, and to view the header line you can type this command:\noffline-uppmax$ grep '#CHROM' HG00097.vcf\nThe meta-information lines starting with ##INFO defines how the data in the INFO column is encoded, and the meta-information lines starting with ##FORMAT defines how the data in the FORMAT column is encoded. To view the meta-information lines describing the INFO column use:\noffline-uppmax$ grep '##INFO' HG00097.vcf\nTo view the meta-information lines describing the FORMAT column use:\noffline-uppmax$ grep '##FORMAT' HG00097.vcf\nNow lets look at the details of one specific genetic variant at position 2:136545844:\noffline-uppmax$ grep '136545844' HG00097.vcf\nFor more detailed information about vcf files please have a look at The Variant Call Format specification.\n\n\n1.2.3 Questions\n\nWhat column of the VCF file contains genotype information for the sample HG00097?\nWhat does GT in the FORMAT column of the data lines mean?\nWhat genotype does the sample HG00097 have at position 2:136545844?\nWhat does AD in the FORMAT column of the data lines mean?\nWhat are the allelic depths for the reference and alternative alles in sample HG00097 at position 2:136545844?\nHow many genetic variants was detected in the sample? The linux command grep -v \"#\" HG00097.vcf | wc -l extracts all lines in HG00097.vcf that don’t start with “#”, and counts these lines.\n\n\n\n1.2.4 Check vcf in IGV\nDownload the vcf file and its index to the local workspace on your laptop, just like you did with the bam file and its index earlier. Open a new terminal window on your laptop and navigate to your local workspace, but do not log in to NSC. Download the files that you just generated with:\n\n\nscp <nsc_username>@tetralith.nsc.uu.se:/proj/naiss2023-22-862/users/<nsc_username>/ngsworkflow/HG00097.vcf* .\n\n\nPlease replace <nsc_nsc_username> with your NSC user name.\nNote that the * in the end of the file name means that you will download all files that start with HG00097.vcf, so you will also download the vcf index.\nCheck that the files were properly downloaded to your local workspace using ls -lrt.\nIn IGV, in the File menu, select Load from File and select your vcf file (not the .idx file) and the bam file (not the .bai file) that you downloaded earlier. The vcf and bam files should appear in the tracks window. You will now see all the variants called in HG00097. You can view all variants in the LCT gene by typing the gene name in the search box, and you can look specifically at the variant at position chr2:136545844 by typing that position in the search box.\n\n\n1.2.5 Questions\n\nHover the mouse over the upper row of the vcf track. What is the reference and alternative alleles of the variant at position chr2:136545844?\nHover the mouse over the lower row of the vcf track and look under “Genotype Information”. What genotype does HG00097 have at position chr2:136545844? Is this the same as you found by looking directly in the vcf file in question 10?\nLook in the bam track and count the number of reads that have “T” and “C”, respectively, at position chr2:136545844. How is this information captured under “Genotype Attributes”? (Again, hoover the mouse over the lower row of the vcf track.)" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#bwa-mem", + "href": "topics/vc/lab_vc_tetralith.html#bwa-mem", + "title": "Variant Calling Workflow", + "section": "2.1 BWA mem", + "text": "2.1 BWA mem\nRun BWA mem for all three samples in the data set. BWA mem should be run exactly as above but with the new sample names. Please note that you also need to adjust the SM field in the read group so that it matches the new sample name, otherwise the joint genotyping step will not work properly.\nIf you run out of time, please click below to get paths to precomputed bam files.\n\n\n/sw/courses/ngsintro/reseq/data/bam/HG00097.bam\n/sw/courses/ngsintro/reseq/data/bam/HG00100.bam\n/sw/courses/ngsintro/reseq/data/bam/HG00101.bam" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#generategvcf", + "href": "topics/vc/lab_vc_tetralith.html#generategvcf", + "title": "Variant Calling Workflow", + "section": "2.2 Generate g.vcf files", + "text": "2.2 Generate g.vcf files\nHaplotypeCaller should also be run for all three samples, but this time the output for each sample needs to be in g.vcf format. This is accomplished with a small change in the HaploteypCaller command:\noffline-uppmax$ gatk --java-options -Xmx7g HaplotypeCaller -R human_g1k_v37_chr2.fasta -ERC GVCF -I <sample.bam> -O <sample>.g.vcf \nPlease replace with the real sample names.\nIf you run out of time, please click below to get paths to the precomputed g.vcf files.\n\n\n/sw/courses/ngsintro/reseq/data/vcf/HG00097.g.vcf\n/sw/courses/ngsintro/reseq/data/vcf/HG00100.g.vcf\n/sw/courses/ngsintro/reseq/data/vcf/HG00101.g.vcf" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#jointgenotyping", + "href": "topics/vc/lab_vc_tetralith.html#jointgenotyping", + "title": "Variant Calling Workflow", + "section": "2.3 Joint genotyping", + "text": "2.3 Joint genotyping\nOnce you have the g.vcf files for all samples you should perform joint genotype calling. To do this you first need to combine all individual .g.vcf files to one file using CombineGVCFs:\noffline-uppmax$ gatk --java-options -Xmx7g CombineGVCFs -R human_g1k_v37_chr2.fasta -V <sample1>.g.vcf -V <sample2>.g.vcf -V <sample3>.g.vcf -O cohort.g.vcf\nPlease replace <sample1>, <sample2>, <sample3> with the real sample names.\nThen run GATK’s GenoteypeGVC to generate a vcf file:\noffline-uppmax$ gatk --java-options -Xmx7g GenotypeGVCFs -R human_g1k_v37_chr2.fasta -V cohort.g.vcf -O cohort.vcf\nIf you run out of time, please click below to get paths to the precomputed cohort.g.vcf and cohort.vcf files.\n\n\n/sw/courses/ngsintro/reseq/data/vcf/cohort.g.vcf\n/sw/courses/ngsintro/reseq/data/vcf/cohort.vcf\n\n\n\n2.3.1 Questions\n\nHow many data lines do the cohort.g.vcf file have? You can use the Linux command grep -v \"#\" cohort.g.vcf to extract all lines in “cohort.g.vcf” that don’t start with “#”, then |, and then wc -l to count those lines.\n\nHow many data lines do the cohort.vcf file have?\n\nExplain the difference in number of data lines.\n\nLook at the header line of the cohort.vcf file. What columns does it have?\nWhat is encoded in the last three columns of the data lines?" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#sbatchscript", + "href": "topics/vc/lab_vc_tetralith.html#sbatchscript", + "title": "Variant Calling Workflow", + "section": "2.4 SBATCH script", + "text": "2.4 SBATCH script\n\n\n\n\n\n\nOptional\n\n\n\nThis section is only for those of you who want to try to run all steps automatically in bash scripts. Below is a skeleton script that can be used as a template. Please modify it to run all the steps in part two of this workshop. You might find it helpful to try each step for one sample in the interactive terminal, so that you know that a particular command is working, before you incorporate it in the script.\n#!/bin/bash\nmodule load bioinfo-tools\nmodule load bwa/0.7.17\nmodule load samtools/1.10\nmodule load GATK/4.1.4.1\n## loop through the samples:\nfor sample in HG00097 HG00100 HG00101;\ndo\n echo \"Now analyzing: \"$sample\n #Fill in the code for running bwa-mem for each sample here\n #Fill in the code for samtools index for each sample here \n #Fill in the code for HaplotypeCaller for each sample here\ndone\n#Fill in the code for CombineGVCFs for all samples here\n#Fill in the code for GenotypeGVCFs here\nPlease save the sbatch script in your cluster folder and call it “joint_genotyping.sh” or similar. Make the script executable by this command:\nchmod u+x joint_genotyping.sh\nUse this command to run the script in the singularity container:\n./joint_genotyping.sh\nIf you would like more help with creating the bash script, please look at our example solution:\n\n\n#!/bin/bash\n\nmodule load bioinfo-tools\nmodule load bwa/0.7.17\nmodule load samtools/1.10\nmodule load GATK/4.1.4.1\n\nfor sample in HG00097 HG00100 HG00101;\ndo\n echo \"Now analyzing: \"$sample\n bwa mem -R \"@RG\\tID:readgroupx\\tPU:flowcellx_lanex\\tSM:\"$sample\"\\tLB:libraryx\\tPL:illumina\" -t 1 human_g1k_v37_chr2.fasta $sample\"_1.fq\" $sample\"_2.fq\" | samtools sort > $sample\".bam\"\n samtools index $sample\".bam\"\n gatk --java-options -Xmx7g HaplotypeCaller -R human_g1k_v37_chr2.fasta -ERC GVCF -I $sample\".bam\" -O $sample\".g.vcf\"\ndone\ngatk --java-options -Xmx7g CombineGVCFs -R human_g1k_v37_chr2.fasta -V HG00097.g.vcf -V HG00100.g.vcf -V HG00101.g.vcf -O cohort.g.vcf\ngatk --java-options -Xmx7g GenotypeGVCFs -R human_g1k_v37_chr2.fasta -V cohort.g.vcf -O cohort.vcf\n\n\nPlease answer the questions above." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#check-combined-vcf-file-in-igv", + "href": "topics/vc/lab_vc_tetralith.html#check-combined-vcf-file-in-igv", + "title": "Variant Calling Workflow", + "section": "2.5 Check combined vcf file in IGV", + "text": "2.5 Check combined vcf file in IGV\nDownload the file cohort.vcf and its index, as well as HG00100.bam and HG00101.bam and their indexes to your local workspace as described above. Then open cohort.vcf, HG00097.bam, HG00100.bam and HG00101.bam in IGV as described above. This time lets look at the variant rs4988235, located at position chr2:136608646 in the HG19 reference genome, that has been shown to lead to lactose persistence.\n\n2.5.1 Questions\n\nWhat is the reference and alternative alleles at chr2:136608646?\nWhat genotype do the three samples have at chr2:136608646? Note how genotypes are color coded in IGV.\nShould any of the individuals avoid drinking milk?\n\nNow compare the data shown in IGV with the data in the VCF file. Extract the row for the chr2:136608646 variant in the cohort.vcf file, for example using grep '136608646' cohort.vcf. What columns of the vcf file contain the information shown in the upper part of the vcf track in IGV?\nWhat columns of the vcf file contain the information shown in the lower part of the vcf track?\nZoom out so that you can see the MCM6 and LCT genes. Is the variant at chr2:136608646 locate within the LCT gene?\nIf you are interested in how this variant affects lactose tolerance please read the article by Mattar et al presented above, or in OMIM." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#bwa-mem-1", + "href": "topics/vc/lab_vc_tetralith.html#bwa-mem-1", + "title": "Variant Calling Workflow", + "section": "3.1 BWA mem", + "text": "3.1 BWA mem\nRun BWA mem for all three samples in the data set. BWA mem should be run exactly as above but with the new sample names. Please note that you also need to adjust the SM field in the read group so that it matches the new sample name." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#mark-duplicates", + "href": "topics/vc/lab_vc_tetralith.html#mark-duplicates", + "title": "Variant Calling Workflow", + "section": "3.2 Mark Duplicates", + "text": "3.2 Mark Duplicates\nSometimes the same DNA fragment is sequenced multiple times, which leads to multiple reads from the same fragment in the fastq file. This can occur due to PCR amplification in the library preparation, or if one read cluster is incorrectly detected as multiple clusters by the sequencing instrument. If a duplicated read contains a genetic variant, the ratio of the two alleles might be obscured, which can lead to incorrect genotyping. It is therefore recommended (in most cases) to mark duplicate reads so that they are counted as one during genotyping.\nPlease read about Picard’s MarkDuplicates here. Picard’s MarkDuplicates has recently been incorporated into the GATK suite, but the usage example in GATKs documentation still describes how to call it via the stand alone Picard program. A usage example for the version of MarkDuplicates that is incorporated in GATK is (with this you don’t have to load the Picard module):\noffline-uppmax$ gatk --java-options -Xmx7g MarkDuplicates \\\n -I input.bam \\\n -O marked_duplicates.bam \\\n -M marked_dup_metrics.txt\nIf you would like more help you can sneak peek at our example solution for HG00097 below.\n\n\noffline-uppmax$ gatk --java-options -Xmx7g MarkDuplicates -I HG00097.bam -O HG00097.md.bam -M HG00097_mdmetrics.txt" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#recalibrate-base-quality-scores", + "href": "topics/vc/lab_vc_tetralith.html#recalibrate-base-quality-scores", + "title": "Variant Calling Workflow", + "section": "3.3 Recalibrate Base Quality Scores", + "text": "3.3 Recalibrate Base Quality Scores\nAnother source of error is systematic biases in the assignment of base quality scores by the sequencing instrument. This can be corrected by GATK’s Base Quality Score Recalibration. In short, you first use BaseRecalibrator to build a recalibration model, and then ApplyBQSR to recalibrate the base qualities in your bam file.\nBaseRecalibrator requires a file with known SNPs as input. This file is available in the data folder on UPPMAX:\n\n\n/sw/courses/ngsintro/reseq/data/ref/1000G_phase1.snps.high_confidence.b37.chr2.vcf\n\n\nPlease use GATK’s documentation to recalibrate the base quality scores in your data. If you would like more help you can sneak peek at our example solution for HG00097 below.\n\n\noffline-uppmax$ gatk --java-options -Xmx7g BaseRecalibrator -R human_g1k_v37_chr2.fasta -I HG00097.md.bam> --known-sites /sw/courses/ngsintro/reseq/data/ref/1000G_phase1.snps.high_confidence.b37.chr2.vcf -O HG00097.recal.table\noffline-uppmax$ gatk --java-options -Xmx7g ApplyBQSR -R human_g1k_v37_chr2.fasta -I HG00097.md.bam --bqsr-recal-file HG00097.recal.table -O HG00097.recal.bam" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#generate-g.vcf-files", + "href": "topics/vc/lab_vc_tetralith.html#generate-g.vcf-files", + "title": "Variant Calling Workflow", + "section": "3.4 Generate g.vcf files", + "text": "3.4 Generate g.vcf files\nHaplotypeCaller should also be run for all three samples, and the output should be in g.vcf exactly as described above. This time use recalibrated bam files as input." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#joint-genotyping", + "href": "topics/vc/lab_vc_tetralith.html#joint-genotyping", + "title": "Variant Calling Workflow", + "section": "3.5 Joint genotyping", + "text": "3.5 Joint genotyping\nOnce you have the g.vcf files for all samples you should perform joint genotype calling. This should be done with the commands CombineGVCFs and GenotypeGVCFs exactly as described above, but you should use the g.vcf files generated from the recalibrated bam files as input." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#variant-filtering", + "href": "topics/vc/lab_vc_tetralith.html#variant-filtering", + "title": "Variant Calling Workflow", + "section": "3.6 Variant Filtering", + "text": "3.6 Variant Filtering\nHaplotypeCaller is designed to be very sensitive, which is good because it minimises the chance of missing real variants. However, it means that the number of false positives can be quite large, so we need to filter the raw callset. GATK offers two ways to filter variants:\n\nThe variant quality score recalibration (VQSR) method uses machine learning to identify variants that are likely to be real. This is the best method if you have a lot of data, for example one whole genome sequence sample or several whole exome samples.\nIf you have less data you can use hard filters as described here.\n\nSince we have very little data we will use hard filters. The parameters are slightly different for SNVs and INDELs, so you need to first select all SNVs using SelectVariants and filter them using VariantFiltration with the parameters suggested for SNVs. Then select all INDELs and filter them with the parameters suggested for INDELs. Finally merge the SNVs and INDELs to get all variants in one file using MergeVCFs. If you would like more help you can sneak peek at our example solution for HG00097 below.\nFilter SNVs:\n\n\noffline-uppmax$ gatk --java-options -Xmx7g SelectVariants \n -R human_g1k_v37_chr2.fasta \n -V cohort.vcf \n --select-type-to-include SNP \n -O cohort.snvs.vcf\n \noffline-uppmax$ gatk --java-options -Xmx7g VariantFiltration \n -R human_g1k_v37_chr2.fasta \n -V cohort.snvs.vcf \n -O cohort.snvs.filtered.vcf \n --filter-name QDfilter --filter-expression \"QD < 2.0\" \n --filter-name MQfilter --filter-expression \"MQ < 40.0\" \n --filter-name FSfilter --filter-expression \"FS > 60.0\"\n\n\nFilter INDELs:\n\n\noffline-uppmax$ gatk --java-options -Xmx7g SelectVariants \n -R human_g1k_v37_chr2.fasta \n -V cohort.vcf \n --select-type-to-include INDEL \n -o cohort.indels.vcf\n\noffline-uppmax$ gatk --java-options -Xmx7g VariantFiltration \n -R human_g1k_v37_chr2.fasta \n -V cohort.indels.vcf \n -O cohort.indels.filtered.vcf \n --filter-name QDfilter --filter-expression \"QD < 2.0\" \n --filter-name FSfilter --filter-expression \"FS > 200.0\"\n\n\nMerge filtered SNVs and INDELs:\n\n\noffline-uppmax$ gatk --java-options -Xmx7g MergeVcfs -I cohort.snvs.filtered.vcf -I cohort.indels.filtered.vcf -O cohort.filtered.vcf\n\n\nOpen your filtered vcf with less and page through it. It still has all the variant lines, but the FILTER column that was blank before is now filled in, with PASS or a list of the filters it failed. Note also that the filters that were run are described in the header section." + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#precomputed-files", + "href": "topics/vc/lab_vc_tetralith.html#precomputed-files", + "title": "Variant Calling Workflow", + "section": "3.7 Precomputed files", + "text": "3.7 Precomputed files\nIf you run out of time, please click below to get the path to precomputed bam and vcf files for the GATK’s best practices section.\n\n\nPath to intermediary and final bam files: /sw/courses/ngsintro/reseq/data/best_practise_bam\nPath to intermediary and final vcf files: /sw/courses/ngsintro/reseq/data/best_practise_vcf" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#bpscript", + "href": "topics/vc/lab_vc_tetralith.html#bpscript", + "title": "Variant Calling Workflow", + "section": "3.8 SBATCH script", + "text": "3.8 SBATCH script\nWe recommend you to incorporate the new steps into an SBATCH script similar to the one you created above for joint variant calling. Please try to complete the script for GATK’s best practices workflow. If you run out of time you can sneak peek at our example solution below.\n\n\n#!/bin/bash\n\n## load modules\nmodule load bioinfo-tools\nmodule load bwa/0.7.17\nmodule load samtools/1.10\nmodule load GATK/4.1.4.1\n\n# define path to reference genome\nref=\"/sw/courses/ngsintro/reseq/data/ref\"\n\n# make symbolic links\nln -s /sw/courses/ngsintro/reseq/data/ref/human_g1k_v37_chr2.fasta\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_2.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_2.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_1.fq\nln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_2.fq\n\n# index reference genome\nbwa index -a bwtsw human_g1k_v37_chr2.fasta\nsamtools faidx human_g1k_v37_chr2.fasta\ngatk --java-options -Xmx7g CreateSequenceDictionary -R human_g1k_v37_chr2.fasta -O human_g1k_v37_chr2.dict\n\n## loop through the samples:\nfor sample in HG00097 HG00100 HG00101;\ndo\n echo \"Now analyzing: ${sample}\"\n # map the reads\n bwa mem -R \"@RG\\tID:readgroupx\\tPU:flowcellx_lanex\\tSM:\"$sample\"\\tLB:libraryx\\tPL:illumina\" -t 1 human_g1k_v37_chr2.fasta $sample\"_1.fq\" $sample\"_2.fq\" | samtools sort > $sample\".bam\"\n samtools index $sample\".bam\"\n # mark duplicates\n gatk --java-options -Xmx7g MarkDuplicates -I $sample\".bam\" -O $sample\".md.bam\" -M $sample\"_mdmetrics.txt\"\n # base quality score recalibration\n gatk --java-options -Xmx7g BaseRecalibrator -R human_g1k_v37_chr2.fasta -I $sample\".md.bam\" --known-sites $ref\"/1000G_phase1.snps.high_confidence.b37.chr2.vcf\" -O $sample\".recal.table\"\n gatk --java-options -Xmx7g ApplyBQSR -R human_g1k_v37_chr2.fasta -I $sample\".md.bam\" --bqsr-recal-file $sample\".recal.table\" -O $sample\".recal.bam\"\n # haplotypeCaller in -ERC mode\n gatk --java-options -Xmx7g HaplotypeCaller -R human_g1k_v37_chr2.fasta -ERC GVCF -I $sample\".bam\" -O $sample\".g.vcf\" \ndone\n\n# joint genotyping\ngatk --java-options -Xmx7g CombineGVCFs -R human_g1k_v37_chr2.fasta -V HG00097.g.vcf -V HG00100.g.vcf -V HG00101.g.vcf -O cohort.g.vcf\ngatk --java-options -Xmx7g GenotypeGVCFs -R human_g1k_v37_chr2.fasta -V cohort.g.vcf -O cohort.vcf\n# variant filtration SNPs\ngatk --java-options -Xmx7g SelectVariants -R human_g1k_v37_chr2.fasta -V cohort.vcf --select-type-to-include SNP -O cohort.snvs.vcf\ngatk --java-options -Xmx7g VariantFiltration -R human_g1k_v37_chr2.fasta -V cohort.snvs.vcf -O cohort.snvs.filtered.vcf --filter-name QDfilter --filter-expression \"QD < 2.0\" --filter-name MQfilter --filter-expression \"MQ < 40.0\" --filter-name FSfilter --filter-expression \"FS > 60.0\"\n# variant filtration indels\ngatk --java-options -Xmx7g SelectVariants -R human_g1k_v37_chr2.fasta -V cohort.vcf --select-type-to-include INDEL -O cohort.indels.vcf\ngatk --java-options -Xmx7g VariantFiltration -R human_g1k_v37_chr2.fasta -V cohort.indels.vcf -O cohort.indels.filtered.vcf --filter-name QDfilter --filter-expression \"QD < 2.0\" --filter-name FSfilter --filter-expression \"FS > 200.0\"\n# merge filtered SNPs and indels\ngatk --java-options -Xmx7g MergeVcfs -I cohort.snvs.filtered.vcf -I cohort.indels.filtered.vcf -O cohort.filtered.vcf" + }, + { + "objectID": "topics/vc/lab_vc_tetralith.html#questions-5", + "href": "topics/vc/lab_vc_tetralith.html#questions-5", + "title": "Variant Calling Workflow", + "section": "3.9 Questions", + "text": "3.9 Questions\n\nHow many variants are present in the cohort.filtered.vcf file?\n\nHow many variants have passed the filters?\n\nLook at the variants that did not pass the filters using grep -v 'PASS' cohort.filtered.vcf. Try to understand why these variants didn’t pass the filter." + } +] \ No newline at end of file diff --git a/2311/site_libs/Proj4Leaflet-1.0.1/proj4leaflet.js b/2311/site_libs/Proj4Leaflet-1.0.1/proj4leaflet.js new file mode 100644 index 00000000..eaa650c1 --- /dev/null +++ b/2311/site_libs/Proj4Leaflet-1.0.1/proj4leaflet.js @@ -0,0 +1,272 @@ +(function (factory) { + var L, proj4; + if (typeof define === 'function' && define.amd) { + // AMD + define(['leaflet', 'proj4'], factory); + } else if (typeof module === 'object' && typeof module.exports === "object") { + // Node/CommonJS + L = require('leaflet'); + proj4 = require('proj4'); + module.exports = factory(L, proj4); + } else { + // Browser globals + if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined') + throw 'Leaflet and proj4 must be loaded first'; + factory(window.L, window.proj4); + } +}(function (L, proj4) { + if (proj4.__esModule && proj4.default) { + // If proj4 was bundled as an ES6 module, unwrap it to get + // to the actual main proj4 object. + // See discussion in https://github.com/kartena/Proj4Leaflet/pull/147 + proj4 = proj4.default; + } + + L.Proj = {}; + + L.Proj._isProj4Obj = function(a) { + return (typeof a.inverse !== 'undefined' && + typeof a.forward !== 'undefined'); + }; + + L.Proj.Projection = L.Class.extend({ + initialize: function(code, def, bounds) { + var isP4 = L.Proj._isProj4Obj(code); + this._proj = isP4 ? code : this._projFromCodeDef(code, def); + this.bounds = isP4 ? def : bounds; + }, + + project: function (latlng) { + var point = this._proj.forward([latlng.lng, latlng.lat]); + return new L.Point(point[0], point[1]); + }, + + unproject: function (point, unbounded) { + var point2 = this._proj.inverse([point.x, point.y]); + return new L.LatLng(point2[1], point2[0], unbounded); + }, + + _projFromCodeDef: function(code, def) { + if (def) { + proj4.defs(code, def); + } else if (proj4.defs[code] === undefined) { + var urn = code.split(':'); + if (urn.length > 3) { + code = urn[urn.length - 3] + ':' + urn[urn.length - 1]; + } + if (proj4.defs[code] === undefined) { + throw 'No projection definition for code ' + code; + } + } + + return proj4(code); + } + }); + + L.Proj.CRS = L.Class.extend({ + includes: L.CRS, + + options: { + transformation: new L.Transformation(1, 0, -1, 0) + }, + + initialize: function(a, b, c) { + var code, + proj, + def, + options; + + if (L.Proj._isProj4Obj(a)) { + proj = a; + code = proj.srsCode; + options = b || {}; + + this.projection = new L.Proj.Projection(proj, options.bounds); + } else { + code = a; + def = b; + options = c || {}; + this.projection = new L.Proj.Projection(code, def, options.bounds); + } + + L.Util.setOptions(this, options); + this.code = code; + this.transformation = this.options.transformation; + + if (this.options.origin) { + this.transformation = + new L.Transformation(1, -this.options.origin[0], + -1, this.options.origin[1]); + } + + if (this.options.scales) { + this._scales = this.options.scales; + } else if (this.options.resolutions) { + this._scales = []; + for (var i = this.options.resolutions.length - 1; i >= 0; i--) { + if (this.options.resolutions[i]) { + this._scales[i] = 1 / this.options.resolutions[i]; + } + } + } + + this.infinite = !this.options.bounds; + + }, + + scale: function(zoom) { + var iZoom = Math.floor(zoom), + baseScale, + nextScale, + scaleDiff, + zDiff; + if (zoom === iZoom) { + return this._scales[zoom]; + } else { + // Non-integer zoom, interpolate + baseScale = this._scales[iZoom]; + nextScale = this._scales[iZoom + 1]; + scaleDiff = nextScale - baseScale; + zDiff = (zoom - iZoom); + return baseScale + scaleDiff * zDiff; + } + }, + + zoom: function(scale) { + // Find closest number in this._scales, down + var downScale = this._closestElement(this._scales, scale), + downZoom = this._scales.indexOf(downScale), + nextScale, + nextZoom, + scaleDiff; + // Check if scale is downScale => return array index + if (scale === downScale) { + return downZoom; + } + if (downScale === undefined) { + return -Infinity; + } + // Interpolate + nextZoom = downZoom + 1; + nextScale = this._scales[nextZoom]; + if (nextScale === undefined) { + return Infinity; + } + scaleDiff = nextScale - downScale; + return (scale - downScale) / scaleDiff + downZoom; + }, + + distance: L.CRS.Earth.distance, + + R: L.CRS.Earth.R, + + /* Get the closest lowest element in an array */ + _closestElement: function(array, element) { + var low; + for (var i = array.length; i--;) { + if (array[i] <= element && (low === undefined || low < array[i])) { + low = array[i]; + } + } + return low; + } + }); + + L.Proj.GeoJSON = L.GeoJSON.extend({ + initialize: function(geojson, options) { + this._callLevel = 0; + L.GeoJSON.prototype.initialize.call(this, geojson, options); + }, + + addData: function(geojson) { + var crs; + + if (geojson) { + if (geojson.crs && geojson.crs.type === 'name') { + crs = new L.Proj.CRS(geojson.crs.properties.name); + } else if (geojson.crs && geojson.crs.type) { + crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code); + } + + if (crs !== undefined) { + this.options.coordsToLatLng = function(coords) { + var point = L.point(coords[0], coords[1]); + return crs.projection.unproject(point); + }; + } + } + + // Base class' addData might call us recursively, but + // CRS shouldn't be cleared in that case, since CRS applies + // to the whole GeoJSON, inluding sub-features. + this._callLevel++; + try { + L.GeoJSON.prototype.addData.call(this, geojson); + } finally { + this._callLevel--; + if (this._callLevel === 0) { + delete this.options.coordsToLatLng; + } + } + } + }); + + L.Proj.geoJson = function(geojson, options) { + return new L.Proj.GeoJSON(geojson, options); + }; + + L.Proj.ImageOverlay = L.ImageOverlay.extend({ + initialize: function (url, bounds, options) { + L.ImageOverlay.prototype.initialize.call(this, url, null, options); + this._projectedBounds = bounds; + }, + + // Danger ahead: Overriding internal methods in Leaflet. + // Decided to do this rather than making a copy of L.ImageOverlay + // and doing very tiny modifications to it. + // Future will tell if this was wise or not. + _animateZoom: function (event) { + var scale = this._map.getZoomScale(event.zoom); + var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y); + var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center); + + L.DomUtil.setTransform(this._image, offset, scale); + }, + + _reset: function () { + var zoom = this._map.getZoom(); + var pixelOrigin = this._map.getPixelOrigin(); + var bounds = L.bounds( + this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin), + this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin) + ); + var size = bounds.getSize(); + + L.DomUtil.setPosition(this._image, bounds.min); + this._image.style.width = size.x + 'px'; + this._image.style.height = size.y + 'px'; + }, + + _projectedToNewLayerPoint: function (point, zoom, center) { + var viewHalf = this._map.getSize()._divideBy(2); + var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round(); + var topLeft = newTopLeft.add(this._map._getMapPanePos()); + + return this._transform(point, zoom)._subtract(topLeft); + }, + + _transform: function (point, zoom) { + var crs = this._map.options.crs; + var transformation = crs.transformation; + var scale = crs.scale(zoom); + + return transformation.transform(point, scale); + } + }); + + L.Proj.imageOverlay = function (url, bounds, options) { + return new L.Proj.ImageOverlay(url, bounds, options); + }; + + return L.Proj; +})); diff --git a/2311/site_libs/bootstrap/bootstrap-icons.css b/2311/site_libs/bootstrap/bootstrap-icons.css new file mode 100644 index 00000000..94f19404 --- /dev/null +++ b/2311/site_libs/bootstrap/bootstrap-icons.css @@ -0,0 +1,2018 @@ +@font-face { + font-display: block; + font-family: "bootstrap-icons"; + src: +url("./bootstrap-icons.woff?2ab2cbbe07fcebb53bdaa7313bb290f2") 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-1::before { content: "\f2a5"; } +.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-1::before { content: "\f68a"; } +.bi-envelope-check-fill::before { content: "\f68b"; } +.bi-envelope-check::before { content: "\f68c"; } +.bi-envelope-dash-1::before { content: "\f68d"; } +.bi-envelope-dash-fill::before { content: "\f68e"; } +.bi-envelope-dash::before { content: "\f68f"; } +.bi-envelope-exclamation-1::before { content: "\f690"; } +.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-1::before { content: "\f695"; } +.bi-envelope-slash-fill::before { content: "\f696"; } +.bi-envelope-slash::before { content: "\f697"; } +.bi-envelope-x-1::before { content: "\f698"; } +.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-mortorboard-fill::before { content: "\f6a2"; } +.bi-mortorboard::before { content: "\f6a3"; } +.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-1::before { content: "\f6b6"; } +.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-1::before { content: "\f6c2"; } +.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-1::before { content: "\f6e0"; } +.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-ssd-fill::before { content: "\f6ed"; } +.bi-ssd::before { content: "\f6ee"; } +.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-1::before { content: "\f759"; } +.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-1::before { content: "\f769"; } +.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-1::before { content: "\f794"; } +.bi-1-circle-fill-1::before { content: "\f795"; } +.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-1::before { content: "\f79a"; } +.bi-2-circle-fill-1::before { content: "\f79b"; } +.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-1::before { content: "\f7a0"; } +.bi-3-circle-fill-1::before { content: "\f7a1"; } +.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-1::before { content: "\f7a6"; } +.bi-4-circle-fill-1::before { content: "\f7a7"; } +.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-1::before { content: "\f7ac"; } +.bi-5-circle-fill-1::before { content: "\f7ad"; } +.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-1::before { content: "\f7b2"; } +.bi-6-circle-fill-1::before { content: "\f7b3"; } +.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-1::before { content: "\f7b8"; } +.bi-7-circle-fill-1::before { content: "\f7b9"; } +.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-1::before { content: "\f7be"; } +.bi-8-circle-fill-1::before { content: "\f7bf"; } +.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-1::before { content: "\f7c4"; } +.bi-9-circle-fill-1::before { content: "\f7c5"; } +.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-1::before { content: "\f7d8"; } +.bi-c-circle-fill-1::before { content: "\f7d9"; } +.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-1::before { content: "\f7e4"; } +.bi-cc-circle-fill-1::before { content: "\f7e5"; } +.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-1::before { content: "\f7f8"; } +.bi-h-circle-fill-1::before { content: "\f7f9"; } +.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-1::before { content: "\f802"; } +.bi-p-circle-fill-1::before { content: "\f803"; } +.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-1::before { content: "\f80c"; } +.bi-r-circle-fill-1::before { content: "\f80d"; } +.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"; } diff --git a/2311/site_libs/bootstrap/bootstrap-icons.woff b/2311/site_libs/bootstrap/bootstrap-icons.woff new file mode 100644 index 00000000..18d21d45 Binary files /dev/null and b/2311/site_libs/bootstrap/bootstrap-icons.woff differ diff --git a/2311/site_libs/bootstrap/bootstrap.min.css b/2311/site_libs/bootstrap/bootstrap.min.css new file mode 100644 index 00000000..f96a1f6a --- /dev/null +++ b/2311/site_libs/bootstrap/bootstrap.min.css @@ -0,0 +1,10 @@ +@import"https://fonts.googleapis.com/css2?family=JetBrains+Mono&family=Nunito:ital,wght@0,400;0,600;1,400;1,600&display=swap";/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root{--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-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: #E9F2D1;--bs-primary: #95b540;--bs-secondary: #E9F2D1;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-default-rgb: 233, 242, 209;--bs-primary-rgb: 149, 181, 64;--bs-secondary-rgb: 233, 242, 209;--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-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-body-color-rgb: 32, 32, 32;--bs-body-bg-rgb: 255, 255, 255;--bs-font-sans-serif: "Nunito", "Source Sans Pro", "Helvetica", "sans-serif";--bs-font-monospace: "JetBrains Mono", "Ubuntu Mono", "Lucida Console", "Courier", "monospace";--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 18px;--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #202020;--bs-body-bg: #ffffff}*,*::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;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}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}h1,.h1{font-size:calc(1.3052rem + 0.6624vw)}@media(min-width: 1200px){h1,.h1{font-size:1.802rem}}h2,.h2{font-size:calc(1.2852rem + 0.4224vw)}@media(min-width: 1200px){h2,.h2{font-size:1.602rem}}h3,.h3{font-size:calc(1.2674rem + 0.2088vw)}@media(min-width: 1200px){h3,.h3{font-size:1.424rem}}h4,.h4{font-size:calc(1.2516rem + 0.0192vw)}@media(min-width: 1200px){h4,.h4{font-size:1.266rem}}h5,.h5{font-size:1.125rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-bs-original-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:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:#96b43f;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{color:#789032}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr /* rtl:ignore */;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875rem;color:#000;background-color:#f5f5f5;padding:.5rem;border:1px solid #dee2e6;border-radius:.25rem}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875rem;color:#9753b8;background-color:#f5f5f5;border-radius:.25rem;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875rem;color:#fff;background-color:#212529;border-radius:.2em}kbd kbd{padding:0;font-size:1em;font-weight:700}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:#6c757d;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]::-webkit-calendar-picker-indicator{display:none}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]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-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:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:#6c757d}.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-bg: transparent;--bs-table-accent-bg: transparent;--bs-table-striped-color: #202020;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #202020;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #202020;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#202020;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid #a0a0a0}.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-accent-bg: var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg: var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg: var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg: #eaf0d9;--bs-table-striped-bg: #dee4ce;--bs-table-striped-color: #000;--bs-table-active-bg: #d3d8c3;--bs-table-active-color: #000;--bs-table-hover-bg: #d8dec9;--bs-table-hover-color: #000;color:#000;border-color:#d3d8c3}.table-secondary{--bs-table-bg: #fbfcf6;--bs-table-striped-bg: #eeefea;--bs-table-striped-color: #000;--bs-table-active-bg: #e2e3dd;--bs-table-active-color: #000;--bs-table-hover-bg: #e8e9e4;--bs-table-hover-color: #000;color:#000;border-color:#e2e3dd}.table-success{--bs-table-bg: #d1e7dd;--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:#000;border-color:#bcd0c7}.table-info{--bs-table-bg: #cff4fc;--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:#000;border-color:#badce3}.table-warning{--bs-table-bg: #fff3cd;--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:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg: #f8d7da;--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:#000;border-color:#dfc2c4}.table-light{--bs-table-bg: #f8f9fa;--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:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg: #212529;--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:#fff;border-color:#373b3e}.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:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#202020;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;border-radius:.25rem;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:#202020;background-color:#fff;border-color:#cadaa0;outline:0;box-shadow:0 0 0 .25rem rgba(149,181,64,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#202020;background-color:#e9ecef;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:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#202020;background-color:#e9ecef;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::-webkit-file-upload-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#202020;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 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 + 2px);padding:.25rem .5rem;font-size:0.875rem;border-radius:.2em}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#202020;background-color:#fff;background-image: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 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#cadaa0;outline:0;box-shadow:0 0 0 .25rem rgba(149,181,64,.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 #202020}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem;border-radius:.2em}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.3rem}.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-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;color-adjust:exact;-webkit-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:#cadaa0;outline:0;box-shadow:0 0 0 .25rem rgba(149,181,64,.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:#95b540;border-color:#95b540}.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]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-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]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23000'/%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:#95b540;border-color:#95b540;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23000' 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{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{width:2em;margin-left:-2.5em;background-image: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");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{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23cadaa0'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23000'/%3e%3c/svg%3e")}.form-check-inline,.shiny-input-container .checkbox-inline,.shiny-input-container .radio-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}.form-range{width:100%;height:1.5rem;padding:0;background-color:rgba(0,0,0,0);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(149,181,64,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(149,181,64,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;background-color:#95b540;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#dfe9c6}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#dee2e6;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#95b540;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#dfe9c6}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#dee2e6;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;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{padding:1rem .75rem}.form-floating>.form-control::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-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-select~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.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{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{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.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:#202020;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.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:.3rem}.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:.2em}.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),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3){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),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4){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:-1px;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:rgba(25,135,84,.9);border-radius:.25rem}.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.73L.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"]{padding-right:4.125rem;background-image: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 5l6 6 6-6'/%3e%3c/svg%3e"),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.73L.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-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-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:valid,.input-group .form-control.is-valid,.was-validated .input-group .form-select:valid,.input-group .form-select.is-valid{z-index:1}.was-validated .input-group .form-control:valid:focus,.input-group .form-control.is-valid:focus,.was-validated .input-group .form-select:valid:focus,.input-group .form-select.is-valid:focus{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:rgba(220,53,69,.9);border-radius:.25rem}.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"]{padding-right:4.125rem;background-image: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 5l6 6 6-6'/%3e%3c/svg%3e"),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-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-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:invalid,.input-group .form-control.is-invalid,.was-validated .input-group .form-select:invalid,.input-group .form-select.is-invalid{z-index:2}.was-validated .input-group .form-control:invalid:focus,.input-group .form-control.is-invalid:focus,.was-validated .input-group .form-select:invalid:focus,.input-group .form-select.is-invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#202020;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;background-color:rgba(0,0,0,0);border:1px solid rgba(0,0,0,0);padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;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:#202020}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(149,181,64,.25)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-default{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}.btn-default:hover{color:#000;background-color:#ecf4d8;border-color:#ebf3d6}.btn-check:focus+.btn-default,.btn-default:focus{color:#000;background-color:#ecf4d8;border-color:#ebf3d6;box-shadow:0 0 0 .25rem rgba(198,206,178,.5)}.btn-check:checked+.btn-default,.btn-check:active+.btn-default,.btn-default:active,.btn-default.active,.show>.btn-default.dropdown-toggle{color:#000;background-color:#edf5da;border-color:#ebf3d6}.btn-check:checked+.btn-default:focus,.btn-check:active+.btn-default:focus,.btn-default:active:focus,.btn-default.active:focus,.show>.btn-default.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(198,206,178,.5)}.btn-default:disabled,.btn-default.disabled{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}.btn-primary{color:#000;background-color:#95b540;border-color:#95b540}.btn-primary:hover{color:#000;background-color:#a5c05d;border-color:#a0bc53}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#000;background-color:#a5c05d;border-color:#a0bc53;box-shadow:0 0 0 .25rem rgba(127,154,54,.5)}.btn-check:checked+.btn-primary,.btn-check:active+.btn-primary,.btn-primary:active,.btn-primary.active,.show>.btn-primary.dropdown-toggle{color:#000;background-color:#aac466;border-color:#a0bc53}.btn-check:checked+.btn-primary:focus,.btn-check:active+.btn-primary:focus,.btn-primary:active:focus,.btn-primary.active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(127,154,54,.5)}.btn-primary:disabled,.btn-primary.disabled{color:#000;background-color:#95b540;border-color:#95b540}.btn-secondary{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}.btn-secondary:hover{color:#000;background-color:#ecf4d8;border-color:#ebf3d6}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#000;background-color:#ecf4d8;border-color:#ebf3d6;box-shadow:0 0 0 .25rem rgba(198,206,178,.5)}.btn-check:checked+.btn-secondary,.btn-check:active+.btn-secondary,.btn-secondary:active,.btn-secondary.active,.show>.btn-secondary.dropdown-toggle{color:#000;background-color:#edf5da;border-color:#ebf3d6}.btn-check:checked+.btn-secondary:focus,.btn-check:active+.btn-secondary:focus,.btn-secondary:active:focus,.btn-secondary.active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(198,206,178,.5)}.btn-secondary:disabled,.btn-secondary.disabled{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:checked+.btn-success,.btn-check:active+.btn-success,.btn-success:active,.btn-success.active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:checked+.btn-success:focus,.btn-check:active+.btn-success:focus,.btn-success:active:focus,.btn-success.active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success:disabled,.btn-success.disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:checked+.btn-info,.btn-check:active+.btn-info,.btn-info:active,.btn-info.active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:checked+.btn-info:focus,.btn-check:active+.btn-info:focus,.btn-info:active:focus,.btn-info.active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info:disabled,.btn-info.disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:checked+.btn-warning,.btn-check:active+.btn-warning,.btn-warning:active,.btn-warning.active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:checked+.btn-warning:focus,.btn-check:active+.btn-warning:focus,.btn-warning:active:focus,.btn-warning.active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning:disabled,.btn-warning.disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:checked+.btn-danger,.btn-check:active+.btn-danger,.btn-danger:active,.btn-danger.active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:checked+.btn-danger:focus,.btn-check:active+.btn-danger:focus,.btn-danger:active:focus,.btn-danger.active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger:disabled,.btn-danger.disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:checked+.btn-light,.btn-check:active+.btn-light,.btn-light:active,.btn-light.active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:checked+.btn-light:focus,.btn-check:active+.btn-light:focus,.btn-light:active:focus,.btn-light.active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light:disabled,.btn-light.disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:checked+.btn-dark,.btn-check:active+.btn-dark,.btn-dark:active,.btn-dark.active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:checked+.btn-dark:focus,.btn-check:active+.btn-dark:focus,.btn-dark:active:focus,.btn-dark.active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark:disabled,.btn-dark.disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-default{color:#e9f2d1;border-color:#e9f2d1;background-color:rgba(0,0,0,0)}.btn-outline-default:hover{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}.btn-check:focus+.btn-outline-default,.btn-outline-default:focus{box-shadow:0 0 0 .25rem rgba(233,242,209,.5)}.btn-check:checked+.btn-outline-default,.btn-check:active+.btn-outline-default,.btn-outline-default:active,.btn-outline-default.active,.btn-outline-default.dropdown-toggle.show{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}.btn-check:checked+.btn-outline-default:focus,.btn-check:active+.btn-outline-default:focus,.btn-outline-default:active:focus,.btn-outline-default.active:focus,.btn-outline-default.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(233,242,209,.5)}.btn-outline-default:disabled,.btn-outline-default.disabled{color:#e9f2d1;background-color:rgba(0,0,0,0)}.btn-outline-primary{color:#95b540;border-color:#95b540;background-color:rgba(0,0,0,0)}.btn-outline-primary:hover{color:#000;background-color:#95b540;border-color:#95b540}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(149,181,64,.5)}.btn-check:checked+.btn-outline-primary,.btn-check:active+.btn-outline-primary,.btn-outline-primary:active,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show{color:#000;background-color:#95b540;border-color:#95b540}.btn-check:checked+.btn-outline-primary:focus,.btn-check:active+.btn-outline-primary:focus,.btn-outline-primary:active:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(149,181,64,.5)}.btn-outline-primary:disabled,.btn-outline-primary.disabled{color:#95b540;background-color:rgba(0,0,0,0)}.btn-outline-secondary{color:#e9f2d1;border-color:#e9f2d1;background-color:rgba(0,0,0,0)}.btn-outline-secondary:hover{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(233,242,209,.5)}.btn-check:checked+.btn-outline-secondary,.btn-check:active+.btn-outline-secondary,.btn-outline-secondary:active,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}.btn-check:checked+.btn-outline-secondary:focus,.btn-check:active+.btn-outline-secondary:focus,.btn-outline-secondary:active:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(233,242,209,.5)}.btn-outline-secondary:disabled,.btn-outline-secondary.disabled{color:#e9f2d1;background-color:rgba(0,0,0,0)}.btn-outline-success{color:#198754;border-color:#198754;background-color:rgba(0,0,0,0)}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:checked+.btn-outline-success,.btn-check:active+.btn-outline-success,.btn-outline-success:active,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show{color:#fff;background-color:#198754;border-color:#198754}.btn-check:checked+.btn-outline-success:focus,.btn-check:active+.btn-outline-success:focus,.btn-outline-success:active:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success:disabled,.btn-outline-success.disabled{color:#198754;background-color:rgba(0,0,0,0)}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0;background-color:rgba(0,0,0,0)}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:checked+.btn-outline-info,.btn-check:active+.btn-outline-info,.btn-outline-info:active,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:checked+.btn-outline-info:focus,.btn-check:active+.btn-outline-info:focus,.btn-outline-info:active:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info:disabled,.btn-outline-info.disabled{color:#0dcaf0;background-color:rgba(0,0,0,0)}.btn-outline-warning{color:#ffc107;border-color:#ffc107;background-color:rgba(0,0,0,0)}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:checked+.btn-outline-warning,.btn-check:active+.btn-outline-warning,.btn-outline-warning:active,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:checked+.btn-outline-warning:focus,.btn-check:active+.btn-outline-warning:focus,.btn-outline-warning:active:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning:disabled,.btn-outline-warning.disabled{color:#ffc107;background-color:rgba(0,0,0,0)}.btn-outline-danger{color:#dc3545;border-color:#dc3545;background-color:rgba(0,0,0,0)}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:checked+.btn-outline-danger,.btn-check:active+.btn-outline-danger,.btn-outline-danger:active,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:checked+.btn-outline-danger:focus,.btn-check:active+.btn-outline-danger:focus,.btn-outline-danger:active:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger:disabled,.btn-outline-danger.disabled{color:#dc3545;background-color:rgba(0,0,0,0)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa;background-color:rgba(0,0,0,0)}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:checked+.btn-outline-light,.btn-check:active+.btn-outline-light,.btn-outline-light:active,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:checked+.btn-outline-light:focus,.btn-check:active+.btn-outline-light:focus,.btn-outline-light:active:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light:disabled,.btn-outline-light.disabled{color:#f8f9fa;background-color:rgba(0,0,0,0)}.btn-outline-dark{color:#212529;border-color:#212529;background-color:rgba(0,0,0,0)}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:checked+.btn-outline-dark,.btn-check:active+.btn-outline-dark,.btn-outline-dark:active,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show{color:#fff;background-color:#212529;border-color:#212529}.btn-check:checked+.btn-outline-dark:focus,.btn-check:active+.btn-outline-dark:focus,.btn-outline-dark:active:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark:disabled,.btn-outline-dark.disabled{color:#212529;background-color:rgba(0,0,0,0)}.btn-link{font-weight:400;color:#96b43f;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:hover{color:#789032}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.2em}.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{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{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#202020;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.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:.125rem}.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:.125rem}.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:.125rem}.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:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;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}.dropdown-item:hover,.dropdown-item:focus{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#000;text-decoration:none;background-color:#95b540}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:0.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:hover,.dropdown-menu-dark .dropdown-item:focus{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#000;background-color:#95b540}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .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>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child){margin-left:-1px}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.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:-1px}.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{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:.5rem 1rem;color:#96b43f;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;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:#789032}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:none;border:1px solid rgba(0,0,0,0);border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:rgba(0,0,0,0);border-color:rgba(0,0,0,0)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:none;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#000;background-color:#95b540}.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{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-top:.5rem;padding-bottom:.5rem}.navbar>.container-xxl,.navbar>.container-xl,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container,.navbar>.container-fluid{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:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-nav{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{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.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:.25 0;font-size:1.25rem;line-height:1;background-color:rgba(0,0,0,0);border:1px solid rgba(0,0,0,0);border-radius:.25rem;transition:box-shadow .15s ease-in-out}@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 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-top,.navbar-expand-sm .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-top,.navbar-expand-md .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-top,.navbar-expand-lg .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-top,.navbar-expand-xl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-top,.navbar-expand-xxl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-top,.navbar-expand .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-light{background-color:#e9f2d1}.navbar-light .navbar-brand{color:#4d5045}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:#45531d}.navbar-light .navbar-nav .nav-link{color:#4d5045}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(69,83,29,.8)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(77,80,69,.75)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .nav-link.active{color:#45531d}.navbar-light .navbar-toggler{color:#4d5045;border-color:rgba(77,80,69,0)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%234d5045' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:#4d5045}.navbar-light .navbar-text a,.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:#45531d}.navbar-dark{background-color:#e9f2d1}.navbar-dark .navbar-brand{color:#4d5045}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#45531d}.navbar-dark .navbar-nav .nav-link{color:#4d5045}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(69,83,29,.8)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(77,80,69,.75)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active{color:#45531d}.navbar-dark .navbar-toggler{color:#4d5045;border-color:rgba(77,80,69,0)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%234d5045' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:#4d5045}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#45531d}.card{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.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:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.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:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-0.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:#adb5bd;border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:#adb5bd;border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@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-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#202020;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#86a33a;background-color:#f4f8ec;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2386a33a'%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");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23202020'%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");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#cadaa0;outline:0;box-shadow:0 0 0 .25rem rgba(149,181,64,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.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{border-radius:0}.breadcrumb{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#96b43f;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid #dee2e6;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:#789032;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#789032;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(149,181,64,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#000;background-color:#95b540;border-color:#95b540}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:0.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2em;border-bottom-left-radius:.2em}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2em;border-bottom-right-radius:.2em}.badge{display:inline-block;padding:.35em .65em;font-size:0.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid rgba(0,0,0,0);border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{color:#5d6154;background-color:#fbfcf6;border-color:#f8fbf1}.alert-default .alert-link{color:#4a4e43}.alert-primary{color:#596d26;background-color:#eaf0d9;border-color:#dfe9c6}.alert-primary .alert-link{color:#47571e}.alert-secondary{color:#5d6154;background-color:#fbfcf6;border-color:#f8fbf1}.alert-secondary .alert-link{color:#4a4e43}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;display:-webkit-flex;height:1rem;overflow:hidden;font-size:0.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#95b540;transition:width .6s ease}@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:1rem 1rem}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#202020;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.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:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#000;background-color:#95b540;border-color:#95b540}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{color:#5d6154;background-color:#fbfcf6}.list-group-item-default.list-group-item-action:hover,.list-group-item-default.list-group-item-action:focus{color:#5d6154;background-color:#e2e3dd}.list-group-item-default.list-group-item-action.active{color:#fff;background-color:#5d6154;border-color:#5d6154}.list-group-item-primary{color:#596d26;background-color:#eaf0d9}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#596d26;background-color:#d3d8c3}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#596d26;border-color:#596d26}.list-group-item-secondary{color:#5d6154;background-color:#fbfcf6}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#5d6154;background-color:#e2e3dd}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#5d6154;border-color:#5d6154}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:rgba(0,0,0,0) 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 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(149,181,64,.25);opacity:1}.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:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:0.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{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:.75rem}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.toast-header .btn-close{margin-right:-0.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;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% - 1rem)}.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% - 1rem)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.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:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(0.3rem - 1px);border-top-right-radius:calc(0.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-0.5rem -0.5rem -0.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem}.modal-footer{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(0.3rem - 1px);border-bottom-left-radius:calc(0.3rem - 1px)}.modal-footer>*{margin:.25rem}@media(min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media(min-width: 992px){.modal-lg,.modal-xl{max-width:800px}}@media(min-width: 1200px){.modal-xl{max-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{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@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{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@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{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@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{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@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{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@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{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);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;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[data-popper-placement^=top]{padding:.4rem 0}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:0}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-end,.bs-tooltip-auto[data-popper-placement^=right]{padding:0 .4rem}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[data-popper-placement^=bottom]{padding:.4rem 0}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:0}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-start,.bs-tooltip-auto[data-popper-placement^=left]{padding:0 .4rem}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0 /* rtl:ignore */;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);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;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-0.5rem - 1px)}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-0.5rem - 1px)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.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:1rem;margin-left:-0.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(0.3rem - 1px);border-top-right-radius:calc(0.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#202020}.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%;list-style:none}.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}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;border:.25em solid currentColor;border-right-color:rgba(0,0,0,0);border-radius:50%;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;background-color:currentColor;border-radius:50%;opacity:0;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{animation-duration:1.5s;-webkit-animation-duration:1.5s;-moz-animation-duration:1.5s;-ms-animation-duration:1.5s;-o-animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.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:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-0.5rem;margin-right:-0.5rem;margin-bottom:-0.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.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:""}.link-default{color:#e9f2d1}.link-default:hover,.link-default:focus{color:#edf5da}.link-primary{color:#95b540}.link-primary:hover,.link-primary:focus{color:#aac466}.link-secondary{color:#e9f2d1}.link-secondary:hover,.link-secondary:focus{color:#edf5da}.link-success{color:#198754}.link-success:hover,.link-success:focus{color:#146c43}.link-info{color:#0dcaf0}.link-info:hover,.link-info:focus{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:hover,.link-warning:focus{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:hover,.link-danger:focus{color:#b02a37}.link-light{color:#f8f9fa}.link-light:hover,.link-light:focus{color:#f9fafb}.link-dark{color:#212529}.link-dark:hover,.link-dark:focus{color:#1a1e21}.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}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top: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){position:absolute !important;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}.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}.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}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display: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}.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:1px solid #dee2e6 !important}.border-0{border:0 !important}.border-top{border-top:1px solid #dee2e6 !important}.border-top-0{border-top:0 !important}.border-end{border-right:1px solid #dee2e6 !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:1px solid #dee2e6 !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:1px solid #dee2e6 !important}.border-start-0{border-left:0 !important}.border-default{border-color:#e9f2d1 !important}.border-primary{border-color:#95b540 !important}.border-secondary{border-color:#e9f2d1 !important}.border-success{border-color:#198754 !important}.border-info{border-color:#0dcaf0 !important}.border-warning{border-color:#ffc107 !important}.border-danger{border-color:#dc3545 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#212529 !important}.border-white{border-color:#fff !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}.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}.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}.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}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.3052rem + 0.6624vw) !important}.fs-2{font-size:calc(1.2852rem + 0.4224vw) !important}.fs-3{font-size:calc(1.2674rem + 0.2088vw) !important}.fs-4{font-size:calc(1.2516rem + 0.0192vw) !important}.fs-5{font-size:1.125rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-light{font-weight:300 !important}.fw-lighter{font-weight:lighter !important}.fw-normal{font-weight:400 !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:#6c757d !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-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}.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-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-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:.25rem !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:.2em !important}.rounded-2{border-radius:.25rem !important}.rounded-3{border-radius:.3rem !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:50rem !important}.rounded-top{border-top-left-radius:.25rem !important;border-top-right-radius:.25rem !important}.rounded-end{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}.rounded-bottom{border-bottom-right-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-start{border-bottom-left-radius:.25rem !important;border-top-left-radius:.25rem !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float: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-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}.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}.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}.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}.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-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}.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}.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}.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}.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-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}.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}.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}.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}.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-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}.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}.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}.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}.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-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}.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}.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}.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:#000}.bg-secondary{color:#000}.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:1.802rem !important}.fs-2{font-size:1.602rem !important}.fs-3{font-size:1.424rem !important}.fs-4{font-size:1.266rem !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-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}}.quarto-container{min-height:calc(100vh - 132px)}footer.footer .nav-footer,#quarto-header>nav{padding-left:1em;padding-right:1em}nav[role=doc-toc]{padding-left:.5em}#quarto-content>*{padding-top:14px}@media(max-width: 991.98px){#quarto-content>*{padding-top:0}#quarto-content .subtitle{padding-top:14px}#quarto-content section:first-of-type h2:first-of-type,#quarto-content section:first-of-type .h2:first-of-type{margin-top:1rem}}.headroom-target,header.headroom{will-change:transform;transition:position 200ms linear;transition:all 200ms linear}header.headroom--pinned{transform:translateY(0%)}header.headroom--unpinned{transform:translateY(-100%)}.navbar-container{width:100%}.navbar-brand{overflow:hidden;text-overflow:ellipsis}.navbar-brand-container{max-width:calc(100% - 115px);min-width:0;display:flex;align-items:center}@media(min-width: 992px){.navbar-brand-container{margin-right:1em}}.navbar-brand.navbar-brand-logo{margin-right:4px;display:inline-flex}.navbar-toggler{flex-basis:content;flex-shrink:0}.navbar .navbar-toggler{order:-1;margin-right:.5em}.navbar-logo{max-height:24px;width:auto;padding-right:4px}nav .nav-item:not(.compact){padding-top:1px}nav .nav-link i,nav .dropdown-item i{padding-right:1px}.navbar-expand-lg .navbar-nav .nav-link{padding-left:.6rem;padding-right:.6rem}nav .nav-item.compact .nav-link{padding-left:.5rem;padding-right:.5rem;font-size:1.1rem}.navbar .quarto-navbar-tools div.dropdown{display:inline-block}.navbar .quarto-navbar-tools .quarto-navigation-tool{color:#4d5045}.navbar .quarto-navbar-tools .quarto-navigation-tool:hover{color:#45531d}@media(max-width: 991.98px){.navbar .quarto-navbar-tools{margin-top:.25em;padding-top:.75em;display:block;color:solid #cccec6 1px;text-align:center;vertical-align:middle;margin-right:auto}}.navbar-nav .dropdown-menu{min-width:220px;font-size:.9rem}.navbar .navbar-nav .nav-link.dropdown-toggle::after{opacity:.75;vertical-align:.175em}.navbar ul.dropdown-menu{padding-top:0;padding-bottom:0}.navbar .dropdown-header{text-transform:uppercase;font-size:.8rem;padding:0 .5rem}.navbar .dropdown-item{padding:.4rem .5rem}.navbar .dropdown-item>i.bi{margin-left:.1rem;margin-right:.25em}.sidebar #quarto-search{margin-top:-1px}.sidebar #quarto-search svg.aa-SubmitIcon{width:16px;height:16px}.sidebar-navigation a{color:inherit}.sidebar-title{margin-top:.25rem;padding-bottom:.5rem;font-size:1.3rem;line-height:1.6rem;visibility:visible}.sidebar-title>a{font-size:inherit;text-decoration:none}.sidebar-title .sidebar-tools-main{margin-top:-6px}@media(max-width: 991.98px){#quarto-sidebar div.sidebar-header{padding-top:.2em}}.sidebar-header-stacked .sidebar-title{margin-top:.6rem}.sidebar-logo{max-width:90%;padding-bottom:.5rem}.sidebar-logo-link{text-decoration:none}.sidebar-navigation li a{text-decoration:none}.sidebar-navigation .quarto-navigation-tool{opacity:.7;font-size:.875rem}#quarto-sidebar>nav>.sidebar-tools-main{margin-left:14px}.sidebar-tools-main{display:inline-flex;margin-left:0px;order:2}.sidebar-tools-main:not(.tools-wide){vertical-align:middle}.sidebar-navigation .quarto-navigation-tool.dropdown-toggle::after{display:none}.sidebar.sidebar-navigation>*{padding-top:1em}.sidebar-item{margin-bottom:.2em}.sidebar-section{margin-top:.2em;padding-left:.5em;padding-bottom:.2em}.sidebar-item .sidebar-item-container{display:flex;justify-content:space-between}.sidebar-item-toggle:hover{cursor:pointer}.sidebar-item .sidebar-item-toggle .bi{font-size:.7rem;text-align:center}.sidebar-item .sidebar-item-toggle .bi-chevron-right::before{transition:transform 200ms ease}.sidebar-item .sidebar-item-toggle[aria-expanded=false] .bi-chevron-right::before{transform:none}.sidebar-item .sidebar-item-toggle[aria-expanded=true] .bi-chevron-right::before{transform:rotate(90deg)}.sidebar-navigation .sidebar-divider{margin-left:0;margin-right:0;margin-top:.5rem;margin-bottom:.5rem}@media(max-width: 991.98px){.quarto-secondary-nav{display:block}.quarto-secondary-nav button.quarto-search-button{padding-right:0em;padding-left:2em}.quarto-secondary-nav button.quarto-btn-toggle{margin-left:-0.75rem;margin-right:.15rem}.quarto-secondary-nav nav.quarto-page-breadcrumbs{display:flex;align-items:center;padding-right:1em;margin-left:-0.25em}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{text-decoration:none}.quarto-secondary-nav nav.quarto-page-breadcrumbs ol.breadcrumb{margin-bottom:0}}@media(min-width: 992px){.quarto-secondary-nav{display:none}}.quarto-secondary-nav .quarto-btn-toggle{color:#595959}.quarto-secondary-nav[aria-expanded=false] .quarto-btn-toggle .bi-chevron-right::before{transform:none}.quarto-secondary-nav[aria-expanded=true] .quarto-btn-toggle .bi-chevron-right::before{transform:rotate(90deg)}.quarto-secondary-nav .quarto-btn-toggle .bi-chevron-right::before{transition:transform 200ms ease}.quarto-secondary-nav{cursor:pointer}.quarto-secondary-nav-title{margin-top:.3em;color:#595959;padding-top:4px}.quarto-secondary-nav nav.quarto-page-breadcrumbs{color:#595959}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{color:#595959}.quarto-secondary-nav nav.quarto-page-breadcrumbs a:hover{color:rgba(80,95,33,.8)}.quarto-secondary-nav nav.quarto-page-breadcrumbs .breadcrumb-item::before{color:#8c8c8c}div.sidebar-item-container{color:#595959}div.sidebar-item-container:hover,div.sidebar-item-container:focus{color:rgba(80,95,33,.8)}div.sidebar-item-container.disabled{color:rgba(89,89,89,.75)}div.sidebar-item-container .active,div.sidebar-item-container .show>.nav-link,div.sidebar-item-container .sidebar-link>code{color:#505f21}div.sidebar.sidebar-navigation.rollup.quarto-sidebar-toggle-contents,nav.sidebar.sidebar-navigation:not(.rollup){background-color:#fff}@media(max-width: 991.98px){.sidebar-navigation .sidebar-item a,.nav-page .nav-page-text,.sidebar-navigation{font-size:1rem}.sidebar-navigation ul.sidebar-section.depth1 .sidebar-section-item{font-size:1.1rem}.sidebar-logo{display:none}.sidebar.sidebar-navigation{position:static;border-bottom:1px solid #dee2e6}.sidebar.sidebar-navigation.collapsing{position:fixed;z-index:1000}.sidebar.sidebar-navigation.show{position:fixed;z-index:1000}.sidebar.sidebar-navigation{min-height:100%}nav.quarto-secondary-nav{background-color:#fff;border-bottom:1px solid #dee2e6}.sidebar .sidebar-footer{visibility:visible;padding-top:1rem;position:inherit}.sidebar-tools-collapse{display:block}}#quarto-sidebar{transition:width .15s ease-in}#quarto-sidebar>*{padding-right:1em}@media(max-width: 991.98px){#quarto-sidebar .sidebar-menu-container{white-space:nowrap;min-width:225px}#quarto-sidebar.show{transition:width .15s ease-out}}@media(min-width: 992px){#quarto-sidebar{display:flex;flex-direction:column}.nav-page .nav-page-text,.sidebar-navigation .sidebar-section .sidebar-item{font-size:.875rem}.sidebar-navigation .sidebar-item{font-size:.925rem}.sidebar.sidebar-navigation{display:block;position:sticky}.sidebar-search{width:100%}.sidebar .sidebar-footer{visibility:visible}}@media(max-width: 991.98px){#quarto-sidebar-glass{position:fixed;top:0;bottom:0;left:0;right:0;background-color:rgba(255,255,255,0);transition:background-color .15s ease-in;z-index:-1}#quarto-sidebar-glass.collapsing{z-index:1000}#quarto-sidebar-glass.show{transition:background-color .15s ease-out;background-color:rgba(102,102,102,.4);z-index:1000}}.sidebar .sidebar-footer{padding:.5rem 1rem;align-self:flex-end;color:#6c757d;width:100%}.quarto-page-breadcrumbs .breadcrumb-item+.breadcrumb-item,.quarto-page-breadcrumbs .breadcrumb-item{padding-right:.33em;padding-left:0}.quarto-page-breadcrumbs .breadcrumb-item::before{padding-right:.33em}.quarto-sidebar-footer{font-size:.875em}.sidebar-section .bi-chevron-right{vertical-align:middle}.sidebar-section .bi-chevron-right::before{font-size:.9em}.notransition{-webkit-transition:none !important;-moz-transition:none !important;-o-transition:none !important;transition:none !important}.btn:focus:not(:focus-visible){box-shadow:none}.page-navigation{display:flex;justify-content:space-between}.nav-page{padding-bottom:.75em}.nav-page .bi{font-size:1.8rem;vertical-align:middle}.nav-page .nav-page-text{padding-left:.25em;padding-right:.25em}.nav-page a{color:#6c757d;text-decoration:none;display:flex;align-items:center}.nav-page a:hover{color:#789032}.toc-actions{display:flex}.toc-actions p{margin-block-start:0;margin-block-end:0}.toc-actions a{text-decoration:none;color:inherit;font-weight:400}.toc-actions a:hover{color:#789032}.toc-actions .action-links{margin-left:4px}.sidebar nav[role=doc-toc] .toc-actions .bi{margin-left:-4px;font-size:.7rem;color:#6c757d}.sidebar nav[role=doc-toc] .toc-actions .bi:before{padding-top:3px}#quarto-margin-sidebar .toc-actions .bi:before{margin-top:.3rem;font-size:.7rem;color:#6c757d;vertical-align:top}.sidebar nav[role=doc-toc] .toc-actions>div:first-of-type{margin-top:-3px}#quarto-margin-sidebar .toc-actions p,.sidebar nav[role=doc-toc] .toc-actions p{font-size:.875rem}.nav-footer .toc-actions{padding-bottom:.5em;padding-top:.5em}.nav-footer .toc-actions :first-child{margin-left:auto}.nav-footer .toc-actions :last-child{margin-right:auto}.nav-footer .toc-actions .action-links{display:flex}.nav-footer .toc-actions .action-links p{padding-right:1.5em}.nav-footer .toc-actions .action-links p:last-of-type{padding-right:0}.nav-footer{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:baseline;text-align:center;padding-top:.5rem;padding-bottom:.5rem;background-color:#fff}body.nav-fixed{padding-top:64px}.nav-footer-contents{color:#6c757d;margin-top:.25rem}.nav-footer{min-height:3.5em;color:dimgray}.nav-footer a{color:dimgray}.nav-footer .nav-footer-left{font-size:.825em}.nav-footer .nav-footer-center{font-size:.825em}.nav-footer .nav-footer-right{font-size:.825em}.nav-footer-left .footer-items,.nav-footer-center .footer-items,.nav-footer-right .footer-items{display:inline-flex;padding-top:.3em;padding-bottom:.3em;margin-bottom:0em}.nav-footer-left .footer-items .nav-link,.nav-footer-center .footer-items .nav-link,.nav-footer-right .footer-items .nav-link{padding-left:.6em;padding-right:.6em}.nav-footer-left{flex:1 1 0px;text-align:left}.nav-footer-right{flex:1 1 0px;text-align:right}.nav-footer-center{flex:1 1 0px;min-height:3em;text-align:center}.nav-footer-center .footer-items{justify-content:center}@media(max-width: 767.98px){.nav-footer-center{margin-top:3em}}.navbar .quarto-reader-toggle.reader .quarto-reader-toggle-btn{background-color:#4d5045;border-radius:3px}.quarto-reader-toggle.reader.quarto-navigation-tool .quarto-reader-toggle-btn{background-color:#595959;border-radius:3px}.quarto-reader-toggle .quarto-reader-toggle-btn{display:inline-flex;padding-left:.2em;padding-right:.2em;margin-left:-0.2em;margin-right:-0.2em;text-align:center}.navbar .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}#quarto-back-to-top{display:none;position:fixed;bottom:50px;background-color:#fff;border-radius:.25rem;box-shadow:0 .2rem .5rem #6c757d,0 0 .05rem #6c757d;color:#6c757d;text-decoration:none;font-size:.9em;text-align:center;left:50%;padding:.4rem .8rem;transform:translate(-50%, 0)}.aa-DetachedOverlay ul.aa-List,#quarto-search-results ul.aa-List{list-style:none;padding-left:0}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{background-color:#fff;position:absolute;z-index:2000}#quarto-search-results .aa-Panel{max-width:400px}#quarto-search input{font-size:.925rem}@media(min-width: 992px){.navbar #quarto-search{margin-left:.25rem;order:999}}@media(max-width: 991.98px){#quarto-sidebar .sidebar-search{display:none}}#quarto-sidebar .sidebar-search .aa-Autocomplete{width:100%}.navbar .aa-Autocomplete .aa-Form{width:180px}.navbar #quarto-search.type-overlay .aa-Autocomplete{width:40px}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form{background-color:inherit;border:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form:focus-within{box-shadow:none;outline:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper{display:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper:focus-within{display:inherit}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-Label svg,.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-LoadingIndicator svg{width:26px;height:26px;color:#4d5045;opacity:1}.navbar #quarto-search.type-overlay .aa-Autocomplete svg.aa-SubmitIcon{width:26px;height:26px;color:#4d5045;opacity:1}.aa-Autocomplete .aa-Form,.aa-DetachedFormContainer .aa-Form{align-items:center;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;color:#202020;display:flex;line-height:1em;margin:0;position:relative;width:100%}.aa-Autocomplete .aa-Form:focus-within,.aa-DetachedFormContainer .aa-Form:focus-within{box-shadow:rgba(149,181,64,.6) 0 0 0 1px;outline:currentColor none medium}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix{align-items:center;display:flex;flex-shrink:0;order:1}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{cursor:initial;flex-shrink:0;padding:0;text-align:left}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg{color:#202020;opacity:.5}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton{appearance:none;background:none;border:0;margin:0}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{align-items:center;display:flex;justify-content:center}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapper,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper{order:3;position:relative;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input{appearance:none;background:none;border:0;color:#202020;font:inherit;height:calc(1.5em + .1rem + 2px);padding:0;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::placeholder,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::placeholder{color:#202020;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input:focus{border-color:none;box-shadow:none;outline:none}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix{align-items:center;display:flex;order:4}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton{align-items:center;background:none;border:0;color:#202020;opacity:.8;cursor:pointer;display:flex;margin:0;width:calc(1.5em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus{color:#202020;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg{width:calc(1.5em + 0.75rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton{border:none;align-items:center;background:none;color:#202020;opacity:.4;font-size:.7rem;cursor:pointer;display:none;margin:0;width:calc(1em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus{color:#202020;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden]{display:none}.aa-PanelLayout:empty{display:none}.quarto-search-no-results.no-query{display:none}.aa-Source:has(.no-query){display:none}#quarto-search-results .aa-Panel{border:solid #ced4da 1px}#quarto-search-results .aa-SourceNoResults{width:398px}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{max-height:65vh;overflow-y:auto;font-size:.925rem}.aa-DetachedOverlay .aa-SourceNoResults,#quarto-search-results .aa-SourceNoResults{height:60px;display:flex;justify-content:center;align-items:center}.aa-DetachedOverlay .search-error,#quarto-search-results .search-error{padding-top:10px;padding-left:20px;padding-right:20px;cursor:default}.aa-DetachedOverlay .search-error .search-error-title,#quarto-search-results .search-error .search-error-title{font-size:1.1rem;margin-bottom:.5rem}.aa-DetachedOverlay .search-error .search-error-title .search-error-icon,#quarto-search-results .search-error .search-error-title .search-error-icon{margin-right:8px}.aa-DetachedOverlay .search-error .search-error-text,#quarto-search-results .search-error .search-error-text{font-weight:300}.aa-DetachedOverlay .search-result-text,#quarto-search-results .search-result-text{font-weight:300;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.2rem;max-height:2.4rem}.aa-DetachedOverlay .aa-SourceHeader .search-result-header,#quarto-search-results .aa-SourceHeader .search-result-header{font-size:.875rem;background-color:#f2f2f2;padding-left:14px;padding-bottom:4px;padding-top:4px}.aa-DetachedOverlay .aa-SourceHeader .search-result-header-no-results,#quarto-search-results .aa-SourceHeader .search-result-header-no-results{display:none}.aa-DetachedOverlay .aa-SourceFooter .algolia-search-logo,#quarto-search-results .aa-SourceFooter .algolia-search-logo{width:110px;opacity:.85;margin:8px;float:right}.aa-DetachedOverlay .search-result-section,#quarto-search-results .search-result-section{font-size:.925em}.aa-DetachedOverlay a.search-result-link,#quarto-search-results a.search-result-link{color:inherit;text-decoration:none}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item,#quarto-search-results li.aa-Item[aria-selected=true] .search-item{background-color:#95b540}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text-container{color:#000;background-color:#95b540}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=true] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-match.mark{color:#000;background-color:#a7c459}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item,#quarto-search-results li.aa-Item[aria-selected=false] .search-item{background-color:#fff}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text-container{color:#202020}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=false] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-match.mark{color:inherit;background-color:#ebf2d9}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container{background-color:#fff;color:#202020}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container{padding-top:0px}.aa-DetachedOverlay li.aa-Item .search-result-doc.document-selectable .search-result-text-container,#quarto-search-results li.aa-Item .search-result-doc.document-selectable .search-result-text-container{margin-top:-4px}.aa-DetachedOverlay .aa-Item,#quarto-search-results .aa-Item{cursor:pointer}.aa-DetachedOverlay .aa-Item .search-item,#quarto-search-results .aa-Item .search-item{border-left:none;border-right:none;border-top:none;background-color:#fff;border-color:#ced4da;color:#202020}.aa-DetachedOverlay .aa-Item .search-item p,#quarto-search-results .aa-Item .search-item p{margin-top:0;margin-bottom:0}.aa-DetachedOverlay .aa-Item .search-item i.bi,#quarto-search-results .aa-Item .search-item i.bi{padding-left:8px;padding-right:8px;font-size:1.3em}.aa-DetachedOverlay .aa-Item .search-item .search-result-title,#quarto-search-results .aa-Item .search-item .search-result-title{margin-top:.3em;margin-bottom:.1rem}.aa-DetachedOverlay .aa-Item .search-result-title-container,#quarto-search-results .aa-Item .search-result-title-container{font-size:1em;display:flex;padding:6px 4px 6px 4px}.aa-DetachedOverlay .aa-Item .search-result-text-container,#quarto-search-results .aa-Item .search-result-text-container{padding-bottom:8px;padding-right:8px;margin-left:44px}.aa-DetachedOverlay .aa-Item .search-result-doc-section,.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-doc-section,#quarto-search-results .aa-Item .search-result-more{padding-top:8px;padding-bottom:8px;padding-left:44px}.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-more{font-size:.8em;font-weight:400}.aa-DetachedOverlay .aa-Item .search-result-doc,#quarto-search-results .aa-Item .search-result-doc{border-top:1px solid #ced4da}.aa-DetachedSearchButton{background:none;border:none}.aa-DetachedSearchButton .aa-DetachedSearchButtonPlaceholder{display:none}.navbar .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#4d5045}.sidebar-tools-collapse #quarto-search,.sidebar-tools-main #quarto-search{display:inline}.sidebar-tools-collapse #quarto-search .aa-Autocomplete,.sidebar-tools-main #quarto-search .aa-Autocomplete{display:inline}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton{padding-left:4px;padding-right:4px}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#595959}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon{margin-top:-3px}.aa-DetachedContainer{background:rgba(255,255,255,.65);width:90%;bottom:0;box-shadow:rgba(206,212,218,.6) 0 0 0 1px;outline:currentColor none medium;display:flex;flex-direction:column;left:0;margin:0;overflow:hidden;padding:0;position:fixed;right:0;top:0;z-index:1101}.aa-DetachedContainer::after{height:32px}.aa-DetachedContainer .aa-SourceHeader{margin:var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px}.aa-DetachedContainer .aa-Panel{background-color:#fff;border-radius:0;box-shadow:none;flex-grow:1;margin:0;padding:0;position:relative}.aa-DetachedContainer .aa-PanelLayout{bottom:0;box-shadow:none;left:0;margin:0;max-height:none;overflow-y:auto;position:absolute;right:0;top:0;width:100%}.aa-DetachedFormContainer{background-color:#fff;border-bottom:1px solid #ced4da;display:flex;flex-direction:row;justify-content:space-between;margin:0;padding:.5em}.aa-DetachedCancelButton{background:none;font-size:.8em;border:0;border-radius:3px;color:#202020;cursor:pointer;margin:0 0 0 .5em;padding:0 .5em}.aa-DetachedCancelButton:hover,.aa-DetachedCancelButton:focus{box-shadow:rgba(149,181,64,.6) 0 0 0 1px;outline:currentColor none medium}.aa-DetachedContainer--modal{bottom:inherit;height:auto;margin:0 auto;position:absolute;top:100px;border-radius:6px;max-width:850px}@media(max-width: 575.98px){.aa-DetachedContainer--modal{width:100%;top:0px;border-radius:0px;border:none}}.aa-DetachedContainer--modal .aa-PanelLayout{max-height:var(--aa-detached-modal-max-height);padding-bottom:var(--aa-spacing-half);position:static}.aa-Detached{height:100vh;overflow:hidden}.aa-DetachedOverlay{background-color:rgba(32,32,32,.4);position:fixed;left:0;right:0;top:0;margin:0;padding:0;height:100vh;z-index:1100}.quarto-listing{padding-bottom:1em}.listing-pagination{padding-top:.5em}ul.pagination{float:right;padding-left:8px;padding-top:.5em}ul.pagination li{padding-right:.75em}ul.pagination li.disabled a,ul.pagination li.active a{color:#202020;text-decoration:none}ul.pagination li:last-of-type{padding-right:0}.listing-actions-group{display:flex}.quarto-listing-filter{margin-bottom:1em;width:200px;margin-left:auto}.quarto-listing-sort{margin-bottom:1em;margin-right:auto;width:auto}.quarto-listing-sort .input-group-text{font-size:.8em}.input-group-text{border-right:none}.quarto-listing-sort select.form-select{font-size:.8em}.listing-no-matching{text-align:center;padding-top:2em;padding-bottom:3em;font-size:1em}#quarto-margin-sidebar .quarto-listing-category{padding-top:0;font-size:1rem}#quarto-margin-sidebar .quarto-listing-category-title{cursor:pointer;font-weight:600;font-size:1rem}.quarto-listing-category .category{cursor:pointer}.quarto-listing-category .category.active{font-weight:600}.quarto-listing-category.category-cloud{display:flex;flex-wrap:wrap;align-items:baseline}.quarto-listing-category.category-cloud .category{padding-right:5px}.quarto-listing-category.category-cloud .category-cloud-1{font-size:.75em}.quarto-listing-category.category-cloud .category-cloud-2{font-size:.95em}.quarto-listing-category.category-cloud .category-cloud-3{font-size:1.15em}.quarto-listing-category.category-cloud .category-cloud-4{font-size:1.35em}.quarto-listing-category.category-cloud .category-cloud-5{font-size:1.55em}.quarto-listing-category.category-cloud .category-cloud-6{font-size:1.75em}.quarto-listing-category.category-cloud .category-cloud-7{font-size:1.95em}.quarto-listing-category.category-cloud .category-cloud-8{font-size:2.15em}.quarto-listing-category.category-cloud .category-cloud-9{font-size:2.35em}.quarto-listing-category.category-cloud .category-cloud-10{font-size:2.55em}.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-1{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-2{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-3{grid-template-columns:repeat(3, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-3{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-3{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-4{grid-template-columns:repeat(4, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-4{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-4{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-5{grid-template-columns:repeat(5, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-5{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-5{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-6{grid-template-columns:repeat(6, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-6{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-6{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-7{grid-template-columns:repeat(7, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-7{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-7{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-8{grid-template-columns:repeat(8, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-8{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-8{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-9{grid-template-columns:repeat(9, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-9{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-9{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-10{grid-template-columns:repeat(10, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-10{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-10{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-11{grid-template-columns:repeat(11, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-11{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-11{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-12{grid-template-columns:repeat(12, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-12{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-12{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-grid{gap:1.5em}.quarto-grid-item.borderless{border:none}.quarto-grid-item.borderless .listing-categories .listing-category:last-of-type,.quarto-grid-item.borderless .listing-categories .listing-category:first-of-type{padding-left:0}.quarto-grid-item.borderless .listing-categories .listing-category{border:0}.quarto-grid-link{text-decoration:none;color:inherit}.quarto-grid-link:hover{text-decoration:none;color:inherit}.quarto-grid-item h5.title,.quarto-grid-item .title.h5{margin-top:0;margin-bottom:0}.quarto-grid-item .card-footer{display:flex;justify-content:space-between;font-size:.8em}.quarto-grid-item .card-footer p{margin-bottom:0}.quarto-grid-item p.card-img-top{margin-bottom:0}.quarto-grid-item p.card-img-top>img{object-fit:cover}.quarto-grid-item .card-other-values{margin-top:.5em;font-size:.8em}.quarto-grid-item .card-other-values tr{margin-bottom:.5em}.quarto-grid-item .card-other-values tr>td:first-of-type{font-weight:600;padding-right:1em;padding-left:1em;vertical-align:top}.quarto-grid-item div.post-contents{display:flex;flex-direction:column;text-decoration:none;height:100%}.quarto-grid-item .listing-item-img-placeholder{background-color:#adb5bd;flex-shrink:0}.quarto-grid-item .card-attribution{padding-top:1em;display:flex;gap:1em;text-transform:uppercase;color:#6c757d;font-weight:500;flex-grow:10;align-items:flex-end}.quarto-grid-item .description{padding-bottom:1em}.quarto-grid-item .card-attribution .date{align-self:flex-end}.quarto-grid-item .card-attribution.justify{justify-content:space-between}.quarto-grid-item .card-attribution.start{justify-content:flex-start}.quarto-grid-item .card-attribution.end{justify-content:flex-end}.quarto-grid-item .card-title{margin-bottom:.1em}.quarto-grid-item .card-subtitle{padding-top:.25em}.quarto-grid-item .card-text{font-size:.9em}.quarto-grid-item .listing-reading-time{padding-bottom:.25em}.quarto-grid-item .card-text-small{font-size:.8em}.quarto-grid-item .card-subtitle.subtitle{font-size:.9em;font-weight:600;padding-bottom:.5em}.quarto-grid-item .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}.quarto-grid-item .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}.quarto-grid-item.card-right{text-align:right}.quarto-grid-item.card-right .listing-categories{justify-content:flex-end}.quarto-grid-item.card-left{text-align:left}.quarto-grid-item.card-center{text-align:center}.quarto-grid-item.card-center .listing-description{text-align:justify}.quarto-grid-item.card-center .listing-categories{justify-content:center}table.quarto-listing-table td.image{padding:0px}table.quarto-listing-table td.image img{width:100%;max-width:50px;object-fit:contain}table.quarto-listing-table a{text-decoration:none}table.quarto-listing-table th a{color:inherit}table.quarto-listing-table th a.asc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table th a.desc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table.table-hover td{cursor:pointer}.quarto-post.image-left{flex-direction:row}.quarto-post.image-right{flex-direction:row-reverse}@media(max-width: 767.98px){.quarto-post.image-right,.quarto-post.image-left{gap:0em;flex-direction:column}.quarto-post .metadata{padding-bottom:1em;order:2}.quarto-post .body{order:1}.quarto-post .thumbnail{order:3}}.list.quarto-listing-default div:last-of-type{border-bottom:none}@media(min-width: 992px){.quarto-listing-container-default{margin-right:2em}}div.quarto-post{display:flex;gap:2em;margin-bottom:1.5em;border-bottom:1px solid #dee2e6}@media(max-width: 767.98px){div.quarto-post{padding-bottom:1em}}div.quarto-post .metadata{flex-basis:20%;flex-grow:0;margin-top:.2em;flex-shrink:10}div.quarto-post .thumbnail{flex-basis:30%;flex-grow:0;flex-shrink:0}div.quarto-post .thumbnail img{margin-top:.4em;width:100%;object-fit:cover}div.quarto-post .body{flex-basis:45%;flex-grow:1;flex-shrink:0}div.quarto-post .body h3.listing-title,div.quarto-post .body .listing-title.h3{margin-top:0px;margin-bottom:0px;border-bottom:none}div.quarto-post .body .listing-subtitle{font-size:.875em;margin-bottom:.5em;margin-top:.2em}div.quarto-post .body .description{font-size:.9em}div.quarto-post a{color:#202020;display:flex;flex-direction:column;text-decoration:none}div.quarto-post a div.description{flex-shrink:0}div.quarto-post .metadata{display:flex;flex-direction:column;font-size:.8em;font-family:var(--bs-font-sans-serif);flex-basis:33%}div.quarto-post .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}div.quarto-post .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}div.quarto-post .listing-description{margin-bottom:.5em}div.quarto-about-jolla{display:flex !important;flex-direction:column;align-items:center;margin-top:10%;padding-bottom:1em}div.quarto-about-jolla .about-image{object-fit:cover;margin-left:auto;margin-right:auto;margin-bottom:1.5em}div.quarto-about-jolla img.round{border-radius:50%}div.quarto-about-jolla img.rounded{border-radius:10px}div.quarto-about-jolla .quarto-title h1.title,div.quarto-about-jolla .quarto-title .title.h1{text-align:center}div.quarto-about-jolla .quarto-title .description{text-align:center}div.quarto-about-jolla h2,div.quarto-about-jolla .h2{border-bottom:none}div.quarto-about-jolla .about-sep{width:60%}div.quarto-about-jolla main{text-align:center}div.quarto-about-jolla .about-links{display:flex}@media(min-width: 992px){div.quarto-about-jolla .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-jolla .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-jolla .about-link{color:#535353;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-jolla .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-jolla .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-jolla .about-link:hover{color:#96b43f}div.quarto-about-jolla .about-link i.bi{margin-right:.15em}div.quarto-about-solana{display:flex !important;flex-direction:column;padding-top:3em !important;padding-bottom:1em}div.quarto-about-solana .about-entity{display:flex !important;align-items:start;justify-content:space-between}@media(min-width: 992px){div.quarto-about-solana .about-entity{flex-direction:row}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity{flex-direction:column-reverse;align-items:center;text-align:center}}div.quarto-about-solana .about-entity .entity-contents{display:flex;flex-direction:column}@media(max-width: 767.98px){div.quarto-about-solana .about-entity .entity-contents{width:100%}}div.quarto-about-solana .about-entity .about-image{object-fit:cover}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-image{margin-bottom:1.5em}}div.quarto-about-solana .about-entity img.round{border-radius:50%}div.quarto-about-solana .about-entity img.rounded{border-radius:10px}div.quarto-about-solana .about-entity .about-links{display:flex;justify-content:left;padding-bottom:1.2em}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-solana .about-entity .about-link{color:#535353;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-solana .about-entity .about-link:hover{color:#96b43f}div.quarto-about-solana .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-solana .about-contents{padding-right:1.5em;flex-basis:0;flex-grow:1}div.quarto-about-solana .about-contents main.content{margin-top:0}div.quarto-about-solana .about-contents h2,div.quarto-about-solana .about-contents .h2{border-bottom:none}div.quarto-about-trestles{display:flex !important;flex-direction:row;padding-top:3em !important;padding-bottom:1em}@media(max-width: 991.98px){div.quarto-about-trestles{flex-direction:column;padding-top:0em !important}}div.quarto-about-trestles .about-entity{display:flex !important;flex-direction:column;align-items:center;text-align:center;padding-right:1em}@media(min-width: 992px){div.quarto-about-trestles .about-entity{flex:0 0 42%}}div.quarto-about-trestles .about-entity .about-image{object-fit:cover;margin-bottom:1.5em}div.quarto-about-trestles .about-entity img.round{border-radius:50%}div.quarto-about-trestles .about-entity img.rounded{border-radius:10px}div.quarto-about-trestles .about-entity .about-links{display:flex;justify-content:center}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-trestles .about-entity .about-link{color:#535353;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-trestles .about-entity .about-link:hover{color:#96b43f}div.quarto-about-trestles .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-trestles .about-contents{flex-basis:0;flex-grow:1}div.quarto-about-trestles .about-contents h2,div.quarto-about-trestles .about-contents .h2{border-bottom:none}@media(min-width: 992px){div.quarto-about-trestles .about-contents{border-left:solid 1px #dee2e6;padding-left:1.5em}}div.quarto-about-trestles .about-contents main.content{margin-top:0}div.quarto-about-marquee{padding-bottom:1em}div.quarto-about-marquee .about-contents{display:flex;flex-direction:column}div.quarto-about-marquee .about-image{max-height:550px;margin-bottom:1.5em;object-fit:cover}div.quarto-about-marquee img.round{border-radius:50%}div.quarto-about-marquee img.rounded{border-radius:10px}div.quarto-about-marquee h2,div.quarto-about-marquee .h2{border-bottom:none}div.quarto-about-marquee .about-links{display:flex;justify-content:center;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-marquee .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-marquee .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-marquee .about-link{color:#535353;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-marquee .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-marquee .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-marquee .about-link:hover{color:#96b43f}div.quarto-about-marquee .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-marquee .about-link{border:none}}div.quarto-about-broadside{display:flex;flex-direction:column;padding-bottom:1em}div.quarto-about-broadside .about-main{display:flex !important;padding-top:0 !important}@media(min-width: 992px){div.quarto-about-broadside .about-main{flex-direction:row;align-items:flex-start}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main{flex-direction:column}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main .about-entity{flex-shrink:0;width:100%;height:450px;margin-bottom:1.5em;background-size:cover;background-repeat:no-repeat}}@media(min-width: 992px){div.quarto-about-broadside .about-main .about-entity{flex:0 10 50%;margin-right:1.5em;width:100%;height:100%;background-size:100%;background-repeat:no-repeat}}div.quarto-about-broadside .about-main .about-contents{padding-top:14px;flex:0 0 50%}div.quarto-about-broadside h2,div.quarto-about-broadside .h2{border-bottom:none}div.quarto-about-broadside .about-sep{margin-top:1.5em;width:60%;align-self:center}div.quarto-about-broadside .about-links{display:flex;justify-content:center;column-gap:20px;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-broadside .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-broadside .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-broadside .about-link{color:#535353;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-broadside .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-broadside .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-broadside .about-link:hover{color:#96b43f}div.quarto-about-broadside .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-broadside .about-link{border:none}}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.25rem;color:#202020;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:#202020}.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}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}.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:inline-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}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption{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{caption-side:top;margin-bottom:1.5rem}caption,.table-caption{padding-top:.5rem;padding-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:#6c757d}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}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-wrap}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}.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}div.ansi-escaped-output{font-family:monospace;display:block}/*! +* +* ansi colors from IPython notebook's +* +*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-fg{color:#282c36}.ansi-black-intense-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-fg{color:#b22b31}.ansi-red-intense-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-fg{color:#007427}.ansi-green-intense-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-fg{color:#b27d12}.ansi-yellow-intense-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-fg{color:#0065ca}.ansi-blue-intense-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-fg{color:#a03196}.ansi-magenta-intense-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-fg{color:#258f8f}.ansi-cyan-intense-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-fg{color:#a1a6b2}.ansi-white-intense-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: #202020;--quarto-text-muted: #6c757d;--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.25rem}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:absolute;right:.5em;left:inherit;background-color:rgba(0,0,0,0)}:root{--mermaid-bg-color: #ffffff;--mermaid-edge-color: #E9F2D1;--mermaid-node-fg-color: #202020;--mermaid-fg-color: #202020;--mermaid-fg-color--lighter: #3a3a3a;--mermaid-fg-color--lightest: #535353;--mermaid-font-family: Nunito, Source Sans Pro, Helvetica, sans-serif;--mermaid-label-bg-color: #ffffff;--mermaid-label-fg-color: #95b540;--mermaid-node-bg-color: rgba(149, 181, 64, 0.1);--mermaid-node-fg-color: #202020}@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}.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}.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.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>*{grid-column:page-start/body-content-end}.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;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0);margin-bottom:1em}.zindex-content{z-index:998;transform:translate3d(0, 0, 0)}.zindex-modal{z-index:1055;transform:translate3d(0, 0, 0)}.zindex-over-content{z-index:999;transform:translate3d(0, 0, 0)}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,.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,.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,.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.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{opacity:.9;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{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:#606060}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,caption,.figure-caption{font-size:.9rem}.panel-caption,.figure-caption,figcaption{color:#606060}.table-caption,caption{color:#202020}.quarto-layout-cell[data-ref-parent] caption{color:#606060}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#606060;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse){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:1em}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:#f5f5f5;border:1px solid #f5f5f5;border-radius:.25rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.95rem;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:#606060}.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 code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:#f5f5f5;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:#6c757d;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.toc-left>*,.sidebar.margin-sidebar>*{padding-top:.5em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:#6c757d;margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#96b43f}.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}.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em}.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 h2,.quarto-notebook .h2{border-bottom:none}.sidebar .quarto-alternate-formats a,.sidebar .quarto-alternate-notebooks a{text-decoration:none}.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#96b43f}.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-size:.875rem;font-weight:400;margin-bottom:.5rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2{margin-top:1rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.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 .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul,.sidebar nav[role=doc-toc] ul{padding-left:0;list-style:none;font-size:.875rem;font-weight:300}.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 #96b43f;color:#96b43f !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#96b43f !important}kbd,.kbd{color:#202020;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}div.hanging-indent{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}.table a{word-break:break-word}.table>thead{border-top-width:1px;border-top-color:#dee2e6;border-bottom:1px solid #a0a0a0}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.25rem;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.callout-titled .callout-body{margin-top:.2em}.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 div.callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body>:first-child{margin-top:.5em}.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){margin-bottom:.5rem}.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:#6c757d}div.callout.callout-style-default>.callout-header{background-color:#6c757d}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 .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:.25rem;border-bottom-right-radius:.25rem;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:#202020}.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}.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 .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{color:#4d5045;background-color:#e9f2d1;border-color:#e9f2d1}.btn.btn-quarto:hover,div.cell-output-display .btn-quarto:hover{color:#4d5045;background-color:#ecf4d8;border-color:#ebf3d6}.btn-check:focus+.btn.btn-quarto,.btn.btn-quarto:focus,.btn-check:focus+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:focus{color:#4d5045;background-color:#ecf4d8;border-color:#ebf3d6;box-shadow:0 0 0 .25rem rgba(210,218,188,.5)}.btn-check:checked+.btn.btn-quarto,.btn-check:active+.btn.btn-quarto,.btn.btn-quarto:active,.btn.btn-quarto.active,.show>.btn.btn-quarto.dropdown-toggle,.btn-check:checked+div.cell-output-display .btn-quarto,.btn-check:active+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:active,div.cell-output-display .btn-quarto.active,.show>div.cell-output-display .btn-quarto.dropdown-toggle{color:#000;background-color:#edf5da;border-color:#ebf3d6}.btn-check:checked+.btn.btn-quarto:focus,.btn-check:active+.btn.btn-quarto:focus,.btn.btn-quarto:active:focus,.btn.btn-quarto.active:focus,.show>.btn.btn-quarto.dropdown-toggle:focus,.btn-check:checked+div.cell-output-display .btn-quarto:focus,.btn-check:active+div.cell-output-display .btn-quarto:focus,div.cell-output-display .btn-quarto:active:focus,div.cell-output-display .btn-quarto.active:focus,.show>div.cell-output-display .btn-quarto.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(210,218,188,.5)}.btn.btn-quarto:disabled,.btn.btn-quarto.disabled,div.cell-output-display .btn-quarto:disabled,div.cell-output-display .btn-quarto.disabled{color:#000;background-color:#e9f2d1;border-color:#e9f2d1}nav.quarto-secondary-nav.color-navbar{background-color:#e9f2d1;color:#4d5045}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#4d5045}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:0}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:#f5f5f5}.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:var(--bs-font-monospace);color:#3a3a3a;border:solid #3a3a3a 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:#f5f5f5;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:var(--bs-font-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}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;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.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;transform:translate3d(0, 0, 0);margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table>thead{border-top-width:0}.table>:not(caption)>*:not(:last-child)>*{border-bottom-color:#d3d3d3;border-bottom-style:solid;border-bottom-width:1px}.table>:not(:first-child){border-top:1px solid #a0a0a0;border-bottom:1px solid inherit}.table tbody{border-bottom-color:#a0a0a0}a.external:after{display:inline-block;height:.75rem;width:.75rem;margin-bottom:.15em;margin-left:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}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,.code-with-filename .code-with-filename-file pre{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file,.quarto-dark .code-with-filename .code-with-filename-file pre{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#4d5045;background:#e9f2d1}.quarto-title-banner .code-tools-button{color:#828774}.quarto-title-banner .code-tools-button:hover{color:#4d5045}.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}}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:.25rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr)}#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:-5px}#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 a{color:#202020}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.7em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#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 .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#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 .description .abstract-title,#title-block-header.quarto-title-block.default .abstract .abstract-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:1fr 1fr}.quarto-title-tools-only{display:flex;justify-content:right}.largest{font-size:1.953em}.larger{font-size:1.563em}.large{font-size:1.25em}.small{font-size:.8em}.smaller{font-size:.64em}.smallest{font-size:.512em}.highlight{background-color:#95b540;color:#fff;font-size:.85em;padding:.2em .3em;border-radius:4px;vertical-align:baseline}.navbar-nav{font-size:.85em;letter-spacing:.1em}.navbar-logo{max-height:20px}.contents-table table{line-height:1.2}.listing-image img{height:40px;width:60px;object-fit:cover}.shadow{box-shadow:2px 2px 10px #d3d3d3}.sourceCode,div.sourceCode{font-size:.875rem;border-radius:0}.alert{border-radius:0}.call-out,.callout-style-default{border-radius:0 !important}div.callout{border-left-color:#dee2e6}div.callout.callout,.callout.callout-style-default{border-left:1px solid;border-left-color:#dee2e6}div.callout-note.callout-style-default>.callout-header{background-color:#e9f2d1}.table-schedule .topic{color:#fff;font-weight:bold;border-radius:4px;padding:1px 4px;background:#bdbdbd}.table-schedule .marker{color:#95b540;margin-left:5px;margin-right:5px}.table-schedule td p{margin-bottom:0;padding:5px 0px}.tooltip-text{visibility:hidden;position:absolute;z-index:1;width:fit-content;color:#fff;background-color:#95b540;padding:5px;border-radius:4px}.hover-text:hover .tooltip-text{visibility:visible}.top{top:-55px;left:-60%}.hover-text{position:relative;display:inline-block;text-align:center}.reveal .callout.callout-captioned .callout-icon::before{margin-top:.5rem;scale:.8}.reveal .slides section[data-vertical-align-top]{top:0 !important}.reveal .blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#5a6570;padding:.625rem 1.25rem;border-left:.25rem solid #ecf0f1;margin-bottom:1rem}.reveal .left{display:block;text-align:left}.reveal .center{display:block;text-align:center}.reveal .right{display:block;text-align:right}.reveal pre{font-size:.92em;line-height:1.3;margin-bottom:.5em}.reveal pre,.reveal code{border-radius:6px;border:0 !important}.reveal code{font-size:.9em;padding-left:4px;padding-right:4px}.reveal div.sourceCode{border:0 !important;border-radius:6px;margin-bottom:.6em !important}.reveal pre code{background-color:#f5f5f5 !important;border-radius:6px}.reveal .slide-number{font-family:"Source Sans Pro"}.reveal .slide ul,.reveal .slide ol{line-height:1.2}.reveal .slide ul li,.reveal .slide ol li{margin-top:.05em !important;margin-bottom:.05em !important}.reveal table{font-size:.8em !important;margin:0}.reveal .dataTables_wrapper .dataTables_length,.reveal .dataTables_wrapper .dataTables_filter,.reveal .dataTables_wrapper .dataTables_info,.reveal .dataTables_wrapper .dataTables_processing,.reveal .dataTables_wrapper .dataTables_paginate{font-size:.8em}.reveal .panel-tabset [role=tab][aria-selected=true]{border:#d3d3d3 2px solid;border-radius:6px 6px 0px 0px;border-bottom:none}.reveal .panel-tabset .tab-content{border-top:#d3d3d3 2px solid}.reveal .bottom-align{bottom:0}.reveal .header-logo-right img{max-width:max(40px,9vw)}.reveal .header-logo-left img{max-width:max(30px,5vw)}.reveal #title-slide{text-align:left !important;bottom:0;top:auto !important}.reveal #title-slide .title{font-size:1.802em;margin:0}.reveal #title-slide .subtitle{font-size:1.602em;margin:0;margin-bottom:1rem !important}.reveal #title-slide .quarto-title-authors{font-size:1.424em;display:block;margin:0;padding-left:0}.reveal #title-slide .quarto-title-author{padding-left:0}.reveal #title-slide .institute{font-size:1.266em;margin:0}.reveal #title-slide .date{font-size:1.266em;margin:0}.reveal .slide-background-content{background-position:right}.reveal .citation,.reveal .citation a:hover{font-size:.8em;color:#d3d3d3}.reveal .citation a{font-size:.8em;color:gray}.references{font-size:.7rem}/*# sourceMappingURL=9161419e6f82ea4435380a70856fa72b.css.map */ diff --git a/2311/site_libs/bootstrap/bootstrap.min.js b/2311/site_libs/bootstrap/bootstrap.min.js new file mode 100644 index 00000000..cc0a2556 --- /dev/null +++ b/2311/site_libs/bootstrap/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 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="transitionend",e=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 e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},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(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=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?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();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?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);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})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=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 L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),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(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.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.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").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(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.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(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{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=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={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;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;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=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={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];zt(s)&&Rt(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}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(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 Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(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 ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={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=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(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,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-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)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(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=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={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:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(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,de(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 fe={passive:!0};const pe={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=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(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?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,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]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={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,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.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"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(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 Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={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=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(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})}},Ie={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=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].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,[bt,_t].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}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={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=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(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 Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_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}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.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(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_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)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_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}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||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,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_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(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.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)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["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:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),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=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_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"function"==typeof t?t.call(this._element):t}_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:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?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()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_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(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/2311/site_libs/clipboard/clipboard.min.js b/2311/site_libs/clipboard/clipboard.min.js new file mode 100644 index 00000000..1103f811 --- /dev/null +++ b/2311/site_libs/clipboard/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * 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=1li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} +/*# sourceMappingURL=bootstrap-theme.min.css.map */ \ No newline at end of file diff --git a/2311/site_libs/fontawesome-4.7.0/bootstrap.min.css b/2311/site_libs/fontawesome-4.7.0/bootstrap.min.css new file mode 100644 index 00000000..3b9ff914 --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(fonts/glyphicons-halflings-regular.eot);src:url(fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(fonts/glyphicons-halflings-regular.woff) format('woff'),url(fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ diff --git a/2311/site_libs/fontawesome-4.7.0/bootstrap.min.js b/2311/site_libs/fontawesome-4.7.0/bootstrap.min.js new file mode 100644 index 00000000..9bcd2fcc --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under the MIT license + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/2311/site_libs/fontawesome-4.7.0/font-awesome.min.css b/2311/site_libs/fontawesome-4.7.0/font-awesome.min.css new file mode 100644 index 00000000..1401f2c5 --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('fonts/fontawesome-webfont.eot?v=4.7.0');src:url('fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/FontAwesome.otf b/2311/site_libs/fontawesome-4.7.0/fonts/FontAwesome.otf new file mode 100644 index 00000000..401ec0f3 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/FontAwesome.otf differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.eot b/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.eot differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.svg b/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.ttf b/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.ttf differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.woff b/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/fontawesome-webfont.woff differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.eot b/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 00000000..b93a4953 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.eot differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.svg b/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 00000000..94fb5490 --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.ttf b/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 00000000..1413fc60 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.ttf differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.woff b/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 00000000..9e612858 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/glyphicons-halflings-regular.woff differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.eot b/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.eot new file mode 100644 index 00000000..9caa3489 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.eot differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.svg b/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.svg new file mode 100644 index 00000000..2a47a0f9 --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.svg @@ -0,0 +1,2230 @@ + + + + + +Created by FontForge 20120731 at Wed Jan 14 22:40:14 2015 + By Adam Bradley +Created by Adam Bradley with FontForge 2.0 (http://fontforge.sf.net) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.ttf b/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.ttf new file mode 100644 index 00000000..180ce515 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.ttf differ diff --git a/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.woff b/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.woff new file mode 100644 index 00000000..5bb6aecb Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/fonts/ionicons.woff differ diff --git a/2311/site_libs/fontawesome-4.7.0/images/markers-matte.png b/2311/site_libs/fontawesome-4.7.0/images/markers-matte.png new file mode 100644 index 00000000..17825866 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/images/markers-matte.png differ diff --git a/2311/site_libs/fontawesome-4.7.0/images/markers-matte@2x.png b/2311/site_libs/fontawesome-4.7.0/images/markers-matte@2x.png new file mode 100644 index 00000000..c981244d Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/images/markers-matte@2x.png differ diff --git a/2311/site_libs/fontawesome-4.7.0/images/markers-plain.png b/2311/site_libs/fontawesome-4.7.0/images/markers-plain.png new file mode 100644 index 00000000..763f3589 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/images/markers-plain.png differ diff --git a/2311/site_libs/fontawesome-4.7.0/images/markers-shadow.png b/2311/site_libs/fontawesome-4.7.0/images/markers-shadow.png new file mode 100644 index 00000000..33cf9550 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/images/markers-shadow.png differ diff --git a/2311/site_libs/fontawesome-4.7.0/images/markers-shadow@2x.png b/2311/site_libs/fontawesome-4.7.0/images/markers-shadow@2x.png new file mode 100644 index 00000000..1116503f Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/images/markers-shadow@2x.png differ diff --git a/2311/site_libs/fontawesome-4.7.0/images/markers-soft.png b/2311/site_libs/fontawesome-4.7.0/images/markers-soft.png new file mode 100644 index 00000000..acc83154 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/images/markers-soft.png differ diff --git a/2311/site_libs/fontawesome-4.7.0/images/markers-soft@2x.png b/2311/site_libs/fontawesome-4.7.0/images/markers-soft@2x.png new file mode 100644 index 00000000..b3acfbf9 Binary files /dev/null and b/2311/site_libs/fontawesome-4.7.0/images/markers-soft@2x.png differ diff --git a/2311/site_libs/fontawesome-4.7.0/ionicons.min.css b/2311/site_libs/fontawesome-4.7.0/ionicons.min.css new file mode 100644 index 00000000..cef8e11c --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/ionicons.min.css @@ -0,0 +1,11 @@ +@charset "UTF-8";/*! + Ionicons, v2.0.1 + Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ + https://twitter.com/benjsperry https://twitter.com/ionicframework + MIT License: https://github.com/driftyco/ionicons + + Android-style icons originally built by Google’s + Material Design Icons: https://github.com/google/material-design-icons + used under CC BY http://creativecommons.org/licenses/by/4.0/ + Modified icons to fit ionicon’s grid from original. +*/@font-face{font-family:"Ionicons";src:url("fonts/ionicons.eot?v=2.0.1");src:url("fonts/ionicons.eot?v=2.0.1#iefix") format("embedded-opentype"),url("fonts/ionicons.ttf?v=2.0.1") format("truetype"),url("fonts/ionicons.woff?v=2.0.1") format("woff"),url("fonts/ionicons.svg?v=2.0.1#Ionicons") format("svg");font-weight:normal;font-style:normal}.ion,.ionicons,.ion-alert:before,.ion-alert-circled:before,.ion-android-add:before,.ion-android-add-circle:before,.ion-android-alarm-clock:before,.ion-android-alert:before,.ion-android-apps:before,.ion-android-archive:before,.ion-android-arrow-back:before,.ion-android-arrow-down:before,.ion-android-arrow-dropdown:before,.ion-android-arrow-dropdown-circle:before,.ion-android-arrow-dropleft:before,.ion-android-arrow-dropleft-circle:before,.ion-android-arrow-dropright:before,.ion-android-arrow-dropright-circle:before,.ion-android-arrow-dropup:before,.ion-android-arrow-dropup-circle:before,.ion-android-arrow-forward:before,.ion-android-arrow-up:before,.ion-android-attach:before,.ion-android-bar:before,.ion-android-bicycle:before,.ion-android-boat:before,.ion-android-bookmark:before,.ion-android-bulb:before,.ion-android-bus:before,.ion-android-calendar:before,.ion-android-call:before,.ion-android-camera:before,.ion-android-cancel:before,.ion-android-car:before,.ion-android-cart:before,.ion-android-chat:before,.ion-android-checkbox:before,.ion-android-checkbox-blank:before,.ion-android-checkbox-outline:before,.ion-android-checkbox-outline-blank:before,.ion-android-checkmark-circle:before,.ion-android-clipboard:before,.ion-android-close:before,.ion-android-cloud:before,.ion-android-cloud-circle:before,.ion-android-cloud-done:before,.ion-android-cloud-outline:before,.ion-android-color-palette:before,.ion-android-compass:before,.ion-android-contact:before,.ion-android-contacts:before,.ion-android-contract:before,.ion-android-create:before,.ion-android-delete:before,.ion-android-desktop:before,.ion-android-document:before,.ion-android-done:before,.ion-android-done-all:before,.ion-android-download:before,.ion-android-drafts:before,.ion-android-exit:before,.ion-android-expand:before,.ion-android-favorite:before,.ion-android-favorite-outline:before,.ion-android-film:before,.ion-android-folder:before,.ion-android-folder-open:before,.ion-android-funnel:before,.ion-android-globe:before,.ion-android-hand:before,.ion-android-hangout:before,.ion-android-happy:before,.ion-android-home:before,.ion-android-image:before,.ion-android-laptop:before,.ion-android-list:before,.ion-android-locate:before,.ion-android-lock:before,.ion-android-mail:before,.ion-android-map:before,.ion-android-menu:before,.ion-android-microphone:before,.ion-android-microphone-off:before,.ion-android-more-horizontal:before,.ion-android-more-vertical:before,.ion-android-navigate:before,.ion-android-notifications:before,.ion-android-notifications-none:before,.ion-android-notifications-off:before,.ion-android-open:before,.ion-android-options:before,.ion-android-people:before,.ion-android-person:before,.ion-android-person-add:before,.ion-android-phone-landscape:before,.ion-android-phone-portrait:before,.ion-android-pin:before,.ion-android-plane:before,.ion-android-playstore:before,.ion-android-print:before,.ion-android-radio-button-off:before,.ion-android-radio-button-on:before,.ion-android-refresh:before,.ion-android-remove:before,.ion-android-remove-circle:before,.ion-android-restaurant:before,.ion-android-sad:before,.ion-android-search:before,.ion-android-send:before,.ion-android-settings:before,.ion-android-share:before,.ion-android-share-alt:before,.ion-android-star:before,.ion-android-star-half:before,.ion-android-star-outline:before,.ion-android-stopwatch:before,.ion-android-subway:before,.ion-android-sunny:before,.ion-android-sync:before,.ion-android-textsms:before,.ion-android-time:before,.ion-android-train:before,.ion-android-unlock:before,.ion-android-upload:before,.ion-android-volume-down:before,.ion-android-volume-mute:before,.ion-android-volume-off:before,.ion-android-volume-up:before,.ion-android-walk:before,.ion-android-warning:before,.ion-android-watch:before,.ion-android-wifi:before,.ion-aperture:before,.ion-archive:before,.ion-arrow-down-a:before,.ion-arrow-down-b:before,.ion-arrow-down-c:before,.ion-arrow-expand:before,.ion-arrow-graph-down-left:before,.ion-arrow-graph-down-right:before,.ion-arrow-graph-up-left:before,.ion-arrow-graph-up-right:before,.ion-arrow-left-a:before,.ion-arrow-left-b:before,.ion-arrow-left-c:before,.ion-arrow-move:before,.ion-arrow-resize:before,.ion-arrow-return-left:before,.ion-arrow-return-right:before,.ion-arrow-right-a:before,.ion-arrow-right-b:before,.ion-arrow-right-c:before,.ion-arrow-shrink:before,.ion-arrow-swap:before,.ion-arrow-up-a:before,.ion-arrow-up-b:before,.ion-arrow-up-c:before,.ion-asterisk:before,.ion-at:before,.ion-backspace:before,.ion-backspace-outline:before,.ion-bag:before,.ion-battery-charging:before,.ion-battery-empty:before,.ion-battery-full:before,.ion-battery-half:before,.ion-battery-low:before,.ion-beaker:before,.ion-beer:before,.ion-bluetooth:before,.ion-bonfire:before,.ion-bookmark:before,.ion-bowtie:before,.ion-briefcase:before,.ion-bug:before,.ion-calculator:before,.ion-calendar:before,.ion-camera:before,.ion-card:before,.ion-cash:before,.ion-chatbox:before,.ion-chatbox-working:before,.ion-chatboxes:before,.ion-chatbubble:before,.ion-chatbubble-working:before,.ion-chatbubbles:before,.ion-checkmark:before,.ion-checkmark-circled:before,.ion-checkmark-round:before,.ion-chevron-down:before,.ion-chevron-left:before,.ion-chevron-right:before,.ion-chevron-up:before,.ion-clipboard:before,.ion-clock:before,.ion-close:before,.ion-close-circled:before,.ion-close-round:before,.ion-closed-captioning:before,.ion-cloud:before,.ion-code:before,.ion-code-download:before,.ion-code-working:before,.ion-coffee:before,.ion-compass:before,.ion-compose:before,.ion-connection-bars:before,.ion-contrast:before,.ion-crop:before,.ion-cube:before,.ion-disc:before,.ion-document:before,.ion-document-text:before,.ion-drag:before,.ion-earth:before,.ion-easel:before,.ion-edit:before,.ion-egg:before,.ion-eject:before,.ion-email:before,.ion-email-unread:before,.ion-erlenmeyer-flask:before,.ion-erlenmeyer-flask-bubbles:before,.ion-eye:before,.ion-eye-disabled:before,.ion-female:before,.ion-filing:before,.ion-film-marker:before,.ion-fireball:before,.ion-flag:before,.ion-flame:before,.ion-flash:before,.ion-flash-off:before,.ion-folder:before,.ion-fork:before,.ion-fork-repo:before,.ion-forward:before,.ion-funnel:before,.ion-gear-a:before,.ion-gear-b:before,.ion-grid:before,.ion-hammer:before,.ion-happy:before,.ion-happy-outline:before,.ion-headphone:before,.ion-heart:before,.ion-heart-broken:before,.ion-help:before,.ion-help-buoy:before,.ion-help-circled:before,.ion-home:before,.ion-icecream:before,.ion-image:before,.ion-images:before,.ion-information:before,.ion-information-circled:before,.ion-ionic:before,.ion-ios-alarm:before,.ion-ios-alarm-outline:before,.ion-ios-albums:before,.ion-ios-albums-outline:before,.ion-ios-americanfootball:before,.ion-ios-americanfootball-outline:before,.ion-ios-analytics:before,.ion-ios-analytics-outline:before,.ion-ios-arrow-back:before,.ion-ios-arrow-down:before,.ion-ios-arrow-forward:before,.ion-ios-arrow-left:before,.ion-ios-arrow-right:before,.ion-ios-arrow-thin-down:before,.ion-ios-arrow-thin-left:before,.ion-ios-arrow-thin-right:before,.ion-ios-arrow-thin-up:before,.ion-ios-arrow-up:before,.ion-ios-at:before,.ion-ios-at-outline:before,.ion-ios-barcode:before,.ion-ios-barcode-outline:before,.ion-ios-baseball:before,.ion-ios-baseball-outline:before,.ion-ios-basketball:before,.ion-ios-basketball-outline:before,.ion-ios-bell:before,.ion-ios-bell-outline:before,.ion-ios-body:before,.ion-ios-body-outline:before,.ion-ios-bolt:before,.ion-ios-bolt-outline:before,.ion-ios-book:before,.ion-ios-book-outline:before,.ion-ios-bookmarks:before,.ion-ios-bookmarks-outline:before,.ion-ios-box:before,.ion-ios-box-outline:before,.ion-ios-briefcase:before,.ion-ios-briefcase-outline:before,.ion-ios-browsers:before,.ion-ios-browsers-outline:before,.ion-ios-calculator:before,.ion-ios-calculator-outline:before,.ion-ios-calendar:before,.ion-ios-calendar-outline:before,.ion-ios-camera:before,.ion-ios-camera-outline:before,.ion-ios-cart:before,.ion-ios-cart-outline:before,.ion-ios-chatboxes:before,.ion-ios-chatboxes-outline:before,.ion-ios-chatbubble:before,.ion-ios-chatbubble-outline:before,.ion-ios-checkmark:before,.ion-ios-checkmark-empty:before,.ion-ios-checkmark-outline:before,.ion-ios-circle-filled:before,.ion-ios-circle-outline:before,.ion-ios-clock:before,.ion-ios-clock-outline:before,.ion-ios-close:before,.ion-ios-close-empty:before,.ion-ios-close-outline:before,.ion-ios-cloud:before,.ion-ios-cloud-download:before,.ion-ios-cloud-download-outline:before,.ion-ios-cloud-outline:before,.ion-ios-cloud-upload:before,.ion-ios-cloud-upload-outline:before,.ion-ios-cloudy:before,.ion-ios-cloudy-night:before,.ion-ios-cloudy-night-outline:before,.ion-ios-cloudy-outline:before,.ion-ios-cog:before,.ion-ios-cog-outline:before,.ion-ios-color-filter:before,.ion-ios-color-filter-outline:before,.ion-ios-color-wand:before,.ion-ios-color-wand-outline:before,.ion-ios-compose:before,.ion-ios-compose-outline:before,.ion-ios-contact:before,.ion-ios-contact-outline:before,.ion-ios-copy:before,.ion-ios-copy-outline:before,.ion-ios-crop:before,.ion-ios-crop-strong:before,.ion-ios-download:before,.ion-ios-download-outline:before,.ion-ios-drag:before,.ion-ios-email:before,.ion-ios-email-outline:before,.ion-ios-eye:before,.ion-ios-eye-outline:before,.ion-ios-fastforward:before,.ion-ios-fastforward-outline:before,.ion-ios-filing:before,.ion-ios-filing-outline:before,.ion-ios-film:before,.ion-ios-film-outline:before,.ion-ios-flag:before,.ion-ios-flag-outline:before,.ion-ios-flame:before,.ion-ios-flame-outline:before,.ion-ios-flask:before,.ion-ios-flask-outline:before,.ion-ios-flower:before,.ion-ios-flower-outline:before,.ion-ios-folder:before,.ion-ios-folder-outline:before,.ion-ios-football:before,.ion-ios-football-outline:before,.ion-ios-game-controller-a:before,.ion-ios-game-controller-a-outline:before,.ion-ios-game-controller-b:before,.ion-ios-game-controller-b-outline:before,.ion-ios-gear:before,.ion-ios-gear-outline:before,.ion-ios-glasses:before,.ion-ios-glasses-outline:before,.ion-ios-grid-view:before,.ion-ios-grid-view-outline:before,.ion-ios-heart:before,.ion-ios-heart-outline:before,.ion-ios-help:before,.ion-ios-help-empty:before,.ion-ios-help-outline:before,.ion-ios-home:before,.ion-ios-home-outline:before,.ion-ios-infinite:before,.ion-ios-infinite-outline:before,.ion-ios-information:before,.ion-ios-information-empty:before,.ion-ios-information-outline:before,.ion-ios-ionic-outline:before,.ion-ios-keypad:before,.ion-ios-keypad-outline:before,.ion-ios-lightbulb:before,.ion-ios-lightbulb-outline:before,.ion-ios-list:before,.ion-ios-list-outline:before,.ion-ios-location:before,.ion-ios-location-outline:before,.ion-ios-locked:before,.ion-ios-locked-outline:before,.ion-ios-loop:before,.ion-ios-loop-strong:before,.ion-ios-medical:before,.ion-ios-medical-outline:before,.ion-ios-medkit:before,.ion-ios-medkit-outline:before,.ion-ios-mic:before,.ion-ios-mic-off:before,.ion-ios-mic-outline:before,.ion-ios-minus:before,.ion-ios-minus-empty:before,.ion-ios-minus-outline:before,.ion-ios-monitor:before,.ion-ios-monitor-outline:before,.ion-ios-moon:before,.ion-ios-moon-outline:before,.ion-ios-more:before,.ion-ios-more-outline:before,.ion-ios-musical-note:before,.ion-ios-musical-notes:before,.ion-ios-navigate:before,.ion-ios-navigate-outline:before,.ion-ios-nutrition:before,.ion-ios-nutrition-outline:before,.ion-ios-paper:before,.ion-ios-paper-outline:before,.ion-ios-paperplane:before,.ion-ios-paperplane-outline:before,.ion-ios-partlysunny:before,.ion-ios-partlysunny-outline:before,.ion-ios-pause:before,.ion-ios-pause-outline:before,.ion-ios-paw:before,.ion-ios-paw-outline:before,.ion-ios-people:before,.ion-ios-people-outline:before,.ion-ios-person:before,.ion-ios-person-outline:before,.ion-ios-personadd:before,.ion-ios-personadd-outline:before,.ion-ios-photos:before,.ion-ios-photos-outline:before,.ion-ios-pie:before,.ion-ios-pie-outline:before,.ion-ios-pint:before,.ion-ios-pint-outline:before,.ion-ios-play:before,.ion-ios-play-outline:before,.ion-ios-plus:before,.ion-ios-plus-empty:before,.ion-ios-plus-outline:before,.ion-ios-pricetag:before,.ion-ios-pricetag-outline:before,.ion-ios-pricetags:before,.ion-ios-pricetags-outline:before,.ion-ios-printer:before,.ion-ios-printer-outline:before,.ion-ios-pulse:before,.ion-ios-pulse-strong:before,.ion-ios-rainy:before,.ion-ios-rainy-outline:before,.ion-ios-recording:before,.ion-ios-recording-outline:before,.ion-ios-redo:before,.ion-ios-redo-outline:before,.ion-ios-refresh:before,.ion-ios-refresh-empty:before,.ion-ios-refresh-outline:before,.ion-ios-reload:before,.ion-ios-reverse-camera:before,.ion-ios-reverse-camera-outline:before,.ion-ios-rewind:before,.ion-ios-rewind-outline:before,.ion-ios-rose:before,.ion-ios-rose-outline:before,.ion-ios-search:before,.ion-ios-search-strong:before,.ion-ios-settings:before,.ion-ios-settings-strong:before,.ion-ios-shuffle:before,.ion-ios-shuffle-strong:before,.ion-ios-skipbackward:before,.ion-ios-skipbackward-outline:before,.ion-ios-skipforward:before,.ion-ios-skipforward-outline:before,.ion-ios-snowy:before,.ion-ios-speedometer:before,.ion-ios-speedometer-outline:before,.ion-ios-star:before,.ion-ios-star-half:before,.ion-ios-star-outline:before,.ion-ios-stopwatch:before,.ion-ios-stopwatch-outline:before,.ion-ios-sunny:before,.ion-ios-sunny-outline:before,.ion-ios-telephone:before,.ion-ios-telephone-outline:before,.ion-ios-tennisball:before,.ion-ios-tennisball-outline:before,.ion-ios-thunderstorm:before,.ion-ios-thunderstorm-outline:before,.ion-ios-time:before,.ion-ios-time-outline:before,.ion-ios-timer:before,.ion-ios-timer-outline:before,.ion-ios-toggle:before,.ion-ios-toggle-outline:before,.ion-ios-trash:before,.ion-ios-trash-outline:before,.ion-ios-undo:before,.ion-ios-undo-outline:before,.ion-ios-unlocked:before,.ion-ios-unlocked-outline:before,.ion-ios-upload:before,.ion-ios-upload-outline:before,.ion-ios-videocam:before,.ion-ios-videocam-outline:before,.ion-ios-volume-high:before,.ion-ios-volume-low:before,.ion-ios-wineglass:before,.ion-ios-wineglass-outline:before,.ion-ios-world:before,.ion-ios-world-outline:before,.ion-ipad:before,.ion-iphone:before,.ion-ipod:before,.ion-jet:before,.ion-key:before,.ion-knife:before,.ion-laptop:before,.ion-leaf:before,.ion-levels:before,.ion-lightbulb:before,.ion-link:before,.ion-load-a:before,.ion-load-b:before,.ion-load-c:before,.ion-load-d:before,.ion-location:before,.ion-lock-combination:before,.ion-locked:before,.ion-log-in:before,.ion-log-out:before,.ion-loop:before,.ion-magnet:before,.ion-male:before,.ion-man:before,.ion-map:before,.ion-medkit:before,.ion-merge:before,.ion-mic-a:before,.ion-mic-b:before,.ion-mic-c:before,.ion-minus:before,.ion-minus-circled:before,.ion-minus-round:before,.ion-model-s:before,.ion-monitor:before,.ion-more:before,.ion-mouse:before,.ion-music-note:before,.ion-navicon:before,.ion-navicon-round:before,.ion-navigate:before,.ion-network:before,.ion-no-smoking:before,.ion-nuclear:before,.ion-outlet:before,.ion-paintbrush:before,.ion-paintbucket:before,.ion-paper-airplane:before,.ion-paperclip:before,.ion-pause:before,.ion-person:before,.ion-person-add:before,.ion-person-stalker:before,.ion-pie-graph:before,.ion-pin:before,.ion-pinpoint:before,.ion-pizza:before,.ion-plane:before,.ion-planet:before,.ion-play:before,.ion-playstation:before,.ion-plus:before,.ion-plus-circled:before,.ion-plus-round:before,.ion-podium:before,.ion-pound:before,.ion-power:before,.ion-pricetag:before,.ion-pricetags:before,.ion-printer:before,.ion-pull-request:before,.ion-qr-scanner:before,.ion-quote:before,.ion-radio-waves:before,.ion-record:before,.ion-refresh:before,.ion-reply:before,.ion-reply-all:before,.ion-ribbon-a:before,.ion-ribbon-b:before,.ion-sad:before,.ion-sad-outline:before,.ion-scissors:before,.ion-search:before,.ion-settings:before,.ion-share:before,.ion-shuffle:before,.ion-skip-backward:before,.ion-skip-forward:before,.ion-social-android:before,.ion-social-android-outline:before,.ion-social-angular:before,.ion-social-angular-outline:before,.ion-social-apple:before,.ion-social-apple-outline:before,.ion-social-bitcoin:before,.ion-social-bitcoin-outline:before,.ion-social-buffer:before,.ion-social-buffer-outline:before,.ion-social-chrome:before,.ion-social-chrome-outline:before,.ion-social-codepen:before,.ion-social-codepen-outline:before,.ion-social-css3:before,.ion-social-css3-outline:before,.ion-social-designernews:before,.ion-social-designernews-outline:before,.ion-social-dribbble:before,.ion-social-dribbble-outline:before,.ion-social-dropbox:before,.ion-social-dropbox-outline:before,.ion-social-euro:before,.ion-social-euro-outline:before,.ion-social-facebook:before,.ion-social-facebook-outline:before,.ion-social-foursquare:before,.ion-social-foursquare-outline:before,.ion-social-freebsd-devil:before,.ion-social-github:before,.ion-social-github-outline:before,.ion-social-google:before,.ion-social-google-outline:before,.ion-social-googleplus:before,.ion-social-googleplus-outline:before,.ion-social-hackernews:before,.ion-social-hackernews-outline:before,.ion-social-html5:before,.ion-social-html5-outline:before,.ion-social-instagram:before,.ion-social-instagram-outline:before,.ion-social-javascript:before,.ion-social-javascript-outline:before,.ion-social-linkedin:before,.ion-social-linkedin-outline:before,.ion-social-markdown:before,.ion-social-nodejs:before,.ion-social-octocat:before,.ion-social-pinterest:before,.ion-social-pinterest-outline:before,.ion-social-python:before,.ion-social-reddit:before,.ion-social-reddit-outline:before,.ion-social-rss:before,.ion-social-rss-outline:before,.ion-social-sass:before,.ion-social-skype:before,.ion-social-skype-outline:before,.ion-social-snapchat:before,.ion-social-snapchat-outline:before,.ion-social-tumblr:before,.ion-social-tumblr-outline:before,.ion-social-tux:before,.ion-social-twitch:before,.ion-social-twitch-outline:before,.ion-social-twitter:before,.ion-social-twitter-outline:before,.ion-social-usd:before,.ion-social-usd-outline:before,.ion-social-vimeo:before,.ion-social-vimeo-outline:before,.ion-social-whatsapp:before,.ion-social-whatsapp-outline:before,.ion-social-windows:before,.ion-social-windows-outline:before,.ion-social-wordpress:before,.ion-social-wordpress-outline:before,.ion-social-yahoo:before,.ion-social-yahoo-outline:before,.ion-social-yen:before,.ion-social-yen-outline:before,.ion-social-youtube:before,.ion-social-youtube-outline:before,.ion-soup-can:before,.ion-soup-can-outline:before,.ion-speakerphone:before,.ion-speedometer:before,.ion-spoon:before,.ion-star:before,.ion-stats-bars:before,.ion-steam:before,.ion-stop:before,.ion-thermometer:before,.ion-thumbsdown:before,.ion-thumbsup:before,.ion-toggle:before,.ion-toggle-filled:before,.ion-transgender:before,.ion-trash-a:before,.ion-trash-b:before,.ion-trophy:before,.ion-tshirt:before,.ion-tshirt-outline:before,.ion-umbrella:before,.ion-university:before,.ion-unlocked:before,.ion-upload:before,.ion-usb:before,.ion-videocamera:before,.ion-volume-high:before,.ion-volume-low:before,.ion-volume-medium:before,.ion-volume-mute:before,.ion-wand:before,.ion-waterdrop:before,.ion-wifi:before,.ion-wineglass:before,.ion-woman:before,.ion-wrench:before,.ion-xbox:before{display:inline-block;font-family:"Ionicons";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ion-alert:before{content:"\f101"}.ion-alert-circled:before{content:"\f100"}.ion-android-add:before{content:"\f2c7"}.ion-android-add-circle:before{content:"\f359"}.ion-android-alarm-clock:before{content:"\f35a"}.ion-android-alert:before{content:"\f35b"}.ion-android-apps:before{content:"\f35c"}.ion-android-archive:before{content:"\f2c9"}.ion-android-arrow-back:before{content:"\f2ca"}.ion-android-arrow-down:before{content:"\f35d"}.ion-android-arrow-dropdown:before{content:"\f35f"}.ion-android-arrow-dropdown-circle:before{content:"\f35e"}.ion-android-arrow-dropleft:before{content:"\f361"}.ion-android-arrow-dropleft-circle:before{content:"\f360"}.ion-android-arrow-dropright:before{content:"\f363"}.ion-android-arrow-dropright-circle:before{content:"\f362"}.ion-android-arrow-dropup:before{content:"\f365"}.ion-android-arrow-dropup-circle:before{content:"\f364"}.ion-android-arrow-forward:before{content:"\f30f"}.ion-android-arrow-up:before{content:"\f366"}.ion-android-attach:before{content:"\f367"}.ion-android-bar:before{content:"\f368"}.ion-android-bicycle:before{content:"\f369"}.ion-android-boat:before{content:"\f36a"}.ion-android-bookmark:before{content:"\f36b"}.ion-android-bulb:before{content:"\f36c"}.ion-android-bus:before{content:"\f36d"}.ion-android-calendar:before{content:"\f2d1"}.ion-android-call:before{content:"\f2d2"}.ion-android-camera:before{content:"\f2d3"}.ion-android-cancel:before{content:"\f36e"}.ion-android-car:before{content:"\f36f"}.ion-android-cart:before{content:"\f370"}.ion-android-chat:before{content:"\f2d4"}.ion-android-checkbox:before{content:"\f374"}.ion-android-checkbox-blank:before{content:"\f371"}.ion-android-checkbox-outline:before{content:"\f373"}.ion-android-checkbox-outline-blank:before{content:"\f372"}.ion-android-checkmark-circle:before{content:"\f375"}.ion-android-clipboard:before{content:"\f376"}.ion-android-close:before{content:"\f2d7"}.ion-android-cloud:before{content:"\f37a"}.ion-android-cloud-circle:before{content:"\f377"}.ion-android-cloud-done:before{content:"\f378"}.ion-android-cloud-outline:before{content:"\f379"}.ion-android-color-palette:before{content:"\f37b"}.ion-android-compass:before{content:"\f37c"}.ion-android-contact:before{content:"\f2d8"}.ion-android-contacts:before{content:"\f2d9"}.ion-android-contract:before{content:"\f37d"}.ion-android-create:before{content:"\f37e"}.ion-android-delete:before{content:"\f37f"}.ion-android-desktop:before{content:"\f380"}.ion-android-document:before{content:"\f381"}.ion-android-done:before{content:"\f383"}.ion-android-done-all:before{content:"\f382"}.ion-android-download:before{content:"\f2dd"}.ion-android-drafts:before{content:"\f384"}.ion-android-exit:before{content:"\f385"}.ion-android-expand:before{content:"\f386"}.ion-android-favorite:before{content:"\f388"}.ion-android-favorite-outline:before{content:"\f387"}.ion-android-film:before{content:"\f389"}.ion-android-folder:before{content:"\f2e0"}.ion-android-folder-open:before{content:"\f38a"}.ion-android-funnel:before{content:"\f38b"}.ion-android-globe:before{content:"\f38c"}.ion-android-hand:before{content:"\f2e3"}.ion-android-hangout:before{content:"\f38d"}.ion-android-happy:before{content:"\f38e"}.ion-android-home:before{content:"\f38f"}.ion-android-image:before{content:"\f2e4"}.ion-android-laptop:before{content:"\f390"}.ion-android-list:before{content:"\f391"}.ion-android-locate:before{content:"\f2e9"}.ion-android-lock:before{content:"\f392"}.ion-android-mail:before{content:"\f2eb"}.ion-android-map:before{content:"\f393"}.ion-android-menu:before{content:"\f394"}.ion-android-microphone:before{content:"\f2ec"}.ion-android-microphone-off:before{content:"\f395"}.ion-android-more-horizontal:before{content:"\f396"}.ion-android-more-vertical:before{content:"\f397"}.ion-android-navigate:before{content:"\f398"}.ion-android-notifications:before{content:"\f39b"}.ion-android-notifications-none:before{content:"\f399"}.ion-android-notifications-off:before{content:"\f39a"}.ion-android-open:before{content:"\f39c"}.ion-android-options:before{content:"\f39d"}.ion-android-people:before{content:"\f39e"}.ion-android-person:before{content:"\f3a0"}.ion-android-person-add:before{content:"\f39f"}.ion-android-phone-landscape:before{content:"\f3a1"}.ion-android-phone-portrait:before{content:"\f3a2"}.ion-android-pin:before{content:"\f3a3"}.ion-android-plane:before{content:"\f3a4"}.ion-android-playstore:before{content:"\f2f0"}.ion-android-print:before{content:"\f3a5"}.ion-android-radio-button-off:before{content:"\f3a6"}.ion-android-radio-button-on:before{content:"\f3a7"}.ion-android-refresh:before{content:"\f3a8"}.ion-android-remove:before{content:"\f2f4"}.ion-android-remove-circle:before{content:"\f3a9"}.ion-android-restaurant:before{content:"\f3aa"}.ion-android-sad:before{content:"\f3ab"}.ion-android-search:before{content:"\f2f5"}.ion-android-send:before{content:"\f2f6"}.ion-android-settings:before{content:"\f2f7"}.ion-android-share:before{content:"\f2f8"}.ion-android-share-alt:before{content:"\f3ac"}.ion-android-star:before{content:"\f2fc"}.ion-android-star-half:before{content:"\f3ad"}.ion-android-star-outline:before{content:"\f3ae"}.ion-android-stopwatch:before{content:"\f2fd"}.ion-android-subway:before{content:"\f3af"}.ion-android-sunny:before{content:"\f3b0"}.ion-android-sync:before{content:"\f3b1"}.ion-android-textsms:before{content:"\f3b2"}.ion-android-time:before{content:"\f3b3"}.ion-android-train:before{content:"\f3b4"}.ion-android-unlock:before{content:"\f3b5"}.ion-android-upload:before{content:"\f3b6"}.ion-android-volume-down:before{content:"\f3b7"}.ion-android-volume-mute:before{content:"\f3b8"}.ion-android-volume-off:before{content:"\f3b9"}.ion-android-volume-up:before{content:"\f3ba"}.ion-android-walk:before{content:"\f3bb"}.ion-android-warning:before{content:"\f3bc"}.ion-android-watch:before{content:"\f3bd"}.ion-android-wifi:before{content:"\f305"}.ion-aperture:before{content:"\f313"}.ion-archive:before{content:"\f102"}.ion-arrow-down-a:before{content:"\f103"}.ion-arrow-down-b:before{content:"\f104"}.ion-arrow-down-c:before{content:"\f105"}.ion-arrow-expand:before{content:"\f25e"}.ion-arrow-graph-down-left:before{content:"\f25f"}.ion-arrow-graph-down-right:before{content:"\f260"}.ion-arrow-graph-up-left:before{content:"\f261"}.ion-arrow-graph-up-right:before{content:"\f262"}.ion-arrow-left-a:before{content:"\f106"}.ion-arrow-left-b:before{content:"\f107"}.ion-arrow-left-c:before{content:"\f108"}.ion-arrow-move:before{content:"\f263"}.ion-arrow-resize:before{content:"\f264"}.ion-arrow-return-left:before{content:"\f265"}.ion-arrow-return-right:before{content:"\f266"}.ion-arrow-right-a:before{content:"\f109"}.ion-arrow-right-b:before{content:"\f10a"}.ion-arrow-right-c:before{content:"\f10b"}.ion-arrow-shrink:before{content:"\f267"}.ion-arrow-swap:before{content:"\f268"}.ion-arrow-up-a:before{content:"\f10c"}.ion-arrow-up-b:before{content:"\f10d"}.ion-arrow-up-c:before{content:"\f10e"}.ion-asterisk:before{content:"\f314"}.ion-at:before{content:"\f10f"}.ion-backspace:before{content:"\f3bf"}.ion-backspace-outline:before{content:"\f3be"}.ion-bag:before{content:"\f110"}.ion-battery-charging:before{content:"\f111"}.ion-battery-empty:before{content:"\f112"}.ion-battery-full:before{content:"\f113"}.ion-battery-half:before{content:"\f114"}.ion-battery-low:before{content:"\f115"}.ion-beaker:before{content:"\f269"}.ion-beer:before{content:"\f26a"}.ion-bluetooth:before{content:"\f116"}.ion-bonfire:before{content:"\f315"}.ion-bookmark:before{content:"\f26b"}.ion-bowtie:before{content:"\f3c0"}.ion-briefcase:before{content:"\f26c"}.ion-bug:before{content:"\f2be"}.ion-calculator:before{content:"\f26d"}.ion-calendar:before{content:"\f117"}.ion-camera:before{content:"\f118"}.ion-card:before{content:"\f119"}.ion-cash:before{content:"\f316"}.ion-chatbox:before{content:"\f11b"}.ion-chatbox-working:before{content:"\f11a"}.ion-chatboxes:before{content:"\f11c"}.ion-chatbubble:before{content:"\f11e"}.ion-chatbubble-working:before{content:"\f11d"}.ion-chatbubbles:before{content:"\f11f"}.ion-checkmark:before{content:"\f122"}.ion-checkmark-circled:before{content:"\f120"}.ion-checkmark-round:before{content:"\f121"}.ion-chevron-down:before{content:"\f123"}.ion-chevron-left:before{content:"\f124"}.ion-chevron-right:before{content:"\f125"}.ion-chevron-up:before{content:"\f126"}.ion-clipboard:before{content:"\f127"}.ion-clock:before{content:"\f26e"}.ion-close:before{content:"\f12a"}.ion-close-circled:before{content:"\f128"}.ion-close-round:before{content:"\f129"}.ion-closed-captioning:before{content:"\f317"}.ion-cloud:before{content:"\f12b"}.ion-code:before{content:"\f271"}.ion-code-download:before{content:"\f26f"}.ion-code-working:before{content:"\f270"}.ion-coffee:before{content:"\f272"}.ion-compass:before{content:"\f273"}.ion-compose:before{content:"\f12c"}.ion-connection-bars:before{content:"\f274"}.ion-contrast:before{content:"\f275"}.ion-crop:before{content:"\f3c1"}.ion-cube:before{content:"\f318"}.ion-disc:before{content:"\f12d"}.ion-document:before{content:"\f12f"}.ion-document-text:before{content:"\f12e"}.ion-drag:before{content:"\f130"}.ion-earth:before{content:"\f276"}.ion-easel:before{content:"\f3c2"}.ion-edit:before{content:"\f2bf"}.ion-egg:before{content:"\f277"}.ion-eject:before{content:"\f131"}.ion-email:before{content:"\f132"}.ion-email-unread:before{content:"\f3c3"}.ion-erlenmeyer-flask:before{content:"\f3c5"}.ion-erlenmeyer-flask-bubbles:before{content:"\f3c4"}.ion-eye:before{content:"\f133"}.ion-eye-disabled:before{content:"\f306"}.ion-female:before{content:"\f278"}.ion-filing:before{content:"\f134"}.ion-film-marker:before{content:"\f135"}.ion-fireball:before{content:"\f319"}.ion-flag:before{content:"\f279"}.ion-flame:before{content:"\f31a"}.ion-flash:before{content:"\f137"}.ion-flash-off:before{content:"\f136"}.ion-folder:before{content:"\f139"}.ion-fork:before{content:"\f27a"}.ion-fork-repo:before{content:"\f2c0"}.ion-forward:before{content:"\f13a"}.ion-funnel:before{content:"\f31b"}.ion-gear-a:before{content:"\f13d"}.ion-gear-b:before{content:"\f13e"}.ion-grid:before{content:"\f13f"}.ion-hammer:before{content:"\f27b"}.ion-happy:before{content:"\f31c"}.ion-happy-outline:before{content:"\f3c6"}.ion-headphone:before{content:"\f140"}.ion-heart:before{content:"\f141"}.ion-heart-broken:before{content:"\f31d"}.ion-help:before{content:"\f143"}.ion-help-buoy:before{content:"\f27c"}.ion-help-circled:before{content:"\f142"}.ion-home:before{content:"\f144"}.ion-icecream:before{content:"\f27d"}.ion-image:before{content:"\f147"}.ion-images:before{content:"\f148"}.ion-information:before{content:"\f14a"}.ion-information-circled:before{content:"\f149"}.ion-ionic:before{content:"\f14b"}.ion-ios-alarm:before{content:"\f3c8"}.ion-ios-alarm-outline:before{content:"\f3c7"}.ion-ios-albums:before{content:"\f3ca"}.ion-ios-albums-outline:before{content:"\f3c9"}.ion-ios-americanfootball:before{content:"\f3cc"}.ion-ios-americanfootball-outline:before{content:"\f3cb"}.ion-ios-analytics:before{content:"\f3ce"}.ion-ios-analytics-outline:before{content:"\f3cd"}.ion-ios-arrow-back:before{content:"\f3cf"}.ion-ios-arrow-down:before{content:"\f3d0"}.ion-ios-arrow-forward:before{content:"\f3d1"}.ion-ios-arrow-left:before{content:"\f3d2"}.ion-ios-arrow-right:before{content:"\f3d3"}.ion-ios-arrow-thin-down:before{content:"\f3d4"}.ion-ios-arrow-thin-left:before{content:"\f3d5"}.ion-ios-arrow-thin-right:before{content:"\f3d6"}.ion-ios-arrow-thin-up:before{content:"\f3d7"}.ion-ios-arrow-up:before{content:"\f3d8"}.ion-ios-at:before{content:"\f3da"}.ion-ios-at-outline:before{content:"\f3d9"}.ion-ios-barcode:before{content:"\f3dc"}.ion-ios-barcode-outline:before{content:"\f3db"}.ion-ios-baseball:before{content:"\f3de"}.ion-ios-baseball-outline:before{content:"\f3dd"}.ion-ios-basketball:before{content:"\f3e0"}.ion-ios-basketball-outline:before{content:"\f3df"}.ion-ios-bell:before{content:"\f3e2"}.ion-ios-bell-outline:before{content:"\f3e1"}.ion-ios-body:before{content:"\f3e4"}.ion-ios-body-outline:before{content:"\f3e3"}.ion-ios-bolt:before{content:"\f3e6"}.ion-ios-bolt-outline:before{content:"\f3e5"}.ion-ios-book:before{content:"\f3e8"}.ion-ios-book-outline:before{content:"\f3e7"}.ion-ios-bookmarks:before{content:"\f3ea"}.ion-ios-bookmarks-outline:before{content:"\f3e9"}.ion-ios-box:before{content:"\f3ec"}.ion-ios-box-outline:before{content:"\f3eb"}.ion-ios-briefcase:before{content:"\f3ee"}.ion-ios-briefcase-outline:before{content:"\f3ed"}.ion-ios-browsers:before{content:"\f3f0"}.ion-ios-browsers-outline:before{content:"\f3ef"}.ion-ios-calculator:before{content:"\f3f2"}.ion-ios-calculator-outline:before{content:"\f3f1"}.ion-ios-calendar:before{content:"\f3f4"}.ion-ios-calendar-outline:before{content:"\f3f3"}.ion-ios-camera:before{content:"\f3f6"}.ion-ios-camera-outline:before{content:"\f3f5"}.ion-ios-cart:before{content:"\f3f8"}.ion-ios-cart-outline:before{content:"\f3f7"}.ion-ios-chatboxes:before{content:"\f3fa"}.ion-ios-chatboxes-outline:before{content:"\f3f9"}.ion-ios-chatbubble:before{content:"\f3fc"}.ion-ios-chatbubble-outline:before{content:"\f3fb"}.ion-ios-checkmark:before{content:"\f3ff"}.ion-ios-checkmark-empty:before{content:"\f3fd"}.ion-ios-checkmark-outline:before{content:"\f3fe"}.ion-ios-circle-filled:before{content:"\f400"}.ion-ios-circle-outline:before{content:"\f401"}.ion-ios-clock:before{content:"\f403"}.ion-ios-clock-outline:before{content:"\f402"}.ion-ios-close:before{content:"\f406"}.ion-ios-close-empty:before{content:"\f404"}.ion-ios-close-outline:before{content:"\f405"}.ion-ios-cloud:before{content:"\f40c"}.ion-ios-cloud-download:before{content:"\f408"}.ion-ios-cloud-download-outline:before{content:"\f407"}.ion-ios-cloud-outline:before{content:"\f409"}.ion-ios-cloud-upload:before{content:"\f40b"}.ion-ios-cloud-upload-outline:before{content:"\f40a"}.ion-ios-cloudy:before{content:"\f410"}.ion-ios-cloudy-night:before{content:"\f40e"}.ion-ios-cloudy-night-outline:before{content:"\f40d"}.ion-ios-cloudy-outline:before{content:"\f40f"}.ion-ios-cog:before{content:"\f412"}.ion-ios-cog-outline:before{content:"\f411"}.ion-ios-color-filter:before{content:"\f414"}.ion-ios-color-filter-outline:before{content:"\f413"}.ion-ios-color-wand:before{content:"\f416"}.ion-ios-color-wand-outline:before{content:"\f415"}.ion-ios-compose:before{content:"\f418"}.ion-ios-compose-outline:before{content:"\f417"}.ion-ios-contact:before{content:"\f41a"}.ion-ios-contact-outline:before{content:"\f419"}.ion-ios-copy:before{content:"\f41c"}.ion-ios-copy-outline:before{content:"\f41b"}.ion-ios-crop:before{content:"\f41e"}.ion-ios-crop-strong:before{content:"\f41d"}.ion-ios-download:before{content:"\f420"}.ion-ios-download-outline:before{content:"\f41f"}.ion-ios-drag:before{content:"\f421"}.ion-ios-email:before{content:"\f423"}.ion-ios-email-outline:before{content:"\f422"}.ion-ios-eye:before{content:"\f425"}.ion-ios-eye-outline:before{content:"\f424"}.ion-ios-fastforward:before{content:"\f427"}.ion-ios-fastforward-outline:before{content:"\f426"}.ion-ios-filing:before{content:"\f429"}.ion-ios-filing-outline:before{content:"\f428"}.ion-ios-film:before{content:"\f42b"}.ion-ios-film-outline:before{content:"\f42a"}.ion-ios-flag:before{content:"\f42d"}.ion-ios-flag-outline:before{content:"\f42c"}.ion-ios-flame:before{content:"\f42f"}.ion-ios-flame-outline:before{content:"\f42e"}.ion-ios-flask:before{content:"\f431"}.ion-ios-flask-outline:before{content:"\f430"}.ion-ios-flower:before{content:"\f433"}.ion-ios-flower-outline:before{content:"\f432"}.ion-ios-folder:before{content:"\f435"}.ion-ios-folder-outline:before{content:"\f434"}.ion-ios-football:before{content:"\f437"}.ion-ios-football-outline:before{content:"\f436"}.ion-ios-game-controller-a:before{content:"\f439"}.ion-ios-game-controller-a-outline:before{content:"\f438"}.ion-ios-game-controller-b:before{content:"\f43b"}.ion-ios-game-controller-b-outline:before{content:"\f43a"}.ion-ios-gear:before{content:"\f43d"}.ion-ios-gear-outline:before{content:"\f43c"}.ion-ios-glasses:before{content:"\f43f"}.ion-ios-glasses-outline:before{content:"\f43e"}.ion-ios-grid-view:before{content:"\f441"}.ion-ios-grid-view-outline:before{content:"\f440"}.ion-ios-heart:before{content:"\f443"}.ion-ios-heart-outline:before{content:"\f442"}.ion-ios-help:before{content:"\f446"}.ion-ios-help-empty:before{content:"\f444"}.ion-ios-help-outline:before{content:"\f445"}.ion-ios-home:before{content:"\f448"}.ion-ios-home-outline:before{content:"\f447"}.ion-ios-infinite:before{content:"\f44a"}.ion-ios-infinite-outline:before{content:"\f449"}.ion-ios-information:before{content:"\f44d"}.ion-ios-information-empty:before{content:"\f44b"}.ion-ios-information-outline:before{content:"\f44c"}.ion-ios-ionic-outline:before{content:"\f44e"}.ion-ios-keypad:before{content:"\f450"}.ion-ios-keypad-outline:before{content:"\f44f"}.ion-ios-lightbulb:before{content:"\f452"}.ion-ios-lightbulb-outline:before{content:"\f451"}.ion-ios-list:before{content:"\f454"}.ion-ios-list-outline:before{content:"\f453"}.ion-ios-location:before{content:"\f456"}.ion-ios-location-outline:before{content:"\f455"}.ion-ios-locked:before{content:"\f458"}.ion-ios-locked-outline:before{content:"\f457"}.ion-ios-loop:before{content:"\f45a"}.ion-ios-loop-strong:before{content:"\f459"}.ion-ios-medical:before{content:"\f45c"}.ion-ios-medical-outline:before{content:"\f45b"}.ion-ios-medkit:before{content:"\f45e"}.ion-ios-medkit-outline:before{content:"\f45d"}.ion-ios-mic:before{content:"\f461"}.ion-ios-mic-off:before{content:"\f45f"}.ion-ios-mic-outline:before{content:"\f460"}.ion-ios-minus:before{content:"\f464"}.ion-ios-minus-empty:before{content:"\f462"}.ion-ios-minus-outline:before{content:"\f463"}.ion-ios-monitor:before{content:"\f466"}.ion-ios-monitor-outline:before{content:"\f465"}.ion-ios-moon:before{content:"\f468"}.ion-ios-moon-outline:before{content:"\f467"}.ion-ios-more:before{content:"\f46a"}.ion-ios-more-outline:before{content:"\f469"}.ion-ios-musical-note:before{content:"\f46b"}.ion-ios-musical-notes:before{content:"\f46c"}.ion-ios-navigate:before{content:"\f46e"}.ion-ios-navigate-outline:before{content:"\f46d"}.ion-ios-nutrition:before{content:"\f470"}.ion-ios-nutrition-outline:before{content:"\f46f"}.ion-ios-paper:before{content:"\f472"}.ion-ios-paper-outline:before{content:"\f471"}.ion-ios-paperplane:before{content:"\f474"}.ion-ios-paperplane-outline:before{content:"\f473"}.ion-ios-partlysunny:before{content:"\f476"}.ion-ios-partlysunny-outline:before{content:"\f475"}.ion-ios-pause:before{content:"\f478"}.ion-ios-pause-outline:before{content:"\f477"}.ion-ios-paw:before{content:"\f47a"}.ion-ios-paw-outline:before{content:"\f479"}.ion-ios-people:before{content:"\f47c"}.ion-ios-people-outline:before{content:"\f47b"}.ion-ios-person:before{content:"\f47e"}.ion-ios-person-outline:before{content:"\f47d"}.ion-ios-personadd:before{content:"\f480"}.ion-ios-personadd-outline:before{content:"\f47f"}.ion-ios-photos:before{content:"\f482"}.ion-ios-photos-outline:before{content:"\f481"}.ion-ios-pie:before{content:"\f484"}.ion-ios-pie-outline:before{content:"\f483"}.ion-ios-pint:before{content:"\f486"}.ion-ios-pint-outline:before{content:"\f485"}.ion-ios-play:before{content:"\f488"}.ion-ios-play-outline:before{content:"\f487"}.ion-ios-plus:before{content:"\f48b"}.ion-ios-plus-empty:before{content:"\f489"}.ion-ios-plus-outline:before{content:"\f48a"}.ion-ios-pricetag:before{content:"\f48d"}.ion-ios-pricetag-outline:before{content:"\f48c"}.ion-ios-pricetags:before{content:"\f48f"}.ion-ios-pricetags-outline:before{content:"\f48e"}.ion-ios-printer:before{content:"\f491"}.ion-ios-printer-outline:before{content:"\f490"}.ion-ios-pulse:before{content:"\f493"}.ion-ios-pulse-strong:before{content:"\f492"}.ion-ios-rainy:before{content:"\f495"}.ion-ios-rainy-outline:before{content:"\f494"}.ion-ios-recording:before{content:"\f497"}.ion-ios-recording-outline:before{content:"\f496"}.ion-ios-redo:before{content:"\f499"}.ion-ios-redo-outline:before{content:"\f498"}.ion-ios-refresh:before{content:"\f49c"}.ion-ios-refresh-empty:before{content:"\f49a"}.ion-ios-refresh-outline:before{content:"\f49b"}.ion-ios-reload:before{content:"\f49d"}.ion-ios-reverse-camera:before{content:"\f49f"}.ion-ios-reverse-camera-outline:before{content:"\f49e"}.ion-ios-rewind:before{content:"\f4a1"}.ion-ios-rewind-outline:before{content:"\f4a0"}.ion-ios-rose:before{content:"\f4a3"}.ion-ios-rose-outline:before{content:"\f4a2"}.ion-ios-search:before{content:"\f4a5"}.ion-ios-search-strong:before{content:"\f4a4"}.ion-ios-settings:before{content:"\f4a7"}.ion-ios-settings-strong:before{content:"\f4a6"}.ion-ios-shuffle:before{content:"\f4a9"}.ion-ios-shuffle-strong:before{content:"\f4a8"}.ion-ios-skipbackward:before{content:"\f4ab"}.ion-ios-skipbackward-outline:before{content:"\f4aa"}.ion-ios-skipforward:before{content:"\f4ad"}.ion-ios-skipforward-outline:before{content:"\f4ac"}.ion-ios-snowy:before{content:"\f4ae"}.ion-ios-speedometer:before{content:"\f4b0"}.ion-ios-speedometer-outline:before{content:"\f4af"}.ion-ios-star:before{content:"\f4b3"}.ion-ios-star-half:before{content:"\f4b1"}.ion-ios-star-outline:before{content:"\f4b2"}.ion-ios-stopwatch:before{content:"\f4b5"}.ion-ios-stopwatch-outline:before{content:"\f4b4"}.ion-ios-sunny:before{content:"\f4b7"}.ion-ios-sunny-outline:before{content:"\f4b6"}.ion-ios-telephone:before{content:"\f4b9"}.ion-ios-telephone-outline:before{content:"\f4b8"}.ion-ios-tennisball:before{content:"\f4bb"}.ion-ios-tennisball-outline:before{content:"\f4ba"}.ion-ios-thunderstorm:before{content:"\f4bd"}.ion-ios-thunderstorm-outline:before{content:"\f4bc"}.ion-ios-time:before{content:"\f4bf"}.ion-ios-time-outline:before{content:"\f4be"}.ion-ios-timer:before{content:"\f4c1"}.ion-ios-timer-outline:before{content:"\f4c0"}.ion-ios-toggle:before{content:"\f4c3"}.ion-ios-toggle-outline:before{content:"\f4c2"}.ion-ios-trash:before{content:"\f4c5"}.ion-ios-trash-outline:before{content:"\f4c4"}.ion-ios-undo:before{content:"\f4c7"}.ion-ios-undo-outline:before{content:"\f4c6"}.ion-ios-unlocked:before{content:"\f4c9"}.ion-ios-unlocked-outline:before{content:"\f4c8"}.ion-ios-upload:before{content:"\f4cb"}.ion-ios-upload-outline:before{content:"\f4ca"}.ion-ios-videocam:before{content:"\f4cd"}.ion-ios-videocam-outline:before{content:"\f4cc"}.ion-ios-volume-high:before{content:"\f4ce"}.ion-ios-volume-low:before{content:"\f4cf"}.ion-ios-wineglass:before{content:"\f4d1"}.ion-ios-wineglass-outline:before{content:"\f4d0"}.ion-ios-world:before{content:"\f4d3"}.ion-ios-world-outline:before{content:"\f4d2"}.ion-ipad:before{content:"\f1f9"}.ion-iphone:before{content:"\f1fa"}.ion-ipod:before{content:"\f1fb"}.ion-jet:before{content:"\f295"}.ion-key:before{content:"\f296"}.ion-knife:before{content:"\f297"}.ion-laptop:before{content:"\f1fc"}.ion-leaf:before{content:"\f1fd"}.ion-levels:before{content:"\f298"}.ion-lightbulb:before{content:"\f299"}.ion-link:before{content:"\f1fe"}.ion-load-a:before{content:"\f29a"}.ion-load-b:before{content:"\f29b"}.ion-load-c:before{content:"\f29c"}.ion-load-d:before{content:"\f29d"}.ion-location:before{content:"\f1ff"}.ion-lock-combination:before{content:"\f4d4"}.ion-locked:before{content:"\f200"}.ion-log-in:before{content:"\f29e"}.ion-log-out:before{content:"\f29f"}.ion-loop:before{content:"\f201"}.ion-magnet:before{content:"\f2a0"}.ion-male:before{content:"\f2a1"}.ion-man:before{content:"\f202"}.ion-map:before{content:"\f203"}.ion-medkit:before{content:"\f2a2"}.ion-merge:before{content:"\f33f"}.ion-mic-a:before{content:"\f204"}.ion-mic-b:before{content:"\f205"}.ion-mic-c:before{content:"\f206"}.ion-minus:before{content:"\f209"}.ion-minus-circled:before{content:"\f207"}.ion-minus-round:before{content:"\f208"}.ion-model-s:before{content:"\f2c1"}.ion-monitor:before{content:"\f20a"}.ion-more:before{content:"\f20b"}.ion-mouse:before{content:"\f340"}.ion-music-note:before{content:"\f20c"}.ion-navicon:before{content:"\f20e"}.ion-navicon-round:before{content:"\f20d"}.ion-navigate:before{content:"\f2a3"}.ion-network:before{content:"\f341"}.ion-no-smoking:before{content:"\f2c2"}.ion-nuclear:before{content:"\f2a4"}.ion-outlet:before{content:"\f342"}.ion-paintbrush:before{content:"\f4d5"}.ion-paintbucket:before{content:"\f4d6"}.ion-paper-airplane:before{content:"\f2c3"}.ion-paperclip:before{content:"\f20f"}.ion-pause:before{content:"\f210"}.ion-person:before{content:"\f213"}.ion-person-add:before{content:"\f211"}.ion-person-stalker:before{content:"\f212"}.ion-pie-graph:before{content:"\f2a5"}.ion-pin:before{content:"\f2a6"}.ion-pinpoint:before{content:"\f2a7"}.ion-pizza:before{content:"\f2a8"}.ion-plane:before{content:"\f214"}.ion-planet:before{content:"\f343"}.ion-play:before{content:"\f215"}.ion-playstation:before{content:"\f30a"}.ion-plus:before{content:"\f218"}.ion-plus-circled:before{content:"\f216"}.ion-plus-round:before{content:"\f217"}.ion-podium:before{content:"\f344"}.ion-pound:before{content:"\f219"}.ion-power:before{content:"\f2a9"}.ion-pricetag:before{content:"\f2aa"}.ion-pricetags:before{content:"\f2ab"}.ion-printer:before{content:"\f21a"}.ion-pull-request:before{content:"\f345"}.ion-qr-scanner:before{content:"\f346"}.ion-quote:before{content:"\f347"}.ion-radio-waves:before{content:"\f2ac"}.ion-record:before{content:"\f21b"}.ion-refresh:before{content:"\f21c"}.ion-reply:before{content:"\f21e"}.ion-reply-all:before{content:"\f21d"}.ion-ribbon-a:before{content:"\f348"}.ion-ribbon-b:before{content:"\f349"}.ion-sad:before{content:"\f34a"}.ion-sad-outline:before{content:"\f4d7"}.ion-scissors:before{content:"\f34b"}.ion-search:before{content:"\f21f"}.ion-settings:before{content:"\f2ad"}.ion-share:before{content:"\f220"}.ion-shuffle:before{content:"\f221"}.ion-skip-backward:before{content:"\f222"}.ion-skip-forward:before{content:"\f223"}.ion-social-android:before{content:"\f225"}.ion-social-android-outline:before{content:"\f224"}.ion-social-angular:before{content:"\f4d9"}.ion-social-angular-outline:before{content:"\f4d8"}.ion-social-apple:before{content:"\f227"}.ion-social-apple-outline:before{content:"\f226"}.ion-social-bitcoin:before{content:"\f2af"}.ion-social-bitcoin-outline:before{content:"\f2ae"}.ion-social-buffer:before{content:"\f229"}.ion-social-buffer-outline:before{content:"\f228"}.ion-social-chrome:before{content:"\f4db"}.ion-social-chrome-outline:before{content:"\f4da"}.ion-social-codepen:before{content:"\f4dd"}.ion-social-codepen-outline:before{content:"\f4dc"}.ion-social-css3:before{content:"\f4df"}.ion-social-css3-outline:before{content:"\f4de"}.ion-social-designernews:before{content:"\f22b"}.ion-social-designernews-outline:before{content:"\f22a"}.ion-social-dribbble:before{content:"\f22d"}.ion-social-dribbble-outline:before{content:"\f22c"}.ion-social-dropbox:before{content:"\f22f"}.ion-social-dropbox-outline:before{content:"\f22e"}.ion-social-euro:before{content:"\f4e1"}.ion-social-euro-outline:before{content:"\f4e0"}.ion-social-facebook:before{content:"\f231"}.ion-social-facebook-outline:before{content:"\f230"}.ion-social-foursquare:before{content:"\f34d"}.ion-social-foursquare-outline:before{content:"\f34c"}.ion-social-freebsd-devil:before{content:"\f2c4"}.ion-social-github:before{content:"\f233"}.ion-social-github-outline:before{content:"\f232"}.ion-social-google:before{content:"\f34f"}.ion-social-google-outline:before{content:"\f34e"}.ion-social-googleplus:before{content:"\f235"}.ion-social-googleplus-outline:before{content:"\f234"}.ion-social-hackernews:before{content:"\f237"}.ion-social-hackernews-outline:before{content:"\f236"}.ion-social-html5:before{content:"\f4e3"}.ion-social-html5-outline:before{content:"\f4e2"}.ion-social-instagram:before{content:"\f351"}.ion-social-instagram-outline:before{content:"\f350"}.ion-social-javascript:before{content:"\f4e5"}.ion-social-javascript-outline:before{content:"\f4e4"}.ion-social-linkedin:before{content:"\f239"}.ion-social-linkedin-outline:before{content:"\f238"}.ion-social-markdown:before{content:"\f4e6"}.ion-social-nodejs:before{content:"\f4e7"}.ion-social-octocat:before{content:"\f4e8"}.ion-social-pinterest:before{content:"\f2b1"}.ion-social-pinterest-outline:before{content:"\f2b0"}.ion-social-python:before{content:"\f4e9"}.ion-social-reddit:before{content:"\f23b"}.ion-social-reddit-outline:before{content:"\f23a"}.ion-social-rss:before{content:"\f23d"}.ion-social-rss-outline:before{content:"\f23c"}.ion-social-sass:before{content:"\f4ea"}.ion-social-skype:before{content:"\f23f"}.ion-social-skype-outline:before{content:"\f23e"}.ion-social-snapchat:before{content:"\f4ec"}.ion-social-snapchat-outline:before{content:"\f4eb"}.ion-social-tumblr:before{content:"\f241"}.ion-social-tumblr-outline:before{content:"\f240"}.ion-social-tux:before{content:"\f2c5"}.ion-social-twitch:before{content:"\f4ee"}.ion-social-twitch-outline:before{content:"\f4ed"}.ion-social-twitter:before{content:"\f243"}.ion-social-twitter-outline:before{content:"\f242"}.ion-social-usd:before{content:"\f353"}.ion-social-usd-outline:before{content:"\f352"}.ion-social-vimeo:before{content:"\f245"}.ion-social-vimeo-outline:before{content:"\f244"}.ion-social-whatsapp:before{content:"\f4f0"}.ion-social-whatsapp-outline:before{content:"\f4ef"}.ion-social-windows:before{content:"\f247"}.ion-social-windows-outline:before{content:"\f246"}.ion-social-wordpress:before{content:"\f249"}.ion-social-wordpress-outline:before{content:"\f248"}.ion-social-yahoo:before{content:"\f24b"}.ion-social-yahoo-outline:before{content:"\f24a"}.ion-social-yen:before{content:"\f4f2"}.ion-social-yen-outline:before{content:"\f4f1"}.ion-social-youtube:before{content:"\f24d"}.ion-social-youtube-outline:before{content:"\f24c"}.ion-soup-can:before{content:"\f4f4"}.ion-soup-can-outline:before{content:"\f4f3"}.ion-speakerphone:before{content:"\f2b2"}.ion-speedometer:before{content:"\f2b3"}.ion-spoon:before{content:"\f2b4"}.ion-star:before{content:"\f24e"}.ion-stats-bars:before{content:"\f2b5"}.ion-steam:before{content:"\f30b"}.ion-stop:before{content:"\f24f"}.ion-thermometer:before{content:"\f2b6"}.ion-thumbsdown:before{content:"\f250"}.ion-thumbsup:before{content:"\f251"}.ion-toggle:before{content:"\f355"}.ion-toggle-filled:before{content:"\f354"}.ion-transgender:before{content:"\f4f5"}.ion-trash-a:before{content:"\f252"}.ion-trash-b:before{content:"\f253"}.ion-trophy:before{content:"\f356"}.ion-tshirt:before{content:"\f4f7"}.ion-tshirt-outline:before{content:"\f4f6"}.ion-umbrella:before{content:"\f2b7"}.ion-university:before{content:"\f357"}.ion-unlocked:before{content:"\f254"}.ion-upload:before{content:"\f255"}.ion-usb:before{content:"\f2b8"}.ion-videocamera:before{content:"\f256"}.ion-volume-high:before{content:"\f257"}.ion-volume-low:before{content:"\f258"}.ion-volume-medium:before{content:"\f259"}.ion-volume-mute:before{content:"\f25a"}.ion-wand:before{content:"\f358"}.ion-waterdrop:before{content:"\f25b"}.ion-wifi:before{content:"\f25c"}.ion-wineglass:before{content:"\f2b9"}.ion-woman:before{content:"\f25d"}.ion-wrench:before{content:"\f2ba"}.ion-xbox:before{content:"\f30c"} diff --git a/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.css b/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.css new file mode 100644 index 00000000..363e239c --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.css @@ -0,0 +1,128 @@ +/* +Author: L. Voogdt +License: MIT +Version: 1.0 +*/ + +/* Marker setup */ +.awesome-marker { + background: url('images/markers-soft.png') no-repeat 0 0; + width: 35px; + height: 46px; + position:absolute; + left:0; + top:0; + display: block; + text-align: center; +} + +.awesome-marker-shadow { + background: url('images/markers-shadow.png') no-repeat 0 0; + width: 36px; + height: 16px; +} + +/* Retina displays */ +@media (min--moz-device-pixel-ratio: 1.5),(-o-min-device-pixel-ratio: 3/2), +(-webkit-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5),(min-resolution: 1.5dppx) { + .awesome-marker { + background-image: url('images/markers-soft@2x.png'); + background-size: 720px 92px; + } + .awesome-marker-shadow { + background-image: url('images/markers-shadow@2x.png'); + background-size: 35px 16px; + } +} + +.awesome-marker i { + color: #333; + margin-top: 10px; + display: inline-block; + font-size: 14px; +} + +.awesome-marker .icon-white { + color: #fff; +} + +/* Colors */ +.awesome-marker-icon-red { + background-position: 0 0; +} + +.awesome-marker-icon-darkred { + background-position: -180px 0; +} + +.awesome-marker-icon-lightred { + background-position: -360px 0; +} + +.awesome-marker-icon-orange { + background-position: -36px 0; +} + +.awesome-marker-icon-beige { + background-position: -396px 0; +} + +.awesome-marker-icon-green { + background-position: -72px 0; +} + +.awesome-marker-icon-darkgreen { + background-position: -252px 0; +} + +.awesome-marker-icon-lightgreen { + background-position: -432px 0; +} + +.awesome-marker-icon-blue { + background-position: -108px 0; +} + +.awesome-marker-icon-darkblue { + background-position: -216px 0; +} + +.awesome-marker-icon-lightblue { + background-position: -468px 0; +} + +.awesome-marker-icon-purple { + background-position: -144px 0; +} + +.awesome-marker-icon-darkpurple { + background-position: -288px 0; +} + +.awesome-marker-icon-pink { + background-position: -504px 0; +} + +.awesome-marker-icon-cadetblue { + background-position: -324px 0; +} + +.awesome-marker-icon-white { + background-position: -576px 0; +} + +.awesome-marker-icon-gray { + background-position: -648px 0; +} + +.awesome-marker-icon-lightgray { + background-position: -612px 0; +} + +.awesome-marker-icon-black { + background-position: -682px 0; +} + +.awesome-marker-square { + background-position-y: -46px; +} diff --git a/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.js b/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.js new file mode 100644 index 00000000..0b5f483d --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.js @@ -0,0 +1,146 @@ +/* + Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons + (c) 2012-2013, Lennard Voogdt + + https://leafletjs.com + https://github.com/lvoogdt + */ + +/*global L*/ + +(function (window, document, undefined) { + "use strict"; + /* + * Leaflet.AwesomeMarkers assumes that you have already included the Leaflet library. + */ + + L.AwesomeMarkers = {}; + + L.AwesomeMarkers.version = '2.0.1'; + + L.AwesomeMarkers.Icon = L.Icon.extend({ + options: { + iconSize: [35, 45], + iconAnchor: [17, 42], + popupAnchor: [1, -32], + shadowAnchor: [10, 12], + shadowSize: [36, 16], + className: 'awesome-marker', + prefix: 'glyphicon', + spinClass: 'fa-spin', + extraClasses: '', + icon: 'home', + markerColor: 'blue', + iconColor: 'white', + iconRotate: 0, + font: 'monospace' + }, + + initialize: function (options) { + options = L.Util.setOptions(this, options); + }, + + createIcon: function () { + var div = document.createElement('div'), + options = this.options; + + if (options.icon) { + div.innerHTML = this._createInner(); + } + + if (options.bgPos) { + div.style.backgroundPosition = + (-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px'; + } + + this._setIconStyles(div, 'icon-' + options.markerColor); + return div; + }, + + _createInner: function() { + var iconClass, + iconSpinClass = "", + iconColorClass = "", + iconColorStyle = "", + options = this.options; + + if(!options.prefix || (options.icon.slice(0,options.prefix.length+1) === options.prefix + "-")) { + iconClass = options.icon; + } else { + iconClass = options.prefix + "-" + options.icon; + } + + if(options.spin && typeof options.spinClass === "string") { + iconSpinClass = options.spinClass; + } + + if(options.iconColor) { + if ((options.iconColor === 'white' || options.iconColor === 'black') && + options.prefix !== 'fa') { + iconColorClass = "icon-" + options.iconColor; + } else if (options.prefix === 'fa' && options.iconColor === 'white') { + iconColorClass = "fa-inverse"; + } else { + iconColorStyle = "color: " + options.iconColor + ";"; + } + } + if(options.font && options.text) { + iconColorStyle += "font-family: " + options.font + ";"; + } + + if(options.iconRotate && options.iconRotate !== 0) { + iconColorStyle += "-webkit-transform: rotate(" + options.iconRotate + "deg);"; + iconColorStyle += "-moz-transform: rotate(" + options.iconRotate + "deg);"; + iconColorStyle += "-o-transform: rotate(" + options.iconRotate + "deg);"; + iconColorStyle += "-ms-transform: rotate(" + options.iconRotate + "deg);"; + iconColorStyle += "transform: rotate(" + options.iconRotate + "deg);"; + } + + if (options.text) { + return "" + options.text + ""; + } + + return ""; + }, + + _setIconStyles: function (img, name) { + var options = this.options, + size = L.point(options[name === 'shadow' ? 'shadowSize' : 'iconSize']), + anchor; + + if (name === 'shadow') { + anchor = L.point(options.shadowAnchor || options.iconAnchor); + } else { + anchor = L.point(options.iconAnchor); + } + + if (!anchor && size) { + anchor = size.divideBy(2, true); + } + + img.className = 'awesome-marker-' + name + ' ' + options.className; + + if (anchor) { + img.style.marginLeft = (-anchor.x) + 'px'; + img.style.marginTop = (-anchor.y) + 'px'; + } + + if (size) { + img.style.width = size.x + 'px'; + img.style.height = size.y + 'px'; + } + }, + + createShadow: function () { + var div = document.createElement('div'); + + this._setIconStyles(div, 'shadow'); + return div; + } + }); + + L.AwesomeMarkers.icon = function (options) { + return new L.AwesomeMarkers.Icon(options); + }; + +}(this, document)); diff --git a/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.min.js b/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.min.js new file mode 100644 index 00000000..0aaf719b --- /dev/null +++ b/2311/site_libs/fontawesome-4.7.0/leaflet.awesome-markers.min.js @@ -0,0 +1 @@ +(function(window,document,undefined){"use strict";L.AwesomeMarkers={};L.AwesomeMarkers.version="2.0.1";L.AwesomeMarkers.Icon=L.Icon.extend({options:{iconSize:[35,45],iconAnchor:[17,42],popupAnchor:[1,-32],shadowAnchor:[10,12],shadowSize:[36,16],className:"awesome-marker",prefix:"glyphicon",spinClass:"fa-spin",extraClasses:"",icon:"home",markerColor:"blue",iconColor:"white",iconRotate:0,font:"monospace"},initialize:function(options){options=L.Util.setOptions(this,options)},createIcon:function(){var div=document.createElement("div"),options=this.options;if(options.icon){div.innerHTML=this._createInner()}if(options.bgPos){div.style.backgroundPosition=-options.bgPos.x+"px "+-options.bgPos.y+"px"}this._setIconStyles(div,"icon-"+options.markerColor);return div},_createInner:function(){var iconClass,iconSpinClass="",iconColorClass="",iconColorStyle="",options=this.options;if(!options.prefix||options.icon.slice(0,options.prefix.length+1)===options.prefix+"-"){iconClass=options.icon}else{iconClass=options.prefix+"-"+options.icon}if(options.spin&&typeof options.spinClass==="string"){iconSpinClass=options.spinClass}if(options.iconColor){if((options.iconColor==="white"||options.iconColor==="black")&&options.prefix!=="fa"){iconColorClass="icon-"+options.iconColor}else if(options.prefix==="fa"&&options.iconColor==="white"){iconColorClass="fa-inverse"}else{iconColorStyle="color: "+options.iconColor+";"}}if(options.font&&options.text){iconColorStyle+="font-family: "+options.font+";"}if(options.iconRotate&&options.iconRotate!==0){iconColorStyle+="-webkit-transform: rotate("+options.iconRotate+"deg);";iconColorStyle+="-moz-transform: rotate("+options.iconRotate+"deg);";iconColorStyle+="-o-transform: rotate("+options.iconRotate+"deg);";iconColorStyle+="-ms-transform: rotate("+options.iconRotate+"deg);";iconColorStyle+="transform: rotate("+options.iconRotate+"deg);"}if(options.text){return""+options.text+""}return""},_setIconStyles:function(img,name){var options=this.options,size=L.point(options[name==="shadow"?"shadowSize":"iconSize"]),anchor;if(name==="shadow"){anchor=L.point(options.shadowAnchor||options.iconAnchor)}else{anchor=L.point(options.iconAnchor)}if(!anchor&&size){anchor=size.divideBy(2,true)}img.className="awesome-marker-"+name+" "+options.className;if(anchor){img.style.marginLeft=-anchor.x+"px";img.style.marginTop=-anchor.y+"px"}if(size){img.style.width=size.x+"px";img.style.height=size.y+"px"}},createShadow:function(){var div=document.createElement("div");this._setIconStyles(div,"shadow");return div}});L.AwesomeMarkers.icon=function(options){return new L.AwesomeMarkers.Icon(options)}})(this,document); diff --git a/2311/site_libs/htmlwidgets-1.6.2/htmlwidgets.js b/2311/site_libs/htmlwidgets-1.6.2/htmlwidgets.js new file mode 100644 index 00000000..1067d029 --- /dev/null +++ b/2311/site_libs/htmlwidgets-1.6.2/htmlwidgets.js @@ -0,0 +1,901 @@ +(function() { + // If window.HTMLWidgets is already defined, then use it; otherwise create a + // new object. This allows preceding code to set options that affect the + // initialization process (though none currently exist). + window.HTMLWidgets = window.HTMLWidgets || {}; + + // See if we're running in a viewer pane. If not, we're in a web browser. + var viewerMode = window.HTMLWidgets.viewerMode = + /\bviewer_pane=1\b/.test(window.location); + + // See if we're running in Shiny mode. If not, it's a static document. + // Note that static widgets can appear in both Shiny and static modes, but + // obviously, Shiny widgets can only appear in Shiny apps/documents. + var shinyMode = window.HTMLWidgets.shinyMode = + typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings; + + // We can't count on jQuery being available, so we implement our own + // version if necessary. + function querySelectorAll(scope, selector) { + if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) { + return scope.find(selector); + } + if (scope.querySelectorAll) { + return scope.querySelectorAll(selector); + } + } + + function asArray(value) { + if (value === null) + return []; + if ($.isArray(value)) + return value; + return [value]; + } + + // Implement jQuery's extend + function extend(target /*, ... */) { + if (arguments.length == 1) { + return target; + } + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + } + return target; + } + + // IE8 doesn't support Array.forEach. + function forEach(values, callback, thisArg) { + if (values.forEach) { + values.forEach(callback, thisArg); + } else { + for (var i = 0; i < values.length; i++) { + callback.call(thisArg, values[i], i, values); + } + } + } + + // Replaces the specified method with the return value of funcSource. + // + // Note that funcSource should not BE the new method, it should be a function + // that RETURNS the new method. funcSource receives a single argument that is + // the overridden method, it can be called from the new method. The overridden + // method can be called like a regular function, it has the target permanently + // bound to it so "this" will work correctly. + function overrideMethod(target, methodName, funcSource) { + var superFunc = target[methodName] || function() {}; + var superFuncBound = function() { + return superFunc.apply(target, arguments); + }; + target[methodName] = funcSource(superFuncBound); + } + + // Add a method to delegator that, when invoked, calls + // delegatee.methodName. If there is no such method on + // the delegatee, but there was one on delegator before + // delegateMethod was called, then the original version + // is invoked instead. + // For example: + // + // var a = { + // method1: function() { console.log('a1'); } + // method2: function() { console.log('a2'); } + // }; + // var b = { + // method1: function() { console.log('b1'); } + // }; + // delegateMethod(a, b, "method1"); + // delegateMethod(a, b, "method2"); + // a.method1(); + // a.method2(); + // + // The output would be "b1", "a2". + function delegateMethod(delegator, delegatee, methodName) { + var inherited = delegator[methodName]; + delegator[methodName] = function() { + var target = delegatee; + var method = delegatee[methodName]; + + // The method doesn't exist on the delegatee. Instead, + // call the method on the delegator, if it exists. + if (!method) { + target = delegator; + method = inherited; + } + + if (method) { + return method.apply(target, arguments); + } + }; + } + + // Implement a vague facsimilie of jQuery's data method + function elementData(el, name, value) { + if (arguments.length == 2) { + return el["htmlwidget_data_" + name]; + } else if (arguments.length == 3) { + el["htmlwidget_data_" + name] = value; + return el; + } else { + throw new Error("Wrong number of arguments for elementData: " + + arguments.length); + } + } + + // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex + function escapeRegExp(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + } + + function hasClass(el, className) { + var re = new RegExp("\\b" + escapeRegExp(className) + "\\b"); + return re.test(el.className); + } + + // elements - array (or array-like object) of HTML elements + // className - class name to test for + // include - if true, only return elements with given className; + // if false, only return elements *without* given className + function filterByClass(elements, className, include) { + var results = []; + for (var i = 0; i < elements.length; i++) { + if (hasClass(elements[i], className) == include) + results.push(elements[i]); + } + return results; + } + + function on(obj, eventName, func) { + if (obj.addEventListener) { + obj.addEventListener(eventName, func, false); + } else if (obj.attachEvent) { + obj.attachEvent(eventName, func); + } + } + + function off(obj, eventName, func) { + if (obj.removeEventListener) + obj.removeEventListener(eventName, func, false); + else if (obj.detachEvent) { + obj.detachEvent(eventName, func); + } + } + + // Translate array of values to top/right/bottom/left, as usual with + // the "padding" CSS property + // https://developer.mozilla.org/en-US/docs/Web/CSS/padding + function unpackPadding(value) { + if (typeof(value) === "number") + value = [value]; + if (value.length === 1) { + return {top: value[0], right: value[0], bottom: value[0], left: value[0]}; + } + if (value.length === 2) { + return {top: value[0], right: value[1], bottom: value[0], left: value[1]}; + } + if (value.length === 3) { + return {top: value[0], right: value[1], bottom: value[2], left: value[1]}; + } + if (value.length === 4) { + return {top: value[0], right: value[1], bottom: value[2], left: value[3]}; + } + } + + // Convert an unpacked padding object to a CSS value + function paddingToCss(paddingObj) { + return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px"; + } + + // Makes a number suitable for CSS + function px(x) { + if (typeof(x) === "number") + return x + "px"; + else + return x; + } + + // Retrieves runtime widget sizing information for an element. + // The return value is either null, or an object with fill, padding, + // defaultWidth, defaultHeight fields. + function sizingPolicy(el) { + var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']"); + if (!sizingEl) + return null; + var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}"); + if (viewerMode) { + return sp.viewer; + } else { + return sp.browser; + } + } + + // @param tasks Array of strings (or falsy value, in which case no-op). + // Each element must be a valid JavaScript expression that yields a + // function. Or, can be an array of objects with "code" and "data" + // properties; in this case, the "code" property should be a string + // of JS that's an expr that yields a function, and "data" should be + // an object that will be added as an additional argument when that + // function is called. + // @param target The object that will be "this" for each function + // execution. + // @param args Array of arguments to be passed to the functions. (The + // same arguments will be passed to all functions.) + function evalAndRun(tasks, target, args) { + if (tasks) { + forEach(tasks, function(task) { + var theseArgs = args; + if (typeof(task) === "object") { + theseArgs = theseArgs.concat([task.data]); + task = task.code; + } + var taskFunc = tryEval(task); + if (typeof(taskFunc) !== "function") { + throw new Error("Task must be a function! Source:\n" + task); + } + taskFunc.apply(target, theseArgs); + }); + } + } + + // Attempt eval() both with and without enclosing in parentheses. + // Note that enclosing coerces a function declaration into + // an expression that eval() can parse + // (otherwise, a SyntaxError is thrown) + function tryEval(code) { + var result = null; + try { + result = eval("(" + code + ")"); + } catch(error) { + if (!(error instanceof SyntaxError)) { + throw error; + } + try { + result = eval(code); + } catch(e) { + if (e instanceof SyntaxError) { + throw error; + } else { + throw e; + } + } + } + return result; + } + + function initSizing(el) { + var sizing = sizingPolicy(el); + if (!sizing) + return; + + var cel = document.getElementById("htmlwidget_container"); + if (!cel) + return; + + if (typeof(sizing.padding) !== "undefined") { + document.body.style.margin = "0"; + document.body.style.padding = paddingToCss(unpackPadding(sizing.padding)); + } + + if (sizing.fill) { + document.body.style.overflow = "hidden"; + document.body.style.width = "100%"; + document.body.style.height = "100%"; + document.documentElement.style.width = "100%"; + document.documentElement.style.height = "100%"; + cel.style.position = "absolute"; + var pad = unpackPadding(sizing.padding); + cel.style.top = pad.top + "px"; + cel.style.right = pad.right + "px"; + cel.style.bottom = pad.bottom + "px"; + cel.style.left = pad.left + "px"; + el.style.width = "100%"; + el.style.height = "100%"; + + return { + getWidth: function() { return cel.getBoundingClientRect().width; }, + getHeight: function() { return cel.getBoundingClientRect().height; } + }; + + } else { + el.style.width = px(sizing.width); + el.style.height = px(sizing.height); + + return { + getWidth: function() { return cel.getBoundingClientRect().width; }, + getHeight: function() { return cel.getBoundingClientRect().height; } + }; + } + } + + // Default implementations for methods + var defaults = { + find: function(scope) { + return querySelectorAll(scope, "." + this.name); + }, + renderError: function(el, err) { + var $el = $(el); + + this.clearError(el); + + // Add all these error classes, as Shiny does + var errClass = "shiny-output-error"; + if (err.type !== null) { + // use the classes of the error condition as CSS class names + errClass = errClass + " " + $.map(asArray(err.type), function(type) { + return errClass + "-" + type; + }).join(" "); + } + errClass = errClass + " htmlwidgets-error"; + + // Is el inline or block? If inline or inline-block, just display:none it + // and add an inline error. + var display = $el.css("display"); + $el.data("restore-display-mode", display); + + if (display === "inline" || display === "inline-block") { + $el.hide(); + if (err.message !== "") { + var errorSpan = $("").addClass(errClass); + errorSpan.text(err.message); + $el.after(errorSpan); + } + } else if (display === "block") { + // If block, add an error just after the el, set visibility:none on the + // el, and position the error to be on top of the el. + // Mark it with a unique ID and CSS class so we can remove it later. + $el.css("visibility", "hidden"); + if (err.message !== "") { + var errorDiv = $("
").addClass(errClass).css("position", "absolute") + .css("top", el.offsetTop) + .css("left", el.offsetLeft) + // setting width can push out the page size, forcing otherwise + // unnecessary scrollbars to appear and making it impossible for + // the element to shrink; so use max-width instead + .css("maxWidth", el.offsetWidth) + .css("height", el.offsetHeight); + errorDiv.text(err.message); + $el.after(errorDiv); + + // Really dumb way to keep the size/position of the error in sync with + // the parent element as the window is resized or whatever. + var intId = setInterval(function() { + if (!errorDiv[0].parentElement) { + clearInterval(intId); + return; + } + errorDiv + .css("top", el.offsetTop) + .css("left", el.offsetLeft) + .css("maxWidth", el.offsetWidth) + .css("height", el.offsetHeight); + }, 500); + } + } + }, + clearError: function(el) { + var $el = $(el); + var display = $el.data("restore-display-mode"); + $el.data("restore-display-mode", null); + + if (display === "inline" || display === "inline-block") { + if (display) + $el.css("display", display); + $(el.nextSibling).filter(".htmlwidgets-error").remove(); + } else if (display === "block"){ + $el.css("visibility", "inherit"); + $(el.nextSibling).filter(".htmlwidgets-error").remove(); + } + }, + sizing: {} + }; + + // Called by widget bindings to register a new type of widget. The definition + // object can contain the following properties: + // - name (required) - A string indicating the binding name, which will be + // used by default as the CSS classname to look for. + // - initialize (optional) - A function(el) that will be called once per + // widget element; if a value is returned, it will be passed as the third + // value to renderValue. + // - renderValue (required) - A function(el, data, initValue) that will be + // called with data. Static contexts will cause this to be called once per + // element; Shiny apps will cause this to be called multiple times per + // element, as the data changes. + window.HTMLWidgets.widget = function(definition) { + if (!definition.name) { + throw new Error("Widget must have a name"); + } + if (!definition.type) { + throw new Error("Widget must have a type"); + } + // Currently we only support output widgets + if (definition.type !== "output") { + throw new Error("Unrecognized widget type '" + definition.type + "'"); + } + // TODO: Verify that .name is a valid CSS classname + + // Support new-style instance-bound definitions. Old-style class-bound + // definitions have one widget "object" per widget per type/class of + // widget; the renderValue and resize methods on such widget objects + // take el and instance arguments, because the widget object can't + // store them. New-style instance-bound definitions have one widget + // object per widget instance; the definition that's passed in doesn't + // provide renderValue or resize methods at all, just the single method + // factory(el, width, height) + // which returns an object that has renderValue(x) and resize(w, h). + // This enables a far more natural programming style for the widget + // author, who can store per-instance state using either OO-style + // instance fields or functional-style closure variables (I guess this + // is in contrast to what can only be called C-style pseudo-OO which is + // what we required before). + if (definition.factory) { + definition = createLegacyDefinitionAdapter(definition); + } + + if (!definition.renderValue) { + throw new Error("Widget must have a renderValue function"); + } + + // For static rendering (non-Shiny), use a simple widget registration + // scheme. We also use this scheme for Shiny apps/documents that also + // contain static widgets. + window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || []; + // Merge defaults into the definition; don't mutate the original definition. + var staticBinding = extend({}, defaults, definition); + overrideMethod(staticBinding, "find", function(superfunc) { + return function(scope) { + var results = superfunc(scope); + // Filter out Shiny outputs, we only want the static kind + return filterByClass(results, "html-widget-output", false); + }; + }); + window.HTMLWidgets.widgets.push(staticBinding); + + if (shinyMode) { + // Shiny is running. Register the definition with an output binding. + // The definition itself will not be the output binding, instead + // we will make an output binding object that delegates to the + // definition. This is because we foolishly used the same method + // name (renderValue) for htmlwidgets definition and Shiny bindings + // but they actually have quite different semantics (the Shiny + // bindings receive data that includes lots of metadata that it + // strips off before calling htmlwidgets renderValue). We can't + // just ignore the difference because in some widgets it's helpful + // to call this.renderValue() from inside of resize(), and if + // we're not delegating, then that call will go to the Shiny + // version instead of the htmlwidgets version. + + // Merge defaults with definition, without mutating either. + var bindingDef = extend({}, defaults, definition); + + // This object will be our actual Shiny binding. + var shinyBinding = new Shiny.OutputBinding(); + + // With a few exceptions, we'll want to simply use the bindingDef's + // version of methods if they are available, otherwise fall back to + // Shiny's defaults. NOTE: If Shiny's output bindings gain additional + // methods in the future, and we want them to be overrideable by + // HTMLWidget binding definitions, then we'll need to add them to this + // list. + delegateMethod(shinyBinding, bindingDef, "getId"); + delegateMethod(shinyBinding, bindingDef, "onValueChange"); + delegateMethod(shinyBinding, bindingDef, "onValueError"); + delegateMethod(shinyBinding, bindingDef, "renderError"); + delegateMethod(shinyBinding, bindingDef, "clearError"); + delegateMethod(shinyBinding, bindingDef, "showProgress"); + + // The find, renderValue, and resize are handled differently, because we + // want to actually decorate the behavior of the bindingDef methods. + + shinyBinding.find = function(scope) { + var results = bindingDef.find(scope); + + // Only return elements that are Shiny outputs, not static ones + var dynamicResults = results.filter(".html-widget-output"); + + // It's possible that whatever caused Shiny to think there might be + // new dynamic outputs, also caused there to be new static outputs. + // Since there might be lots of different htmlwidgets bindings, we + // schedule execution for later--no need to staticRender multiple + // times. + if (results.length !== dynamicResults.length) + scheduleStaticRender(); + + return dynamicResults; + }; + + // Wrap renderValue to handle initialization, which unfortunately isn't + // supported natively by Shiny at the time of this writing. + + shinyBinding.renderValue = function(el, data) { + Shiny.renderDependencies(data.deps); + // Resolve strings marked as javascript literals to objects + if (!(data.evals instanceof Array)) data.evals = [data.evals]; + for (var i = 0; data.evals && i < data.evals.length; i++) { + window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]); + } + if (!bindingDef.renderOnNullValue) { + if (data.x === null) { + el.style.visibility = "hidden"; + return; + } else { + el.style.visibility = "inherit"; + } + } + if (!elementData(el, "initialized")) { + initSizing(el); + + elementData(el, "initialized", true); + if (bindingDef.initialize) { + var rect = el.getBoundingClientRect(); + var result = bindingDef.initialize(el, rect.width, rect.height); + elementData(el, "init_result", result); + } + } + bindingDef.renderValue(el, data.x, elementData(el, "init_result")); + evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]); + }; + + // Only override resize if bindingDef implements it + if (bindingDef.resize) { + shinyBinding.resize = function(el, width, height) { + // Shiny can call resize before initialize/renderValue have been + // called, which doesn't make sense for widgets. + if (elementData(el, "initialized")) { + bindingDef.resize(el, width, height, elementData(el, "init_result")); + } + }; + } + + Shiny.outputBindings.register(shinyBinding, bindingDef.name); + } + }; + + var scheduleStaticRenderTimerId = null; + function scheduleStaticRender() { + if (!scheduleStaticRenderTimerId) { + scheduleStaticRenderTimerId = setTimeout(function() { + scheduleStaticRenderTimerId = null; + window.HTMLWidgets.staticRender(); + }, 1); + } + } + + // Render static widgets after the document finishes loading + // Statically render all elements that are of this widget's class + window.HTMLWidgets.staticRender = function() { + var bindings = window.HTMLWidgets.widgets || []; + forEach(bindings, function(binding) { + var matches = binding.find(document.documentElement); + forEach(matches, function(el) { + var sizeObj = initSizing(el, binding); + + var getSize = function(el) { + if (sizeObj) { + return {w: sizeObj.getWidth(), h: sizeObj.getHeight()} + } else { + var rect = el.getBoundingClientRect(); + return {w: rect.width, h: rect.height} + } + }; + + if (hasClass(el, "html-widget-static-bound")) + return; + el.className = el.className + " html-widget-static-bound"; + + var initResult; + if (binding.initialize) { + var size = getSize(el); + initResult = binding.initialize(el, size.w, size.h); + elementData(el, "init_result", initResult); + } + + if (binding.resize) { + var lastSize = getSize(el); + var resizeHandler = function(e) { + var size = getSize(el); + if (size.w === 0 && size.h === 0) + return; + if (size.w === lastSize.w && size.h === lastSize.h) + return; + lastSize = size; + binding.resize(el, size.w, size.h, initResult); + }; + + on(window, "resize", resizeHandler); + + // This is needed for cases where we're running in a Shiny + // app, but the widget itself is not a Shiny output, but + // rather a simple static widget. One example of this is + // an rmarkdown document that has runtime:shiny and widget + // that isn't in a render function. Shiny only knows to + // call resize handlers for Shiny outputs, not for static + // widgets, so we do it ourselves. + if (window.jQuery) { + window.jQuery(document).on( + "shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets", + resizeHandler + ); + window.jQuery(document).on( + "hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets", + resizeHandler + ); + } + + // This is needed for the specific case of ioslides, which + // flips slides between display:none and display:block. + // Ideally we would not have to have ioslide-specific code + // here, but rather have ioslides raise a generic event, + // but the rmarkdown package just went to CRAN so the + // window to getting that fixed may be long. + if (window.addEventListener) { + // It's OK to limit this to window.addEventListener + // browsers because ioslides itself only supports + // such browsers. + on(document, "slideenter", resizeHandler); + on(document, "slideleave", resizeHandler); + } + } + + var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']"); + if (scriptData) { + var data = JSON.parse(scriptData.textContent || scriptData.text); + // Resolve strings marked as javascript literals to objects + if (!(data.evals instanceof Array)) data.evals = [data.evals]; + for (var k = 0; data.evals && k < data.evals.length; k++) { + window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]); + } + binding.renderValue(el, data.x, initResult); + evalAndRun(data.jsHooks.render, initResult, [el, data.x]); + } + }); + }); + + invokePostRenderHandlers(); + } + + + function has_jQuery3() { + if (!window.jQuery) { + return false; + } + var $version = window.jQuery.fn.jquery; + var $major_version = parseInt($version.split(".")[0]); + return $major_version >= 3; + } + + /* + / Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's + / on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now + / really means $(setTimeout(fn)). + / https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous + / + / Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny + / one tick later than it did before, which means staticRender() is + / called renderValue() earlier than (advanced) widget authors might be expecting. + / https://github.com/rstudio/shiny/issues/2630 + / + / For a concrete example, leaflet has some methods (e.g., updateBounds) + / which reference Shiny methods registered in initShiny (e.g., setInputValue). + / Since leaflet is privy to this life-cycle, it knows to use setTimeout() to + / delay execution of those methods (until Shiny methods are ready) + / https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268 + / + / Ideally widget authors wouldn't need to use this setTimeout() hack that + / leaflet uses to call Shiny methods on a staticRender(). In the long run, + / the logic initShiny should be broken up so that method registration happens + / right away, but binding happens later. + */ + function maybeStaticRenderLater() { + if (shinyMode && has_jQuery3()) { + window.jQuery(window.HTMLWidgets.staticRender); + } else { + window.HTMLWidgets.staticRender(); + } + } + + if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", function() { + document.removeEventListener("DOMContentLoaded", arguments.callee, false); + maybeStaticRenderLater(); + }, false); + } else if (document.attachEvent) { + document.attachEvent("onreadystatechange", function() { + if (document.readyState === "complete") { + document.detachEvent("onreadystatechange", arguments.callee); + maybeStaticRenderLater(); + } + }); + } + + + window.HTMLWidgets.getAttachmentUrl = function(depname, key) { + // If no key, default to the first item + if (typeof(key) === "undefined") + key = 1; + + var link = document.getElementById(depname + "-" + key + "-attachment"); + if (!link) { + throw new Error("Attachment " + depname + "/" + key + " not found in document"); + } + return link.getAttribute("href"); + }; + + window.HTMLWidgets.dataframeToD3 = function(df) { + var names = []; + var length; + for (var name in df) { + if (df.hasOwnProperty(name)) + names.push(name); + if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof(length) !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; + }; + + window.HTMLWidgets.transposeArray2D = function(array) { + if (array.length === 0) return array; + var newArray = array[0].map(function(col, i) { + return array.map(function(row) { + return row[i] + }) + }); + return newArray; + }; + // Split value at splitChar, but allow splitChar to be escaped + // using escapeChar. Any other characters escaped by escapeChar + // will be included as usual (including escapeChar itself). + function splitWithEscape(value, splitChar, escapeChar) { + var results = []; + var escapeMode = false; + var currentResult = ""; + for (var pos = 0; pos < value.length; pos++) { + if (!escapeMode) { + if (value[pos] === splitChar) { + results.push(currentResult); + currentResult = ""; + } else if (value[pos] === escapeChar) { + escapeMode = true; + } else { + currentResult += value[pos]; + } + } else { + currentResult += value[pos]; + escapeMode = false; + } + } + if (currentResult !== "") { + results.push(currentResult); + } + return results; + } + // Function authored by Yihui/JJ Allaire + window.HTMLWidgets.evaluateStringMember = function(o, member) { + var parts = splitWithEscape(member, '.', '\\'); + for (var i = 0, l = parts.length; i < l; i++) { + var part = parts[i]; + // part may be a character or 'numeric' member name + if (o !== null && typeof o === "object" && part in o) { + if (i == (l - 1)) { // if we are at the end of the line then evalulate + if (typeof o[part] === "string") + o[part] = tryEval(o[part]); + } else { // otherwise continue to next embedded object + o = o[part]; + } + } + } + }; + + // Retrieve the HTMLWidget instance (i.e. the return value of an + // HTMLWidget binding's initialize() or factory() function) + // associated with an element, or null if none. + window.HTMLWidgets.getInstance = function(el) { + return elementData(el, "init_result"); + }; + + // Finds the first element in the scope that matches the selector, + // and returns the HTMLWidget instance (i.e. the return value of + // an HTMLWidget binding's initialize() or factory() function) + // associated with that element, if any. If no element matches the + // selector, or the first matching element has no HTMLWidget + // instance associated with it, then null is returned. + // + // The scope argument is optional, and defaults to window.document. + window.HTMLWidgets.find = function(scope, selector) { + if (arguments.length == 1) { + selector = scope; + scope = document; + } + + var el = scope.querySelector(selector); + if (el === null) { + return null; + } else { + return window.HTMLWidgets.getInstance(el); + } + }; + + // Finds all elements in the scope that match the selector, and + // returns the HTMLWidget instances (i.e. the return values of + // an HTMLWidget binding's initialize() or factory() function) + // associated with the elements, in an array. If elements that + // match the selector don't have an associated HTMLWidget + // instance, the returned array will contain nulls. + // + // The scope argument is optional, and defaults to window.document. + window.HTMLWidgets.findAll = function(scope, selector) { + if (arguments.length == 1) { + selector = scope; + scope = document; + } + + var nodes = scope.querySelectorAll(selector); + var results = []; + for (var i = 0; i < nodes.length; i++) { + results.push(window.HTMLWidgets.getInstance(nodes[i])); + } + return results; + }; + + var postRenderHandlers = []; + function invokePostRenderHandlers() { + while (postRenderHandlers.length) { + var handler = postRenderHandlers.shift(); + if (handler) { + handler(); + } + } + } + + // Register the given callback function to be invoked after the + // next time static widgets are rendered. + window.HTMLWidgets.addPostRenderHandler = function(callback) { + postRenderHandlers.push(callback); + }; + + // Takes a new-style instance-bound definition, and returns an + // old-style class-bound definition. This saves us from having + // to rewrite all the logic in this file to accomodate both + // types of definitions. + function createLegacyDefinitionAdapter(defn) { + var result = { + name: defn.name, + type: defn.type, + initialize: function(el, width, height) { + return defn.factory(el, width, height); + }, + renderValue: function(el, x, instance) { + return instance.renderValue(x); + }, + resize: function(el, width, height, instance) { + return instance.resize(width, height); + } + }; + + if (defn.find) + result.find = defn.find; + if (defn.renderError) + result.renderError = defn.renderError; + if (defn.clearError) + result.clearError = defn.clearError; + + return result; + } +})(); diff --git a/2311/site_libs/jquery-3.6.0/jquery-3.6.0.js b/2311/site_libs/jquery-3.6.0/jquery-3.6.0.js new file mode 100644 index 00000000..fc6c299b --- /dev/null +++ b/2311/site_libs/jquery-3.6.0/jquery-3.6.0.js @@ -0,0 +1,10881 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2021-03-02T17:08Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2021-02-16 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( "' ); + + var leadingWs = text.match( /^\n?(\s*)/ )[1].length, + leadingTabs = text.match( /^\n?(\t*)/ )[1].length; + + if( leadingTabs > 0 ) { + text = text.replace( new RegExp('\\n?\\t{' + leadingTabs + '}','g'), '\n' ); + } + else if( leadingWs > 1 ) { + text = text.replace( new RegExp('\\n? {' + leadingWs + '}', 'g'), '\n' ); + } + + return text; + + } + + /** + * Given a markdown slide section element, this will + * return all arguments that aren't related to markdown + * parsing. Used to forward any other user-defined arguments + * to the output markdown slide. + */ + function getForwardedAttributes( section ) { + + var attributes = section.attributes; + var result = []; + + for( var i = 0, len = attributes.length; i < len; i++ ) { + var name = attributes[i].name, + value = attributes[i].value; + + // disregard attributes that are used for markdown loading/parsing + if( /data\-(markdown|separator|vertical|notes)/gi.test( name ) ) continue; + + if( value ) { + result.push( name + '="' + value + '"' ); + } + else { + result.push( name ); + } + } + + return result.join( ' ' ); + + } + + /** + * Inspects the given options and fills out default + * values for what's not defined. + */ + function getSlidifyOptions( options ) { + + options = options || {}; + options.separator = options.separator || DEFAULT_SLIDE_SEPARATOR; + options.notesSeparator = options.notesSeparator || DEFAULT_NOTES_SEPARATOR; + options.attributes = options.attributes || ''; + + return options; + + } + + /** + * Helper function for constructing a markdown slide. + */ + function createMarkdownSlide( content, options ) { + + options = getSlidifyOptions( options ); + + var notesMatch = content.split( new RegExp( options.notesSeparator, 'mgi' ) ); + + if( notesMatch.length === 2 ) { + content = notesMatch[0] + ''; + } + + // prevent script end tags in the content from interfering + // with parsing + content = content.replace( /<\/script>/g, SCRIPT_END_PLACEHOLDER ); + + return ''; + + } + + /** + * Parses a data string into multiple slides based + * on the passed in separator arguments. + */ + function slidify( markdown, options ) { + + options = getSlidifyOptions( options ); + + var separatorRegex = new RegExp( options.separator + ( options.verticalSeparator ? '|' + options.verticalSeparator : '' ), 'mg' ), + horizontalSeparatorRegex = new RegExp( options.separator ); + + var matches, + lastIndex = 0, + isHorizontal, + wasHorizontal = true, + content, + sectionStack = []; + + // iterate until all blocks between separators are stacked up + while( matches = separatorRegex.exec( markdown ) ) { + var notes = null; + + // determine direction (horizontal by default) + isHorizontal = horizontalSeparatorRegex.test( matches[0] ); + + if( !isHorizontal && wasHorizontal ) { + // create vertical stack + sectionStack.push( [] ); + } + + // pluck slide content from markdown input + content = markdown.substring( lastIndex, matches.index ); + + if( isHorizontal && wasHorizontal ) { + // add to horizontal stack + sectionStack.push( content ); + } + else { + // add to vertical stack + sectionStack[sectionStack.length-1].push( content ); + } + + lastIndex = separatorRegex.lastIndex; + wasHorizontal = isHorizontal; + } + + // add the remaining slide + ( wasHorizontal ? sectionStack : sectionStack[sectionStack.length-1] ).push( markdown.substring( lastIndex ) ); + + var markdownSections = ''; + + // flatten the hierarchical stack, and insert
tags + for( var i = 0, len = sectionStack.length; i < len; i++ ) { + // vertical + if( sectionStack[i] instanceof Array ) { + markdownSections += '
'; + + sectionStack[i].forEach( function( child ) { + markdownSections += '
' + createMarkdownSlide( child, options ) + '
'; + } ); + + markdownSections += '
'; + } + else { + markdownSections += '
' + createMarkdownSlide( sectionStack[i], options ) + '
'; + } + } + + return markdownSections; + + } + + /** + * Parses any current data-markdown slides, splits + * multi-slide markdown into separate sections and + * handles loading of external markdown. + */ + function processSlides( scope ) { + + return new Promise( function( resolve ) { + + var externalPromises = []; + + [].slice.call( scope.querySelectorAll( 'section[data-markdown]:not([data-markdown-parsed])') ).forEach( function( section, i ) { + + if( section.getAttribute( 'data-markdown' ).length ) { + + externalPromises.push( loadExternalMarkdown( section ).then( + + // Finished loading external file + function( xhr, url ) { + section.outerHTML = slidify( xhr.responseText, { + separator: section.getAttribute( 'data-separator' ), + verticalSeparator: section.getAttribute( 'data-separator-vertical' ), + notesSeparator: section.getAttribute( 'data-separator-notes' ), + attributes: getForwardedAttributes( section ) + }); + }, + + // Failed to load markdown + function( xhr, url ) { + section.outerHTML = '
' + + 'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' + + 'Check your browser\'s JavaScript console for more details.' + + '

Remember that you need to serve the presentation HTML from a HTTP server.

' + + '
'; + } + + ) ); + + } + else { + + section.outerHTML = slidify( getMarkdownFromSlide( section ), { + separator: section.getAttribute( 'data-separator' ), + verticalSeparator: section.getAttribute( 'data-separator-vertical' ), + notesSeparator: section.getAttribute( 'data-separator-notes' ), + attributes: getForwardedAttributes( section ) + }); + + } + + }); + + Promise.all( externalPromises ).then( resolve ); + + } ); + + } + + function loadExternalMarkdown( section ) { + + return new Promise( function( resolve, reject ) { + + var xhr = new XMLHttpRequest(), + url = section.getAttribute( 'data-markdown' ); + + var datacharset = section.getAttribute( 'data-charset' ); + + // see https://developer.mozilla.org/en-US/docs/Web/API/element.getAttribute#Notes + if( datacharset != null && datacharset != '' ) { + xhr.overrideMimeType( 'text/html; charset=' + datacharset ); + } + + xhr.onreadystatechange = function( section, xhr ) { + if( xhr.readyState === 4 ) { + // file protocol yields status code 0 (useful for local debug, mobile applications etc.) + if ( ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status === 0 ) { + + resolve( xhr, url ); + + } + else { + + reject( xhr, url ); + + } + } + }.bind( this, section, xhr ); + + xhr.open( 'GET', url, true ); + + try { + xhr.send(); + } + catch ( e ) { + console.warn( 'Failed to get the Markdown file ' + url + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + e ); + resolve( xhr, url ); + } + + } ); + + } + + /** + * Check if a node value has the attributes pattern. + * If yes, extract it and add that value as one or several attributes + * to the target element. + * + * You need Cache Killer on Chrome to see the effect on any FOM transformation + * directly on refresh (F5) + * http://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development/7000899#answer-11786277 + */ + function addAttributeInElement( node, elementTarget, separator ) { + + var mardownClassesInElementsRegex = new RegExp( separator, 'mg' ); + var mardownClassRegex = new RegExp( "([^\"= ]+?)=\"([^\"]+?)\"|(data-[^\"= ]+?)(?=[\" ])", 'mg' ); + var nodeValue = node.nodeValue; + var matches, + matchesClass; + if( matches = mardownClassesInElementsRegex.exec( nodeValue ) ) { + + var classes = matches[1]; + nodeValue = nodeValue.substring( 0, matches.index ) + nodeValue.substring( mardownClassesInElementsRegex.lastIndex ); + node.nodeValue = nodeValue; + while( matchesClass = mardownClassRegex.exec( classes ) ) { + if( matchesClass[2] ) { + elementTarget.setAttribute( matchesClass[1], matchesClass[2] ); + } else { + elementTarget.setAttribute( matchesClass[3], "" ); + } + } + return true; + } + return false; + } + + /** + * Add attributes to the parent element of a text node, + * or the element of an attribute node. + */ + function addAttributes( section, element, previousElement, separatorElementAttributes, separatorSectionAttributes ) { + + if ( element != null && element.childNodes != undefined && element.childNodes.length > 0 ) { + var previousParentElement = element; + for( var i = 0; i < element.childNodes.length; i++ ) { + var childElement = element.childNodes[i]; + if ( i > 0 ) { + var j = i - 1; + while ( j >= 0 ) { + var aPreviousChildElement = element.childNodes[j]; + if ( typeof aPreviousChildElement.setAttribute == 'function' && aPreviousChildElement.tagName != "BR" ) { + previousParentElement = aPreviousChildElement; + break; + } + j = j - 1; + } + } + var parentSection = section; + if( childElement.nodeName == "section" ) { + parentSection = childElement ; + previousParentElement = childElement ; + } + if ( typeof childElement.setAttribute == 'function' || childElement.nodeType == Node.COMMENT_NODE ) { + addAttributes( parentSection, childElement, previousParentElement, separatorElementAttributes, separatorSectionAttributes ); + } + } + } + + if ( element.nodeType == Node.COMMENT_NODE ) { + if ( addAttributeInElement( element, previousElement, separatorElementAttributes ) == false ) { + addAttributeInElement( element, section, separatorSectionAttributes ); + } + } + } + + /** + * Converts any current data-markdown slides in the + * DOM to HTML. + */ + function convertSlides() { + + var sections = deck.getRevealElement().querySelectorAll( '[data-markdown]:not([data-markdown-parsed])'); + + [].slice.call( sections ).forEach( function( section ) { + + section.setAttribute( 'data-markdown-parsed', true ) + + var notes = section.querySelector( 'aside.notes' ); + var markdown = getMarkdownFromSlide( section ); + + section.innerHTML = marked( markdown ); + addAttributes( section, section, null, section.getAttribute( 'data-element-attributes' ) || + section.parentNode.getAttribute( 'data-element-attributes' ) || + DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR, + section.getAttribute( 'data-attributes' ) || + section.parentNode.getAttribute( 'data-attributes' ) || + DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR); + + // If there were notes, we need to re-add them after + // having overwritten the section's HTML + if( notes ) { + section.appendChild( notes ); + } + + } ); + + return Promise.resolve(); + + } + + function escapeForHTML( input ) { + + return input.replace( /([&<>'"])/g, char => HTML_ESCAPE_MAP[char] ); + + } + + return { + id: 'markdown', + + /** + * Starts processing and converting Markdown within the + * current reveal.js deck. + */ + init: function( reveal ) { + + deck = reveal; + + let { renderer, animateLists, ...markedOptions } = deck.getConfig().markdown || {}; + + if( !renderer ) { + renderer = new marked.Renderer(); + + renderer.code = ( code, language ) => { + + // Off by default + let lineNumbers = ''; + + // Users can opt in to show line numbers and highlight + // specific lines. + // ```javascript [] show line numbers + // ```javascript [1,4-8] highlights lines 1 and 4-8 + if( CODE_LINE_NUMBER_REGEX.test( language ) ) { + lineNumbers = language.match( CODE_LINE_NUMBER_REGEX )[1].trim(); + lineNumbers = `data-line-numbers="${lineNumbers}"`; + language = language.replace( CODE_LINE_NUMBER_REGEX, '' ).trim(); + } + + // Escape before this gets injected into the DOM to + // avoid having the HTML parser alter our code before + // highlight.js is able to read it + code = escapeForHTML( code ); + + return `
${code}
`; + }; + } + + if( animateLists === true ) { + renderer.listitem = text => `
  • ${text}
  • `; + } + + marked.setOptions( { + renderer, + ...markedOptions + } ); + + return processSlides( deck.getRevealElement() ).then( convertSlides ); + + }, + + // TODO: Do these belong in the API? + processSlides: processSlides, + convertSlides: convertSlides, + slidify: slidify, + marked: marked + } + +}; + +export default Plugin; diff --git a/2311/site_libs/revealjs/plugin/math/katex.js b/2311/site_libs/revealjs/plugin/math/katex.js new file mode 100755 index 00000000..a8b47c4a --- /dev/null +++ b/2311/site_libs/revealjs/plugin/math/katex.js @@ -0,0 +1,96 @@ +/** + * A plugin which enables rendering of math equations inside + * of reveal.js slides. Essentially a thin wrapper for KaTeX. + * + * @author Hakim El Hattab + * @author Gerhard Burger + */ +export const KaTeX = () => { + let deck; + + let defaultOptions = { + version: 'latest', + delimiters: [ + {left: '$$', right: '$$', display: true}, // Note: $$ has to come before $ + {left: '$', right: '$', display: false}, + {left: '\\(', right: '\\)', display: false}, + {left: '\\[', right: '\\]', display: true} + ], + ignoredTags: ['script', 'noscript', 'style', 'textarea', 'pre'] + } + + const loadCss = src => { + let link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = src; + document.head.appendChild(link); + }; + + /** + * Loads a JavaScript file and returns a Promise for when it is loaded + * Credits: https://aaronsmith.online/easily-load-an-external-script-using-javascript/ + */ + const loadScript = src => { + return new Promise((resolve, reject) => { + const script = document.createElement('script') + script.type = 'text/javascript' + script.onload = resolve + script.onerror = reject + script.src = src + document.head.append(script) + }) + }; + + async function loadScripts(urls) { + for(const url of urls) { + await loadScript(url); + } + } + + return { + id: 'katex', + + init: function (reveal) { + + deck = reveal; + + let revealOptions = deck.getConfig().katex || {}; + + let options = {...defaultOptions, ...revealOptions}; + const {local, version, extensions, ...katexOptions} = options; + + let baseUrl = options.local || 'https://cdn.jsdelivr.net/npm/katex'; + let versionString = options.local ? '' : '@' + options.version; + + let cssUrl = baseUrl + versionString + '/dist/katex.min.css'; + let katexUrl = baseUrl + versionString + '/dist/katex.min.js'; + let mhchemUrl = baseUrl + versionString + '/dist/contrib/mhchem.min.js' + let karUrl = baseUrl + versionString + '/dist/contrib/auto-render.min.js'; + + let katexScripts = [katexUrl]; + if(options.extensions && options.extensions.includes("mhchem")) { + katexScripts.push(mhchemUrl); + } + katexScripts.push(karUrl); + + const renderMath = () => { + renderMathInElement(reveal.getSlidesElement(), katexOptions); + deck.layout(); + } + + loadCss(cssUrl); + + // For some reason dynamically loading with defer attribute doesn't result in the expected behavior, the below code does + loadScripts(katexScripts).then(() => { + if( deck.isReady() ) { + renderMath(); + } + else { + deck.on( 'ready', renderMath.bind( this ) ); + } + }); + + } + } + +}; diff --git a/2311/site_libs/revealjs/plugin/math/math.esm.js b/2311/site_libs/revealjs/plugin/math/math.esm.js new file mode 100644 index 00000000..a0d1468d --- /dev/null +++ b/2311/site_libs/revealjs/plugin/math/math.esm.js @@ -0,0 +1 @@ +var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},e=function(t){return t&&t.Math==Math&&t},n=e("object"==typeof globalThis&&globalThis)||e("object"==typeof window&&window)||e("object"==typeof self&&self)||e("object"==typeof t&&t)||function(){return this}()||Function("return this")(),r={},o=function(t){try{return!!t()}catch(t){return!0}},i=!o((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),a={},c={}.propertyIsEnumerable,u=Object.getOwnPropertyDescriptor,f=u&&!c.call({1:2},1);a.f=f?function(t){var e=u(this,t);return!!e&&e.enumerable}:c;var s=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}},l={}.toString,p=function(t){return l.call(t).slice(8,-1)},h=p,v="".split,d=o((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==h(t)?v.call(t,""):Object(t)}:Object,y=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t},g=d,m=y,b=function(t){return g(m(t))},w=function(t){return"object"==typeof t?null!==t:"function"==typeof t},j=w,x=function(t,e){if(!j(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!j(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!j(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!j(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")},O=y,E=function(t){return Object(O(t))},S=E,T={}.hasOwnProperty,P=function(t,e){return T.call(S(t),e)},_=w,k=n.document,L=_(k)&&_(k.createElement),M=function(t){return L?k.createElement(t):{}},A=M,I=!i&&!o((function(){return 7!=Object.defineProperty(A("div"),"a",{get:function(){return 7}}).a})),R=i,C=a,N=s,F=b,J=x,D=P,$=I,G=Object.getOwnPropertyDescriptor;r.f=R?G:function(t,e){if(t=F(t),e=J(e,!0),$)try{return G(t,e)}catch(t){}if(D(t,e))return N(!C.f.call(t,e),t[e])};var H={},z=w,W=function(t){if(!z(t))throw TypeError(String(t)+" is not an object");return t},q=i,U=I,K=W,Q=x,X=Object.defineProperty;H.f=q?X:function(t,e,n){if(K(t),e=Q(e,!0),K(n),U)try{return X(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t};var Y=H,B=s,V=i?function(t,e,n){return Y.f(t,e,B(1,n))}:function(t,e,n){return t[e]=n,t},Z={exports:{}},tt=n,et=V,nt=function(t,e){try{et(tt,t,e)}catch(n){tt[t]=e}return e},rt=nt,ot=n["__core-js_shared__"]||rt("__core-js_shared__",{}),it=ot,at=Function.toString;"function"!=typeof it.inspectSource&&(it.inspectSource=function(t){return at.call(t)});var ct=it.inspectSource,ut=ct,ft=n.WeakMap,st="function"==typeof ft&&/native code/.test(ut(ft)),lt={exports:{}},pt=ot;(lt.exports=function(t,e){return pt[t]||(pt[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.12.1",mode:"global",copyright:"© 2021 Denis Pushkarev (zloirock.ru)"});var ht,vt,dt,yt=0,gt=Math.random(),mt=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++yt+gt).toString(36)},bt=lt.exports,wt=mt,jt=bt("keys"),xt=function(t){return jt[t]||(jt[t]=wt(t))},Ot={},Et=st,St=w,Tt=V,Pt=P,_t=ot,kt=xt,Lt=Ot,Mt=n.WeakMap;if(Et||_t.state){var At=_t.state||(_t.state=new Mt),It=At.get,Rt=At.has,Ct=At.set;ht=function(t,e){if(Rt.call(At,t))throw new TypeError("Object already initialized");return e.facade=t,Ct.call(At,t,e),e},vt=function(t){return It.call(At,t)||{}},dt=function(t){return Rt.call(At,t)}}else{var Nt=kt("state");Lt[Nt]=!0,ht=function(t,e){if(Pt(t,Nt))throw new TypeError("Object already initialized");return e.facade=t,Tt(t,Nt,e),e},vt=function(t){return Pt(t,Nt)?t[Nt]:{}},dt=function(t){return Pt(t,Nt)}}var Ft={set:ht,get:vt,has:dt,enforce:function(t){return dt(t)?vt(t):ht(t,{})},getterFor:function(t){return function(e){var n;if(!St(e)||(n=vt(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}},Jt=n,Dt=V,$t=P,Gt=nt,Ht=ct,zt=Ft.get,Wt=Ft.enforce,qt=String(String).split("String");(Z.exports=function(t,e,n,r){var o,i=!!r&&!!r.unsafe,a=!!r&&!!r.enumerable,c=!!r&&!!r.noTargetGet;"function"==typeof n&&("string"!=typeof e||$t(n,"name")||Dt(n,"name",e),(o=Wt(n)).source||(o.source=qt.join("string"==typeof e?e:""))),t!==Jt?(i?!c&&t[e]&&(a=!0):delete t[e],a?t[e]=n:Dt(t,e,n)):a?t[e]=n:Gt(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&zt(this).source||Ht(this)}));var Ut=n,Kt=n,Qt=function(t){return"function"==typeof t?t:void 0},Xt=function(t,e){return arguments.length<2?Qt(Ut[t])||Qt(Kt[t]):Ut[t]&&Ut[t][e]||Kt[t]&&Kt[t][e]},Yt={},Bt=Math.ceil,Vt=Math.floor,Zt=function(t){return isNaN(t=+t)?0:(t>0?Vt:Bt)(t)},te=Zt,ee=Math.min,ne=function(t){return t>0?ee(te(t),9007199254740991):0},re=Zt,oe=Math.max,ie=Math.min,ae=b,ce=ne,ue=function(t,e){var n=re(t);return n<0?oe(n+e,0):ie(n,e)},fe=function(t){return function(e,n,r){var o,i=ae(e),a=ce(i.length),c=ue(r,a);if(t&&n!=n){for(;a>c;)if((o=i[c++])!=o)return!0}else for(;a>c;c++)if((t||c in i)&&i[c]===n)return t||c||0;return!t&&-1}},se={includes:fe(!0),indexOf:fe(!1)},le=P,pe=b,he=se.indexOf,ve=Ot,de=function(t,e){var n,r=pe(t),o=0,i=[];for(n in r)!le(ve,n)&&le(r,n)&&i.push(n);for(;e.length>o;)le(r,n=e[o++])&&(~he(i,n)||i.push(n));return i},ye=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],ge=de,me=ye.concat("length","prototype");Yt.f=Object.getOwnPropertyNames||function(t){return ge(t,me)};var be={};be.f=Object.getOwnPropertySymbols;var we=Yt,je=be,xe=W,Oe=Xt("Reflect","ownKeys")||function(t){var e=we.f(xe(t)),n=je.f;return n?e.concat(n(t)):e},Ee=P,Se=Oe,Te=r,Pe=H,_e=o,ke=/#|\.prototype\./,Le=function(t,e){var n=Ae[Me(t)];return n==Re||n!=Ie&&("function"==typeof e?_e(e):!!e)},Me=Le.normalize=function(t){return String(t).replace(ke,".").toLowerCase()},Ae=Le.data={},Ie=Le.NATIVE="N",Re=Le.POLYFILL="P",Ce=Le,Ne=n,Fe=r.f,Je=V,De=Z.exports,$e=nt,Ge=function(t,e){for(var n=Se(e),r=Pe.f,o=Te.f,i=0;io;)for(var c,u=Ze(arguments[o++]),f=i?Xe(u).concat(i(u)):Xe(u),s=f.length,l=0;s>l;)c=f[l++],Ke&&!a.call(u,c)||(n[c]=u[c]);return n}:tn;function rn(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function on(t){for(var e=1;e=0||(o[n]=t[n]);return o}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n])}return o}function sn(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,c=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){c=!0,i=t},f:function(){try{a||null==n.return||n.return()}finally{if(c)throw i}}}}ze({target:"Object",stat:!0,forced:Object.assign!==nn},{assign:nn});!function(t){var e=function(t){var e,n=Object.prototype,r=n.hasOwnProperty,o="function"==typeof Symbol?Symbol:{},i=o.iterator||"@@iterator",a=o.asyncIterator||"@@asyncIterator",c=o.toStringTag||"@@toStringTag";function u(t,e,n){return Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{u({},"")}catch(t){u=function(t,e,n){return t[e]=n}}function f(t,e,n,r){var o=e&&e.prototype instanceof y?e:y,i=Object.create(o.prototype),a=new _(r||[]);return i._invoke=function(t,e,n){var r=l;return function(o,i){if(r===h)throw new Error("Generator is already running");if(r===v){if("throw"===o)throw i;return L()}for(n.method=o,n.arg=i;;){var a=n.delegate;if(a){var c=S(a,n);if(c){if(c===d)continue;return c}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(r===l)throw r=v,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);r=h;var u=s(t,e,n);if("normal"===u.type){if(r=n.done?v:p,u.arg===d)continue;return{value:u.arg,done:n.done}}"throw"===u.type&&(r=v,n.method="throw",n.arg=u.arg)}}}(t,n,a),i}function s(t,e,n){try{return{type:"normal",arg:t.call(e,n)}}catch(t){return{type:"throw",arg:t}}}t.wrap=f;var l="suspendedStart",p="suspendedYield",h="executing",v="completed",d={};function y(){}function g(){}function m(){}var b={};b[i]=function(){return this};var w=Object.getPrototypeOf,j=w&&w(w(k([])));j&&j!==n&&r.call(j,i)&&(b=j);var x=m.prototype=y.prototype=Object.create(b);function O(t){["next","throw","return"].forEach((function(e){u(t,e,(function(t){return this._invoke(e,t)}))}))}function E(t,e){function n(o,i,a,c){var u=s(t[o],t,i);if("throw"!==u.type){var f=u.arg,l=f.value;return l&&"object"==typeof l&&r.call(l,"__await")?e.resolve(l.__await).then((function(t){n("next",t,a,c)}),(function(t){n("throw",t,a,c)})):e.resolve(l).then((function(t){f.value=t,a(f)}),(function(t){return n("throw",t,a,c)}))}c(u.arg)}var o;this._invoke=function(t,r){function i(){return new e((function(e,o){n(t,r,e,o)}))}return o=o?o.then(i,i):i()}}function S(t,n){var r=t.iterator[n.method];if(r===e){if(n.delegate=null,"throw"===n.method){if(t.iterator.return&&(n.method="return",n.arg=e,S(t,n),"throw"===n.method))return d;n.method="throw",n.arg=new TypeError("The iterator does not provide a 'throw' method")}return d}var o=s(r,t.iterator,n.arg);if("throw"===o.type)return n.method="throw",n.arg=o.arg,n.delegate=null,d;var i=o.arg;return i?i.done?(n[t.resultName]=i.value,n.next=t.nextLoc,"return"!==n.method&&(n.method="next",n.arg=e),n.delegate=null,d):i:(n.method="throw",n.arg=new TypeError("iterator result is not an object"),n.delegate=null,d)}function T(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function P(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function _(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(T,this),this.reset(!0)}function k(t){if(t){var n=t[i];if(n)return n.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var o=-1,a=function n(){for(;++o=0;--i){var a=this.tryEntries[i],c=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var u=r.call(a,"catchLoc"),f=r.call(a,"finallyLoc");if(u&&f){if(this.prev=0;--n){var o=this.tryEntries[n];if(o.tryLoc<=this.prev&&r.call(o,"finallyLoc")&&this.prev=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),P(n),d}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var r=n.completion;if("throw"===r.type){var o=r.arg;P(n)}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,n,r){return this.delegate={iterator:k(t),resultName:n,nextLoc:r},"next"===this.method&&(this.arg=e),d}},t}(t.exports);try{regeneratorRuntime=e}catch(t){Function("r","regeneratorRuntime = r")(e)}}({exports:{}});var pn,hn,vn=Xt("navigator","userAgent")||"",dn=vn,yn=n.process,gn=yn&&yn.versions,mn=gn&&gn.v8;mn?hn=(pn=mn.split("."))[0]<4?1:pn[0]+pn[1]:dn&&(!(pn=dn.match(/Edge\/(\d+)/))||pn[1]>=74)&&(pn=dn.match(/Chrome\/(\d+)/))&&(hn=pn[1]);var bn=hn&&+hn,wn=bn,jn=o,xn=!!Object.getOwnPropertySymbols&&!jn((function(){return!String(Symbol())||!Symbol.sham&&wn&&wn<41})),On=xn&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,En=n,Sn=lt.exports,Tn=P,Pn=mt,_n=xn,kn=On,Ln=Sn("wks"),Mn=En.Symbol,An=kn?Mn:Mn&&Mn.withoutSetter||Pn,In=function(t){return Tn(Ln,t)&&(_n||"string"==typeof Ln[t])||(_n&&Tn(Mn,t)?Ln[t]=Mn[t]:Ln[t]=An("Symbol."+t)),Ln[t]},Rn={};Rn[In("toStringTag")]="z";var Cn="[object z]"===String(Rn),Nn=Cn,Fn=p,Jn=In("toStringTag"),Dn="Arguments"==Fn(function(){return arguments}()),$n=Nn?Fn:function(t){var e,n,r;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=Object(t),Jn))?n:Dn?Fn(e):"Object"==(r=Fn(e))&&"function"==typeof e.callee?"Arguments":r},Gn=$n,Hn=Cn?{}.toString:function(){return"[object "+Gn(this)+"]"},zn=Cn,Wn=Z.exports,qn=Hn;zn||Wn(Object.prototype,"toString",qn,{unsafe:!0});var Un=n.Promise,Kn=Z.exports,Qn=w,Xn=W,Yn=function(t){if(!Qn(t)&&null!==t)throw TypeError("Can't set "+String(t)+" as a prototype");return t},Bn=Object.setPrototypeOf||("__proto__"in{}?function(){var t,e=!1,n={};try{(t=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set).call(n,[]),e=n instanceof Array}catch(t){}return function(n,r){return Xn(n),Yn(r),e?t.call(n,r):n.__proto__=r,n}}():void 0),Vn=H.f,Zn=P,tr=In("toStringTag"),er=Xt,nr=H,rr=i,or=In("species"),ir=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t},ar={},cr=ar,ur=In("iterator"),fr=Array.prototype,sr=ir,lr=function(t,e,n){if(sr(t),void 0===e)return t;switch(n){case 0:return function(){return t.call(e)};case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}},pr=$n,hr=ar,vr=In("iterator"),dr=W,yr=W,gr=function(t){return void 0!==t&&(cr.Array===t||fr[ur]===t)},mr=ne,br=lr,wr=function(t){if(null!=t)return t[vr]||t["@@iterator"]||hr[pr(t)]},jr=function(t){var e=t.return;if(void 0!==e)return dr(e.call(t)).value},xr=function(t,e){this.stopped=t,this.result=e},Or=In("iterator"),Er=!1;try{var Sr=0,Tr={next:function(){return{done:!!Sr++}},return:function(){Er=!0}};Tr[Or]=function(){return this},Array.from(Tr,(function(){throw 2}))}catch(t){}var Pr,_r,kr,Lr=W,Mr=ir,Ar=In("species"),Ir=Xt("document","documentElement"),Rr=/(?:iphone|ipod|ipad).*applewebkit/i.test(vn),Cr="process"==p(n.process),Nr=n,Fr=o,Jr=lr,Dr=Ir,$r=M,Gr=Rr,Hr=Cr,zr=Nr.location,Wr=Nr.setImmediate,qr=Nr.clearImmediate,Ur=Nr.process,Kr=Nr.MessageChannel,Qr=Nr.Dispatch,Xr=0,Yr={},Br=function(t){if(Yr.hasOwnProperty(t)){var e=Yr[t];delete Yr[t],e()}},Vr=function(t){return function(){Br(t)}},Zr=function(t){Br(t.data)},to=function(t){Nr.postMessage(t+"",zr.protocol+"//"+zr.host)};Wr&&qr||(Wr=function(t){for(var e=[],n=1;arguments.length>n;)e.push(arguments[n++]);return Yr[++Xr]=function(){("function"==typeof t?t:Function(t)).apply(void 0,e)},Pr(Xr),Xr},qr=function(t){delete Yr[t]},Hr?Pr=function(t){Ur.nextTick(Vr(t))}:Qr&&Qr.now?Pr=function(t){Qr.now(Vr(t))}:Kr&&!Gr?(kr=(_r=new Kr).port2,_r.port1.onmessage=Zr,Pr=Jr(kr.postMessage,kr,1)):Nr.addEventListener&&"function"==typeof postMessage&&!Nr.importScripts&&zr&&"file:"!==zr.protocol&&!Fr(to)?(Pr=to,Nr.addEventListener("message",Zr,!1)):Pr="onreadystatechange"in $r("script")?function(t){Dr.appendChild($r("script")).onreadystatechange=function(){Dr.removeChild(this),Br(t)}}:function(t){setTimeout(Vr(t),0)});var eo,no,ro,oo,io,ao,co,uo,fo={set:Wr,clear:qr},so=/web0s(?!.*chrome)/i.test(vn),lo=n,po=r.f,ho=fo.set,vo=Rr,yo=so,go=Cr,mo=lo.MutationObserver||lo.WebKitMutationObserver,bo=lo.document,wo=lo.process,jo=lo.Promise,xo=po(lo,"queueMicrotask"),Oo=xo&&xo.value;Oo||(eo=function(){var t,e;for(go&&(t=wo.domain)&&t.exit();no;){e=no.fn,no=no.next;try{e()}catch(t){throw no?oo():ro=void 0,t}}ro=void 0,t&&t.enter()},vo||go||yo||!mo||!bo?jo&&jo.resolve?((co=jo.resolve(void 0)).constructor=jo,uo=co.then,oo=function(){uo.call(co,eo)}):oo=go?function(){wo.nextTick(eo)}:function(){ho.call(lo,eo)}:(io=!0,ao=bo.createTextNode(""),new mo(eo).observe(ao,{characterData:!0}),oo=function(){ao.data=io=!io}));var Eo=Oo||function(t){var e={fn:t,next:void 0};ro&&(ro.next=e),no||(no=e,oo()),ro=e},So={},To=ir,Po=function(t){var e,n;this.promise=new t((function(t,r){if(void 0!==e||void 0!==n)throw TypeError("Bad Promise constructor");e=t,n=r})),this.resolve=To(e),this.reject=To(n)};So.f=function(t){return new Po(t)};var _o,ko,Lo,Mo,Ao=W,Io=w,Ro=So,Co=n,No="object"==typeof window,Fo=ze,Jo=n,Do=Xt,$o=Un,Go=Z.exports,Ho=function(t,e,n){for(var r in e)Kn(t,r,e[r],n);return t},zo=Bn,Wo=function(t,e,n){t&&!Zn(t=n?t:t.prototype,tr)&&Vn(t,tr,{configurable:!0,value:e})},qo=function(t){var e=er(t),n=nr.f;rr&&e&&!e[or]&&n(e,or,{configurable:!0,get:function(){return this}})},Uo=w,Ko=ir,Qo=function(t,e,n){if(!(t instanceof e))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation");return t},Xo=ct,Yo=function(t,e,n){var r,o,i,a,c,u,f,s=n&&n.that,l=!(!n||!n.AS_ENTRIES),p=!(!n||!n.IS_ITERATOR),h=!(!n||!n.INTERRUPTED),v=br(e,s,1+l+h),d=function(t){return r&&jr(r),new xr(!0,t)},y=function(t){return l?(yr(t),h?v(t[0],t[1],d):v(t[0],t[1])):h?v(t,d):v(t)};if(p)r=t;else{if("function"!=typeof(o=wr(t)))throw TypeError("Target is not iterable");if(gr(o)){for(i=0,a=mr(t.length);a>i;i++)if((c=y(t[i]))&&c instanceof xr)return c;return new xr(!1)}r=o.call(t)}for(u=r.next;!(f=u.call(r)).done;){try{c=y(f.value)}catch(t){throw jr(r),t}if("object"==typeof c&&c&&c instanceof xr)return c}return new xr(!1)},Bo=function(t,e){if(!e&&!Er)return!1;var n=!1;try{var r={};r[Or]=function(){return{next:function(){return{done:n=!0}}}},t(r)}catch(t){}return n},Vo=function(t,e){var n,r=Lr(t).constructor;return void 0===r||null==(n=Lr(r)[Ar])?e:Mr(n)},Zo=fo.set,ti=Eo,ei=function(t,e){if(Ao(t),Io(e)&&e.constructor===t)return e;var n=Ro.f(t);return(0,n.resolve)(e),n.promise},ni=function(t,e){var n=Co.console;n&&n.error&&(1===arguments.length?n.error(t):n.error(t,e))},ri=So,oi=function(t){try{return{error:!1,value:t()}}catch(t){return{error:!0,value:t}}},ii=Ft,ai=Ce,ci=No,ui=Cr,fi=bn,si=In("species"),li="Promise",pi=ii.get,hi=ii.set,vi=ii.getterFor(li),di=$o&&$o.prototype,yi=$o,gi=di,mi=Jo.TypeError,bi=Jo.document,wi=Jo.process,ji=ri.f,xi=ji,Oi=!!(bi&&bi.createEvent&&Jo.dispatchEvent),Ei="function"==typeof PromiseRejectionEvent,Si=!1,Ti=ai(li,(function(){var t=Xo(yi)!==String(yi);if(!t&&66===fi)return!0;if(fi>=51&&/native code/.test(yi))return!1;var e=new yi((function(t){t(1)})),n=function(t){t((function(){}),(function(){}))};return(e.constructor={})[si]=n,!(Si=e.then((function(){}))instanceof n)||!t&&ci&&!Ei})),Pi=Ti||!Bo((function(t){yi.all(t).catch((function(){}))})),_i=function(t){var e;return!(!Uo(t)||"function"!=typeof(e=t.then))&&e},ki=function(t,e){if(!t.notified){t.notified=!0;var n=t.reactions;ti((function(){for(var r=t.value,o=1==t.state,i=0;n.length>i;){var a,c,u,f=n[i++],s=o?f.ok:f.fail,l=f.resolve,p=f.reject,h=f.domain;try{s?(o||(2===t.rejection&&Ii(t),t.rejection=1),!0===s?a=r:(h&&h.enter(),a=s(r),h&&(h.exit(),u=!0)),a===f.promise?p(mi("Promise-chain cycle")):(c=_i(a))?c.call(a,l,p):l(a)):p(r)}catch(t){h&&!u&&h.exit(),p(t)}}t.reactions=[],t.notified=!1,e&&!t.rejection&&Mi(t)}))}},Li=function(t,e,n){var r,o;Oi?((r=bi.createEvent("Event")).promise=e,r.reason=n,r.initEvent(t,!1,!0),Jo.dispatchEvent(r)):r={promise:e,reason:n},!Ei&&(o=Jo["on"+t])?o(r):"unhandledrejection"===t&&ni("Unhandled promise rejection",n)},Mi=function(t){Zo.call(Jo,(function(){var e,n=t.facade,r=t.value;if(Ai(t)&&(e=oi((function(){ui?wi.emit("unhandledRejection",r,n):Li("unhandledrejection",n,r)})),t.rejection=ui||Ai(t)?2:1,e.error))throw e.value}))},Ai=function(t){return 1!==t.rejection&&!t.parent},Ii=function(t){Zo.call(Jo,(function(){var e=t.facade;ui?wi.emit("rejectionHandled",e):Li("rejectionhandled",e,t.value)}))},Ri=function(t,e,n){return function(r){t(e,r,n)}},Ci=function(t,e,n){t.done||(t.done=!0,n&&(t=n),t.value=e,t.state=2,ki(t,!0))},Ni=function(t,e,n){if(!t.done){t.done=!0,n&&(t=n);try{if(t.facade===e)throw mi("Promise can't be resolved itself");var r=_i(e);r?ti((function(){var n={done:!1};try{r.call(e,Ri(Ni,n,t),Ri(Ci,n,t))}catch(e){Ci(n,e,t)}})):(t.value=e,t.state=1,ki(t,!1))}catch(e){Ci({done:!1},e,t)}}};if(Ti&&(gi=(yi=function(t){Qo(this,yi,li),Ko(t),_o.call(this);var e=pi(this);try{t(Ri(Ni,e),Ri(Ci,e))}catch(t){Ci(e,t)}}).prototype,(_o=function(t){hi(this,{type:li,done:!1,notified:!1,parent:!1,reactions:[],rejection:!1,state:0,value:void 0})}).prototype=Ho(gi,{then:function(t,e){var n=vi(this),r=ji(Vo(this,yi));return r.ok="function"!=typeof t||t,r.fail="function"==typeof e&&e,r.domain=ui?wi.domain:void 0,n.parent=!0,n.reactions.push(r),0!=n.state&&ki(n,!1),r.promise},catch:function(t){return this.then(void 0,t)}}),ko=function(){var t=new _o,e=pi(t);this.promise=t,this.resolve=Ri(Ni,e),this.reject=Ri(Ci,e)},ri.f=ji=function(t){return t===yi||t===Lo?new ko(t):xi(t)},"function"==typeof $o&&di!==Object.prototype)){Mo=di.then,Si||(Go(di,"then",(function(t,e){var n=this;return new yi((function(t,e){Mo.call(n,t,e)})).then(t,e)}),{unsafe:!0}),Go(di,"catch",gi.catch,{unsafe:!0}));try{delete di.constructor}catch(t){}zo&&zo(di,gi)}Fo({global:!0,wrap:!0,forced:Ti},{Promise:yi}),Wo(yi,li,!1),qo(li),Lo=Do(li),Fo({target:li,stat:!0,forced:Ti},{reject:function(t){var e=ji(this);return e.reject.call(void 0,t),e.promise}}),Fo({target:li,stat:!0,forced:Ti},{resolve:function(t){return ei(this,t)}}),Fo({target:li,stat:!0,forced:Pi},{all:function(t){var e=this,n=ji(e),r=n.resolve,o=n.reject,i=oi((function(){var n=Ko(e.resolve),i=[],a=0,c=1;Yo(t,(function(t){var u=a++,f=!1;i.push(void 0),c++,n.call(e,t).then((function(t){f||(f=!0,i[u]=t,--c||r(i))}),o)})),--c||r(i)}));return i.error&&o(i.value),n.promise},race:function(t){var e=this,n=ji(e),r=n.reject,o=oi((function(){var o=Ko(e.resolve);Yo(t,(function(t){o.call(e,t).then(n.resolve,r)}))}));return o.error&&r(o.value),n.promise}});var Fi,Ji=H,Di=W,$i=Ue,Gi=i?Object.defineProperties:function(t,e){Di(t);for(var n,r=$i(e),o=r.length,i=0;o>i;)Ji.f(t,n=r[i++],e[n]);return t},Hi=W,zi=Gi,Wi=ye,qi=Ot,Ui=Ir,Ki=M,Qi=xt("IE_PROTO"),Xi=function(){},Yi=function(t){return" + + \ No newline at end of file diff --git a/2311/site_libs/revealjs/plugin/pdf-export/pdfexport.js b/2311/site_libs/revealjs/plugin/pdf-export/pdfexport.js new file mode 100644 index 00000000..bf9104c8 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/pdf-export/pdfexport.js @@ -0,0 +1,111 @@ +var PdfExport = ( function( _Reveal ){ + + var Reveal = _Reveal; + var setStylesheet = null; + var installAltKeyBindings = null; + + function getRevealJsPath(){ + var regex = /\b[^/]+\/reveal.css$/i; + var script = Array.from( document.querySelectorAll( 'link' ) ).find( function( e ){ + return e.attributes.href && e.attributes.href.value.search( regex ) >= 0; + }); + if( !script ){ + console.error( 'reveal.css could not be found in included elements. Did you rename this file?' ); + return ''; + } + return script.attributes.href.value.replace( regex, '' ); + } + + function setStylesheet3( pdfExport ){ + var link = document.querySelector( '#print' ); + if( !link ){ + link = document.createElement( 'link' ); + link.rel = 'stylesheet'; + link.id = 'print'; + document.querySelector( 'head' ).appendChild( link ); + } + var style = 'paper'; + if( pdfExport ){ + style = 'pdf'; + } + link.href = getRevealJsPath() + 'css/print/' + style + '.css'; + } + + function setStylesheet4( pdfExport ){ + } + + function installAltKeyBindings3(){ + } + + function installAltKeyBindings4(){ + if( isPrintingPDF() ){ + var config = Reveal.getConfig(); + var shortcut = config.pdfExportShortcut || 'E'; + window.addEventListener( 'keydown', function( e ){ + if( e.target.nodeName.toUpperCase() == 'BODY' + && ( e.key.toUpperCase() == shortcut.toUpperCase() || e.keyCode == shortcut.toUpperCase().charCodeAt( 0 ) ) ){ + e.preventDefault(); + togglePdfExport(); + return false; + } + }, true ); + } + } + + function isPrintingPDF(){ + return ( /print-pdf/gi ).test( window.location.search ); + } + + function togglePdfExport(){ + var url_doc = new URL( document.URL ); + var query_doc = new URLSearchParams( url_doc.searchParams ); + if( isPrintingPDF() ){ + query_doc.delete( 'print-pdf' ); + }else{ + query_doc.set( 'print-pdf', '' ); + } + url_doc.search = ( query_doc.toString() ? '?' + query_doc.toString() : '' ); + window.location.href = url_doc.toString(); + } + + function installKeyBindings(){ + var config = Reveal.getConfig(); + var shortcut = config.pdfExportShortcut || 'E'; + Reveal.addKeyBinding({ + keyCode: shortcut.toUpperCase().charCodeAt( 0 ), + key: shortcut.toUpperCase(), + description: 'PDF export mode' + }, togglePdfExport ); + installAltKeyBindings(); + } + + function install(){ + installKeyBindings(); + setStylesheet( isPrintingPDF() ); + } + + var Plugin = { + } + + if( Reveal && Reveal.VERSION && Reveal.VERSION.length && Reveal.VERSION[ 0 ] == '3' ){ + // reveal 3.x + setStylesheet = setStylesheet3; + installAltKeyBindings = installAltKeyBindings3; + install(); + }else{ + // must be reveal 4.x + setStylesheet = setStylesheet4; + installAltKeyBindings = installAltKeyBindings4; + Plugin.id = 'pdf-export'; + Plugin.init = function( _Reveal ){ + Reveal = _Reveal; + install(); + }; + Plugin.togglePdfExport = function () { + togglePdfExport(); + }; + } + + return Plugin; + +})( Reveal ); diff --git a/2311/site_libs/revealjs/plugin/pdf-export/plugin.yml b/2311/site_libs/revealjs/plugin/pdf-export/plugin.yml new file mode 100644 index 00000000..f6db9d03 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/pdf-export/plugin.yml @@ -0,0 +1,2 @@ +name: PdfExport +script: pdfexport.js diff --git a/2311/site_libs/revealjs/plugin/quarto-line-highlight/line-highlight.css b/2311/site_libs/revealjs/plugin/quarto-line-highlight/line-highlight.css new file mode 100644 index 00000000..e8410fe9 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/quarto-line-highlight/line-highlight.css @@ -0,0 +1,31 @@ +.reveal + div.sourceCode + pre + code.has-line-highlights + > span:not(.highlight-line) { + opacity: 0.4; +} + +.reveal pre.numberSource { + padding-left: 0; +} + +.reveal pre.numberSource code > span { + left: -2.1em; +} + +pre.numberSource code > span > a:first-child::before { + left: -0.7em; +} + +.reveal pre > code:not(:first-child).fragment { + position: absolute; + top: 0; + left: 0; + width: 100%; + box-sizing: border-box; +} + +.reveal div.sourceCode pre code { + min-height: 100%; +} diff --git a/2311/site_libs/revealjs/plugin/quarto-line-highlight/line-highlight.js b/2311/site_libs/revealjs/plugin/quarto-line-highlight/line-highlight.js new file mode 100644 index 00000000..5bffdc77 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/quarto-line-highlight/line-highlight.js @@ -0,0 +1,351 @@ +window.QuartoLineHighlight = function () { + function isPrintView() { + return /print-pdf/gi.test(window.location.search); + } + + const delimiters = { + step: "|", + line: ",", + lineRange: "-", + }; + + const regex = new RegExp( + "^[\\d" + Object.values(delimiters).join("") + "]+$" + ); + + function handleLinesSelector(deck, attr) { + // if we are in printview with pdfSeparateFragments: false + // then we'll also want to supress + if (regex.test(attr)) { + if (isPrintView() && deck.getConfig().pdfSeparateFragments !== true) { + return false; + } else { + return true; + } + } else { + return false; + } + } + + const kCodeLineNumbersAttr = "data-code-line-numbers"; + const kFragmentIndex = "data-fragment-index"; + + function initQuartoLineHighlight(deck) { + const divSourceCode = deck + .getRevealElement() + .querySelectorAll("div.sourceCode"); + // Process each div created by Pandoc highlighting - numbered line are already included. + divSourceCode.forEach((el) => { + if (el.hasAttribute(kCodeLineNumbersAttr)) { + const codeLineAttr = el.getAttribute(kCodeLineNumbersAttr); + el.removeAttribute("data-code-line-numbers"); + if (handleLinesSelector(deck, codeLineAttr)) { + // Only process if attr is a string to select lines to highlights + // e.g "1|3,6|8-11" + const codeBlock = el.querySelectorAll("pre code"); + codeBlock.forEach((code) => { + // move attributes on code block + code.setAttribute(kCodeLineNumbersAttr, codeLineAttr); + + const scrollState = { currentBlock: code }; + + // Check if there are steps and duplicate code block accordingly + const highlightSteps = splitLineNumbers(codeLineAttr); + if (highlightSteps.length > 1) { + // If the original code block has a fragment-index, + // each clone should follow in an incremental sequence + let fragmentIndex = parseInt( + code.getAttribute(kFragmentIndex), + 10 + ); + fragmentIndex = + typeof fragmentIndex !== "number" || isNaN(fragmentIndex) + ? null + : fragmentIndex; + + let stepN = 1; + highlightSteps.slice(1).forEach( + // Generate fragments for all steps except the original block + (step) => { + var fragmentBlock = code.cloneNode(true); + fragmentBlock.setAttribute( + "data-code-line-numbers", + joinLineNumbers([step]) + ); + fragmentBlock.classList.add("fragment"); + + // Pandoc sets id on spans we need to keep unique + fragmentBlock + .querySelectorAll(":scope > span") + .forEach((span) => { + if (span.hasAttribute("id")) { + span.setAttribute( + "id", + span.getAttribute("id").concat("-" + stepN) + ); + } + }); + stepN = ++stepN; + + // Add duplicated element after existing one + code.parentNode.appendChild(fragmentBlock); + + // Each new element is highlighted based on the new attributes value + highlightCodeBlock(fragmentBlock); + + if (typeof fragmentIndex === "number") { + fragmentBlock.setAttribute(kFragmentIndex, fragmentIndex); + fragmentIndex += 1; + } else { + fragmentBlock.removeAttribute(kFragmentIndex); + } + + // Scroll highlights into view as we step through them + fragmentBlock.addEventListener( + "visible", + scrollHighlightedLineIntoView.bind( + this, + fragmentBlock, + scrollState + ) + ); + fragmentBlock.addEventListener( + "hidden", + scrollHighlightedLineIntoView.bind( + this, + fragmentBlock.previousSibling, + scrollState + ) + ); + } + ); + code.removeAttribute(kFragmentIndex); + code.setAttribute( + kCodeLineNumbersAttr, + joinLineNumbers([highlightSteps[0]]) + ); + } + + // Scroll the first highlight into view when the slide becomes visible. + const slide = + typeof code.closest === "function" + ? code.closest("section:not(.stack)") + : null; + if (slide) { + const scrollFirstHighlightIntoView = function () { + scrollHighlightedLineIntoView(code, scrollState, true); + slide.removeEventListener( + "visible", + scrollFirstHighlightIntoView + ); + }; + slide.addEventListener("visible", scrollFirstHighlightIntoView); + } + + highlightCodeBlock(code); + }); + } + } + }); + } + + function highlightCodeBlock(codeBlock) { + const highlightSteps = splitLineNumbers( + codeBlock.getAttribute(kCodeLineNumbersAttr) + ); + + if (highlightSteps.length) { + // If we have at least one step, we generate fragments + highlightSteps[0].forEach((highlight) => { + // Add expected class on
     for reveal CSS
    +        codeBlock.parentNode.classList.add("code-wrapper");
    +
    +        // Select lines to highlight
    +        spanToHighlight = [];
    +        if (typeof highlight.last === "number") {
    +          spanToHighlight = [].slice.call(
    +            codeBlock.querySelectorAll(
    +              ":scope > span:nth-child(n+" +
    +                highlight.first +
    +                "):nth-child(-n+" +
    +                highlight.last +
    +                ")"
    +            )
    +          );
    +        } else if (typeof highlight.first === "number") {
    +          spanToHighlight = [].slice.call(
    +            codeBlock.querySelectorAll(
    +              ":scope > span:nth-child(" + highlight.first + ")"
    +            )
    +          );
    +        }
    +        if (spanToHighlight.length) {
    +          // Add a class on  and  to select line to highlight
    +          spanToHighlight.forEach((span) =>
    +            span.classList.add("highlight-line")
    +          );
    +          codeBlock.classList.add("has-line-highlights");
    +        }
    +      });
    +    }
    +  }
    +
    +  /**
    +   * Animates scrolling to the first highlighted line
    +   * in the given code block.
    +   */
    +  function scrollHighlightedLineIntoView(block, scrollState, skipAnimation) {
    +    window.cancelAnimationFrame(scrollState.animationFrameID);
    +
    +    // Match the scroll position of the currently visible
    +    // code block
    +    if (scrollState.currentBlock) {
    +      block.scrollTop = scrollState.currentBlock.scrollTop;
    +    }
    +
    +    // Remember the current code block so that we can match
    +    // its scroll position when showing/hiding fragments
    +    scrollState.currentBlock = block;
    +
    +    const highlightBounds = getHighlightedLineBounds(block);
    +    let viewportHeight = block.offsetHeight;
    +
    +    // Subtract padding from the viewport height
    +    const blockStyles = window.getComputedStyle(block);
    +    viewportHeight -=
    +      parseInt(blockStyles.paddingTop) + parseInt(blockStyles.paddingBottom);
    +
    +    // Scroll position which centers all highlights
    +    const startTop = block.scrollTop;
    +    let targetTop =
    +      highlightBounds.top +
    +      (Math.min(highlightBounds.bottom - highlightBounds.top, viewportHeight) -
    +        viewportHeight) /
    +        2;
    +
    +    // Make sure the scroll target is within bounds
    +    targetTop = Math.max(
    +      Math.min(targetTop, block.scrollHeight - viewportHeight),
    +      0
    +    );
    +
    +    if (skipAnimation === true || startTop === targetTop) {
    +      block.scrollTop = targetTop;
    +    } else {
    +      // Don't attempt to scroll if there is no overflow
    +      if (block.scrollHeight <= viewportHeight) return;
    +
    +      let time = 0;
    +
    +      const animate = function () {
    +        time = Math.min(time + 0.02, 1);
    +
    +        // Update our eased scroll position
    +        block.scrollTop =
    +          startTop + (targetTop - startTop) * easeInOutQuart(time);
    +
    +        // Keep animating unless we've reached the end
    +        if (time < 1) {
    +          scrollState.animationFrameID = requestAnimationFrame(animate);
    +        }
    +      };
    +
    +      animate();
    +    }
    +  }
    +
    +  function getHighlightedLineBounds(block) {
    +    const highlightedLines = block.querySelectorAll(".highlight-line");
    +    if (highlightedLines.length === 0) {
    +      return { top: 0, bottom: 0 };
    +    } else {
    +      const firstHighlight = highlightedLines[0];
    +      const lastHighlight = highlightedLines[highlightedLines.length - 1];
    +
    +      return {
    +        top: firstHighlight.offsetTop,
    +        bottom: lastHighlight.offsetTop + lastHighlight.offsetHeight,
    +      };
    +    }
    +  }
    +
    +  /**
    +   * The easing function used when scrolling.
    +   */
    +  function easeInOutQuart(t) {
    +    // easeInOutQuart
    +    return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
    +  }
    +
    +  function splitLineNumbers(lineNumbersAttr) {
    +    // remove space
    +    lineNumbersAttr = lineNumbersAttr.replace("/s/g", "");
    +    // seperate steps (for fragment)
    +    lineNumbersAttr = lineNumbersAttr.split(delimiters.step);
    +
    +    // for each step, calculate first and last line, if any
    +    return lineNumbersAttr.map((highlights) => {
    +      // detect lines
    +      const lines = highlights.split(delimiters.line);
    +      return lines.map((range) => {
    +        if (/^[\d-]+$/.test(range)) {
    +          range = range.split(delimiters.lineRange);
    +          const firstLine = parseInt(range[0], 10);
    +          const lastLine = range[1] ? parseInt(range[1], 10) : undefined;
    +          return {
    +            first: firstLine,
    +            last: lastLine,
    +          };
    +        } else {
    +          return {};
    +        }
    +      });
    +    });
    +  }
    +
    +  function joinLineNumbers(splittedLineNumbers) {
    +    return splittedLineNumbers
    +      .map(function (highlights) {
    +        return highlights
    +          .map(function (highlight) {
    +            // Line range
    +            if (typeof highlight.last === "number") {
    +              return highlight.first + delimiters.lineRange + highlight.last;
    +            }
    +            // Single line
    +            else if (typeof highlight.first === "number") {
    +              return highlight.first;
    +            }
    +            // All lines
    +            else {
    +              return "";
    +            }
    +          })
    +          .join(delimiters.line);
    +      })
    +      .join(delimiters.step);
    +  }
    +
    +  return {
    +    id: "quarto-line-highlight",
    +    init: function (deck) {
    +      initQuartoLineHighlight(deck);
    +
    +      // If we're printing to PDF, scroll the code highlights of
    +      // all blocks in the deck into view at once
    +      deck.on("pdf-ready", function () {
    +        [].slice
    +          .call(
    +            deck
    +              .getRevealElement()
    +              .querySelectorAll(
    +                "pre code[data-code-line-numbers].current-fragment"
    +              )
    +          )
    +          .forEach(function (block) {
    +            scrollHighlightedLineIntoView(block, {}, true);
    +          });
    +      });
    +    },
    +  };
    +};
    diff --git a/2311/site_libs/revealjs/plugin/quarto-line-highlight/plugin.yml b/2311/site_libs/revealjs/plugin/quarto-line-highlight/plugin.yml
    new file mode 100644
    index 00000000..ca206862
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/quarto-line-highlight/plugin.yml
    @@ -0,0 +1,4 @@
    +# adapted from https://github.com/hakimel/reveal.js/tree/master/plugin/highlight
    +name: QuartoLineHighlight
    +script: line-highlight.js
    +stylesheet: line-highlight.css
    diff --git a/2311/site_libs/revealjs/plugin/quarto-support/footer.css b/2311/site_libs/revealjs/plugin/quarto-support/footer.css
    new file mode 100644
    index 00000000..390d5b38
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/quarto-support/footer.css
    @@ -0,0 +1,110 @@
    +.reveal .slide-logo {
    +  display: block;
    +  position: fixed;
    +  bottom: 0;
    +  right: 12px;
    +  max-height: 2.2rem;
    +  height: 100%;
    +  width: auto;
    +  z-index: 2;
    +}
    +
    +.reveal .footer {
    +  display: block;
    +  position: fixed;
    +  bottom: 18px;
    +  width: 100%;
    +  margin: 0 auto;
    +  text-align: center;
    +  font-size: 18px;
    +  z-index: 2;
    +}
    +
    +.reveal .footer > * {
    +  margin-top: 0;
    +  margin-bottom: 0;
    +}
    +
    +.reveal .slide .footer {
    +  display: none;
    +}
    +
    +.reveal .slide-number {
    +  bottom: 10px;
    +  right: 10px;
    +  font-size: 16px;
    +  background-color: transparent;
    +}
    +
    +.reveal.has-logo .slide-number {
    +  bottom: initial;
    +  top: 8px;
    +  right: 8px;
    +}
    +
    +.reveal .slide-number .slide-number-delimiter {
    +  margin: 0;
    +}
    +
    +.reveal .slide-menu-button {
    +  left: 8px;
    +  bottom: 8px;
    +}
    +
    +.reveal .slide-chalkboard-buttons {
    +  position: fixed;
    +  left: 12px;
    +  bottom: 8px;
    +  z-index: 30;
    +  font-size: 24px;
    +}
    +
    +.reveal .slide-chalkboard-buttons.slide-menu-offset {
    +  left: 54px;
    +}
    +
    +.reveal .slide-chalkboard-buttons > span {
    +  margin-right: 14px;
    +  cursor: pointer;
    +}
    +
    +@media screen and (max-width: 800px) {
    +  .reveal .slide-logo {
    +    max-height: 1.1rem;
    +    bottom: -2px;
    +    right: 10px;
    +  }
    +  .reveal .footer {
    +    font-size: 14px;
    +    bottom: 12px;
    +  }
    +  .reveal .slide-number {
    +    font-size: 12px;
    +    bottom: 7px;
    +  }
    +  .reveal .slide-menu-button .fas::before {
    +    height: 1.3rem;
    +    width: 1.3rem;
    +    vertical-align: -0.125em;
    +    background-size: 1.3rem 1.3rem;
    +  }
    +
    +  .reveal .slide-chalkboard-buttons .fas::before {
    +    height: 0.95rem;
    +    width: 0.95rem;
    +    background-size: 0.95rem 0.95rem;
    +    vertical-align: -0em;
    +  }
    +
    +  .reveal .slide-chalkboard-buttons.slide-menu-offset {
    +    left: 36px;
    +  }
    +  .reveal .slide-chalkboard-buttons > span {
    +    margin-right: 9px;
    +  }
    +}
    +
    +html.print-pdf .reveal .slide-menu-button,
    +html.print-pdf .reveal .slide-chalkboard-buttons {
    +  display: none;
    +}
    diff --git a/2311/site_libs/revealjs/plugin/quarto-support/plugin.yml b/2311/site_libs/revealjs/plugin/quarto-support/plugin.yml
    new file mode 100644
    index 00000000..546956e9
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/quarto-support/plugin.yml
    @@ -0,0 +1,5 @@
    +name: QuartoSupport
    +script: support.js
    +stylesheet: footer.css
    +config:
    +  smaller: false
    diff --git a/2311/site_libs/revealjs/plugin/quarto-support/support.js b/2311/site_libs/revealjs/plugin/quarto-support/support.js
    new file mode 100644
    index 00000000..9adc9213
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/quarto-support/support.js
    @@ -0,0 +1,290 @@
    +// catch all plugin for various quarto features
    +window.QuartoSupport = function () {
    +  function isPrintView() {
    +    return /print-pdf/gi.test(window.location.search);
    +  }
    +
    +  // implement controlsAudo
    +  function controlsAuto(deck) {
    +    const config = deck.getConfig();
    +    if (config.controlsAuto === true) {
    +      const iframe = window.location !== window.parent.location;
    +      const localhost =
    +        window.location.hostname === "localhost" ||
    +        window.location.hostname === "127.0.0.1";
    +      deck.configure({
    +        controls:
    +          (iframe && !localhost) ||
    +          (deck.hasVerticalSlides() && config.navigationMode !== "linear"),
    +      });
    +    }
    +  }
    +
    +  // helper to provide event handlers for all links in a container
    +  function handleLinkClickEvents(deck, container) {
    +    Array.from(container.querySelectorAll("a")).forEach((el) => {
    +      const url = el.getAttribute("href");
    +      if (/^(http|www)/gi.test(url)) {
    +        el.addEventListener(
    +          "click",
    +          (ev) => {
    +            const fullscreen = !!window.document.fullscreen;
    +            const dataPreviewLink = el.getAttribute("data-preview-link");
    +
    +            // if there is a local specifcation then use that
    +            if (dataPreviewLink) {
    +              if (
    +                dataPreviewLink === "true" ||
    +                (dataPreviewLink === "auto" && fullscreen)
    +              ) {
    +                ev.preventDefault();
    +                deck.showPreview(url);
    +                return false;
    +              }
    +            } else {
    +              const previewLinks = !!deck.getConfig().previewLinks;
    +              const previewLinksAuto =
    +                deck.getConfig().previewLinksAuto === true;
    +              if (previewLinks == true || (previewLinksAuto && fullscreen)) {
    +                ev.preventDefault();
    +                deck.showPreview(url);
    +                return false;
    +              }
    +            }
    +
    +            // if the deck is in an iframe we want to open it externally
    +            // (don't do this when in vscode though as it has its own
    +            // handler for opening links externally that will be play)
    +            const iframe = window.location !== window.parent.location;
    +            if (
    +              iframe &&
    +              !window.location.search.includes("quartoPreviewReqId=")
    +            ) {
    +              ev.preventDefault();
    +              ev.stopImmediatePropagation();
    +              window.open(url, "_blank");
    +              return false;
    +            }
    +
    +            // if the user has set data-preview-link to "auto" we need to handle the event
    +            // (because reveal will interpret "auto" as true)
    +            if (dataPreviewLink === "auto") {
    +              ev.preventDefault();
    +              ev.stopImmediatePropagation();
    +              const target =
    +                el.getAttribute("target") ||
    +                (ev.ctrlKey || ev.metaKey ? "_blank" : "");
    +              if (target) {
    +                window.open(url, target);
    +              } else {
    +                window.location.href = url;
    +              }
    +              return false;
    +            }
    +          },
    +          false
    +        );
    +      }
    +    });
    +  }
    +
    +  // implement previewLinksAuto
    +  function previewLinksAuto(deck) {
    +    handleLinkClickEvents(deck, deck.getRevealElement());
    +  }
    +
    +  // apply styles
    +  function applyGlobalStyles(deck) {
    +    if (deck.getConfig()["smaller"] === true) {
    +      const revealParent = deck.getRevealElement();
    +      revealParent.classList.add("smaller");
    +    }
    +  }
    +
    +  // add logo image
    +  function addLogoImage(deck) {
    +    const revealParent = deck.getRevealElement();
    +    const logoImg = document.querySelector(".slide-logo");
    +    if (logoImg) {
    +      revealParent.appendChild(logoImg);
    +      revealParent.classList.add("has-logo");
    +    }
    +  }
    +
    +  // add footer text
    +  function addFooter(deck) {
    +    const revealParent = deck.getRevealElement();
    +    const defaultFooterDiv = document.querySelector(".footer-default");
    +    if (defaultFooterDiv) {
    +      revealParent.appendChild(defaultFooterDiv);
    +      handleLinkClickEvents(deck, defaultFooterDiv);
    +      if (!isPrintView()) {
    +        deck.on("slidechanged", function (ev) {
    +          const prevSlideFooter = document.querySelector(
    +            ".reveal > .footer:not(.footer-default)"
    +          );
    +          if (prevSlideFooter) {
    +            prevSlideFooter.remove();
    +          }
    +          const currentSlideFooter = ev.currentSlide.querySelector(".footer");
    +          if (currentSlideFooter) {
    +            defaultFooterDiv.style.display = "none";
    +            const slideFooter = currentSlideFooter.cloneNode(true);
    +            handleLinkClickEvents(deck, slideFooter);
    +            deck.getRevealElement().appendChild(slideFooter);
    +          } else {
    +            defaultFooterDiv.style.display = "block";
    +          }
    +        });
    +      }
    +    }
    +  }
    +
    +  // add chalkboard buttons
    +  function addChalkboardButtons(deck) {
    +    const chalkboard = deck.getPlugin("RevealChalkboard");
    +    if (chalkboard && !isPrintView()) {
    +      const revealParent = deck.getRevealElement();
    +      const chalkboardDiv = document.createElement("div");
    +      chalkboardDiv.classList.add("slide-chalkboard-buttons");
    +      if (document.querySelector(".slide-menu-button")) {
    +        chalkboardDiv.classList.add("slide-menu-offset");
    +      }
    +      // add buttons
    +      const buttons = [
    +        {
    +          icon: "easel2",
    +          title: "Toggle Chalkboard (b)",
    +          onclick: chalkboard.toggleChalkboard,
    +        },
    +        {
    +          icon: "brush",
    +          title: "Toggle Notes Canvas (c)",
    +          onclick: chalkboard.toggleNotesCanvas,
    +        },
    +      ];
    +      buttons.forEach(function (button) {
    +        const span = document.createElement("span");
    +        span.title = button.title;
    +        const icon = document.createElement("i");
    +        icon.classList.add("fas");
    +        icon.classList.add("fa-" + button.icon);
    +        span.appendChild(icon);
    +        span.onclick = function (event) {
    +          event.preventDefault();
    +          button.onclick();
    +        };
    +        chalkboardDiv.appendChild(span);
    +      });
    +      revealParent.appendChild(chalkboardDiv);
    +      const config = deck.getConfig();
    +      if (!config.chalkboard.buttons) {
    +        chalkboardDiv.classList.add("hidden");
    +      }
    +
    +      // show and hide chalkboard buttons on slidechange
    +      deck.on("slidechanged", function (ev) {
    +        const config = deck.getConfig();
    +        let buttons = !!config.chalkboard.buttons;
    +        const slideButtons = ev.currentSlide.getAttribute(
    +          "data-chalkboard-buttons"
    +        );
    +        if (slideButtons) {
    +          if (slideButtons === "true" || slideButtons === "1") {
    +            buttons = true;
    +          } else if (slideButtons === "false" || slideButtons === "0") {
    +            buttons = false;
    +          }
    +        }
    +        if (buttons) {
    +          chalkboardDiv.classList.remove("hidden");
    +        } else {
    +          chalkboardDiv.classList.add("hidden");
    +        }
    +      });
    +    }
    +  }
    +
    +  function handleTabbyClicks() {
    +    const tabs = document.querySelectorAll(".panel-tabset-tabby > li > a");
    +    for (let i = 0; i < tabs.length; i++) {
    +      const tab = tabs[i];
    +      tab.onclick = function (ev) {
    +        ev.preventDefault();
    +        ev.stopPropagation();
    +        return false;
    +      };
    +    }
    +  }
    +
    +  function fixupForPrint(deck) {
    +    if (isPrintView()) {
    +      const slides = deck.getSlides();
    +      slides.forEach(function (slide) {
    +        slide.removeAttribute("data-auto-animate");
    +      });
    +      window.document.querySelectorAll(".hljs").forEach(function (el) {
    +        el.classList.remove("hljs");
    +      });
    +      window.document.querySelectorAll(".hljs-ln-code").forEach(function (el) {
    +        el.classList.remove("hljs-ln-code");
    +      });
    +    }
    +  }
    +
    +  function handleSlideChanges(deck) {
    +    // dispatch for htmlwidgets
    +    const fireSlideEnter = () => {
    +      const event = window.document.createEvent("Event");
    +      event.initEvent("slideenter", true, true);
    +      window.document.dispatchEvent(event);
    +    };
    +
    +    const fireSlideChanged = (previousSlide, currentSlide) => {
    +      fireSlideEnter();
    +
    +      // dispatch for shiny
    +      if (window.jQuery) {
    +        if (previousSlide) {
    +          window.jQuery(previousSlide).trigger("hidden");
    +        }
    +        if (currentSlide) {
    +          window.jQuery(currentSlide).trigger("shown");
    +        }
    +      }
    +    };
    +
    +    // fire slideEnter for tabby tab activations (for htmlwidget resize behavior)
    +    document.addEventListener("tabby", fireSlideEnter, false);
    +
    +    deck.on("slidechanged", function (event) {
    +      fireSlideChanged(event.previousSlide, event.currentSlide);
    +    });
    +  }
    +
    +  function workaroundMermaidDistance(deck) {
    +    if (window.document.querySelector("pre.mermaid-js")) {
    +      const slideCount = deck.getTotalSlides();
    +      deck.configure({
    +        mobileViewDistance: slideCount,
    +        viewDistance: slideCount,
    +      });
    +    }
    +  }
    +
    +  return {
    +    id: "quarto-support",
    +    init: function (deck) {
    +      controlsAuto(deck);
    +      previewLinksAuto(deck);
    +      fixupForPrint(deck);
    +      applyGlobalStyles(deck);
    +      addLogoImage(deck);
    +      addFooter(deck);
    +      addChalkboardButtons(deck);
    +      handleTabbyClicks();
    +      handleSlideChanges(deck);
    +      workaroundMermaidDistance(deck);
    +    },
    +  };
    +};
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/README.md b/2311/site_libs/revealjs/plugin/reveal-chalkboard/README.md
    new file mode 100644
    index 00000000..7391a00b
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/README.md
    @@ -0,0 +1,160 @@
    +# Chalkboard
    +
    +With this plugin you can add a chalkboard to reveal.js. The plugin provides two possibilities to include handwritten notes to your presentation:
    +
    +- you can make notes directly on the slides, e.g. to comment on certain aspects,
    +- you can open a chalkboard or whiteboard on which you can make notes.
    +
    +The main use case in mind when implementing the plugin is classroom usage in which you may want to explain some course content and quickly need to make some notes.
    +
    +The plugin records all drawings made so that they can be play backed using the `autoSlide` feature or the `audio-slideshow` plugin.
    +
    +[Check out the live demo](https://rajgoel.github.io/reveal.js-demos/chalkboard-demo.html)
    +
    +The chalkboard effect is based on [Chalkboard](https://github.com/mmoustafa/Chalkboard) by Mohamed Moustafa.
    +
    +## Installation
    +
    +Copy the file `plugin.js` and the  `img` directory into the plugin folder of your reveal.js presentation, i.e. `plugin/chalkboard` and load the plugin as shown below.
    +
    +```html
    +
    +
    +
    +
    +```
    +
    +The following stylesheet
    +```html
    +
    +
    +```
    +has to be included to the `head` section of you HTML-file.
    +
    +
    +In order to include buttons for opening and closing the notes canvas or the chalkboard you should make sure that `font-awesome` is available. The easiest way is to include
    +```
    +
    +```
    +to the ```head``` section of you HTML-file.
    +
    +## Usage
    +
    +### Mouse or touch
    +- Click on the pen symbols at the bottom left to toggle the notes canvas or chalkboard
    +- Click on the color picker at the left to change the color (the color picker is only visible if the notes canvas or chalkboard is active)
    +- Click on the up/down arrows on the left to the switch among multiple chalkboardd (the up/down arrows are only available for the chlakboard)
    +- Click the left mouse button and drag to write on notes canvas or chalkboard
    +- Click the right mouse button and drag to wipe away previous drawings
    +- Touch and move to write on notes canvas or chalkboard
    +- Touch and hold for half a second, then move to wipe away previous drawings
    +
    +### Keyboard
    +- Press the 'BACKSPACE' key to delete all chalkboard drawings
    +- Press the 'DEL' key to clear the notes canvas or chalkboard
    +- Press the 'c' key to toggle the notes canvas
    +- Press the 'b' key to toggle the chalkboard
    +- Press the 'd' key to download drawings
    +- Press the 'x' key to cycle colors forward
    +- Press the 'y' key to cycle colors backward
    +
    +## Playback
    +
    +If the `autoSlide` feature is set or if the `audio-slideshow` plugin is used, pre-recorded chalkboard drawings can be played. The slideshow plays back the user interaction with the chalkboard in the same way as it was conducted when recording the data.
    +
    +## Multiplexing
    +
    +The plugin supports multiplexing via the [`multiplex` plugin](https://github.com/reveal/multiplex) or the [`seminar` plugin](https://github.com/rajgoel/reveal.js-plugins/tree/master/seminar).
    +
    +## PDF-Export
    +
    +If the slideshow is opened in [print mode](https://revealjs.com/pdf-export/), the chalkboard drawings in the session storage (see `storage` option - print version must be opened in the same tab or window as the original slideshow) or provided in a file (see `src` option) are included in the PDF-file. Each drawing on the chalkboard is added after the slide that was shown when opening the chalkboard. Drawings on the notes canvas are not included in the PDF-file.
    +
    +
    +## Configuration
    +
    +The plugin has several configuration options:
    +
    +- ```boardmarkerWidth```: an integer, the drawing width of the boardmarker; larger values draw thicker lines.
    +- ```chalkWidth```: an integer, the drawing width of the chalk; larger values draw thicker lines.
    +- ```chalkEffect```: a float in the range ```[0.0, 1.0]```, the intesity of the chalk effect on the chalk board. Full effect (default) ```1.0```, no effect ```0.0```.
    +- ```storage```: Optional variable name for session storage of drawings.
    +- ```src```: Optional filename for pre-recorded drawings.
    +- ```readOnly```: Configuation option allowing to prevent changes to existing drawings. If set to ```true``` no changes can be made, if set to false ```false``` changes can be made, if unset or set to ```undefined``` no changes to the drawings can be made after returning to a slide or fragment for which drawings had been recorded before. In any case the recorded drawings for a slide or fragment can be cleared by pressing the 'DEL' key (i.e. by using the ```RevealChalkboard.clear()``` function).
    +- ```transition```: Gives the duration (in milliseconds) of the transition for a slide change, so that the notes canvas is drawn after the transition is completed.
    +- ```theme```: Can be set to either ```"chalkboard"``` or ```"whiteboard"```.
    +
    +The following configuration options allow to change the appearance of the notes canvas and the chalkboard. All of these options require two values, the first gives the value for the notes canvas, the second for the chalkboard.
    +
    +- ```background```: The first value expects a (semi-)transparent color which is used to provide visual feedback that the notes canvas is enabled, the second value expects a filename to a background image for the chalkboard.
    +- ```grid```: By default whiteboard and chalkboard themes include a grid pattern on the background. This pattern can be modified by setting the color, the distance between lines, and the line width, e.g. ```{ color: 'rgb(127,127,255,0.1)', distance: 40, width: 2}```. Alternatively, the grid can be removed by setting the value to ```false```.
    +- ```eraser```: An image path and radius for the eraser.
    +- ```boardmarkers```: A list of boardmarkers with given color and cursor.
    +- ```chalks```: A list of chalks with given color and cursor.
    +- ```rememberColor```: Whether to remember the last selected color for the slide canvas or the board.
    +
    +All of the configurations are optional and the default values shown below are used if the options are not provided.
    +
    +```javascript
    +Reveal.initialize({
    +	// ...
    +    chalkboard: {
    +        boardmarkerWidth: 3,
    +        chalkWidth: 7,
    +        chalkEffect: 1.0,
    +        storage: null,
    +        src: null,
    +        readOnly: undefined,
    +        transition: 800,
    +        theme: "chalkboard",
    +        background: [ 'rgba(127,127,127,.1)' , path + 'img/blackboard.png' ],
    +        grid: { color: 'rgb(50,50,10,0.5)', distance: 80, width: 2},
    +        eraser: { src: path + 'img/sponge.png', radius: 20},
    +        boardmarkers : [
    +                { color: 'rgba(100,100,100,1)', cursor: 'url(' + path + 'img/boardmarker-black.png), auto'},
    +                { color: 'rgba(30,144,255, 1)', cursor: 'url(' + path + 'img/boardmarker-blue.png), auto'},
    +                { color: 'rgba(220,20,60,1)', cursor: 'url(' + path + 'img/boardmarker-red.png), auto'},
    +                { color: 'rgba(50,205,50,1)', cursor: 'url(' + path + 'img/boardmarker-green.png), auto'},
    +                { color: 'rgba(255,140,0,1)', cursor: 'url(' + path + 'img/boardmarker-orange.png), auto'},
    +                { color: 'rgba(150,0,20150,1)', cursor: 'url(' + path + 'img/boardmarker-purple.png), auto'},
    +                { color: 'rgba(255,220,0,1)', cursor: 'url(' + path + 'img/boardmarker-yellow.png), auto'}
    +        ],
    +        chalks: [
    +                { color: 'rgba(255,255,255,0.5)', cursor: 'url(' + path + 'img/chalk-white.png), auto'},
    +                { color: 'rgba(96, 154, 244, 0.5)', cursor: 'url(' + path + 'img/chalk-blue.png), auto'},
    +                { color: 'rgba(237, 20, 28, 0.5)', cursor: 'url(' + path + 'img/chalk-red.png), auto'},
    +                { color: 'rgba(20, 237, 28, 0.5)', cursor: 'url(' + path + 'img/chalk-green.png), auto'},
    +                { color: 'rgba(220, 133, 41, 0.5)', cursor: 'url(' + path + 'img/chalk-orange.png), auto'},
    +                { color: 'rgba(220,0,220,0.5)', cursor: 'url(' + path + 'img/chalk-purple.png), auto'},
    +                { color: 'rgba(255,220,0,0.5)', cursor: 'url(' + path + 'img/chalk-yellow.png), auto'}
    +        ]
    +    },
    +    customcontrols: {
    +  		controls: [
    +  			{ icon: '',
    +  			  title: 'Toggle chalkboard (B)',
    +  			  action: 'RevealChalkboard.toggleChalkboard();'
    +  			},
    +  			{ icon: '',
    +  			  title: 'Toggle notes canvas (C)',
    +  			  action: 'RevealChalkboard.toggleNotesCanvas();'
    +  			}
    +  		]
    +    },
    +    // ...
    +
    +});
    +```
    +
    +
    +## License
    +
    +MIT licensed
    +
    +Copyright (C) 2021 Asvin Goel
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/LICENSE.txt b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/LICENSE.txt
    new file mode 100644
    index 00000000..28c1c4bc
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/LICENSE.txt
    @@ -0,0 +1,34 @@
    +Font Awesome Free License
    +-------------------------
    +
    +Font Awesome Free is free, open source, and GPL friendly. You can use it for
    +commercial projects, open source projects, or really almost whatever you want.
    +Full Font Awesome Free license: https://fontawesome.com/license.
    +
    +# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
    +In the Font Awesome Free download, the CC BY 4.0 license applies to all icons
    +packaged as SVG and JS file types.
    +
    +# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL)
    +In the Font Awesome Free download, the SIL OLF license applies to all icons
    +packaged as web and desktop font files.
    +
    +# Code: MIT License (https://opensource.org/licenses/MIT)
    +In the Font Awesome Free download, the MIT license applies to all non-font and
    +non-icon files.
    +
    +# Attribution
    +Attribution is required by MIT, SIL OLF, and CC BY licenses. Downloaded Font
    +Awesome Free files already contain embedded comments with sufficient
    +attribution, so you shouldn't need to do anything additional when using these
    +files normally.
    +
    +We've kept attribution comments terse, so we ask that you do not actively work
    +to remove them from files, especially code. They're a great way for folks to 
    +learn about Font Awesome.
    +
    +# Brand Icons
    +All brand icons are trademarks of their respective owners. The use of these
    +trademarks does not indicate endorsement of the trademark holder by Font
    +Awesome, nor vice versa. **Please do not use brand logos for any purpose except
    +to represent the company, product, or service to which they refer.**
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/all.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/all.css
    new file mode 100644
    index 00000000..7fec2e37
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/all.css
    @@ -0,0 +1,5 @@
    +/*!
    + * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
    + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
    + */
    +.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:a 2s infinite linear}.fa-pulse{animation:a 1s infinite steps(8)}@keyframes a{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blind:before{content:"\f29d"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-open:before{content:"\f518"}.fa-bookmark:before{content:"\f02e"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-certificate:before{content:"\f0a3"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-concierge-bell:before{content:"\f562"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-credit-card:before{content:"\f09d"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-deviantart:before{content:"\f1bd"}.fa-diagnoses:before{content:"\f470"}.fa-dice:before{content:"\f522"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-gift:before{content:"\f06b"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hashtag:before{content:"\f292"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-houzz:before{content:"\f27c"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-internet-explorer:before{content:"\f26b"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mercury:before{content:"\f223"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-motorcycle:before{content:"\f21c"}.fa-mouse-pointer:before{content:"\f245"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-old-republic:before{content:"\f510"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-people-carry:before{content:"\f4ce"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poo:before{content:"\f2fe"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-r-project:before{content:"\f4f7"}.fa-random:before{content:"\f074"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-rendact:before{content:"\f3e4"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-retweet:before{content:"\f079"}.fa-ribbon:before{content:"\f4d6"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-search:before{content:"\f002"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skull:before{content:"\f54c"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowflake:before{content:"\f2dc"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toolbox:before{content:"\f552"}.fa-tooth:before{content:"\f5c9"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-train:before{content:"\f238"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-moving:before{content:"\f4df"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900}
    \ No newline at end of file
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/brands.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/brands.css
    new file mode 100644
    index 00000000..2d9e4c6c
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/brands.css
    @@ -0,0 +1,5 @@
    +/*!
    + * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
    + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
    + */
    +@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}
    \ No newline at end of file
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/fontawesome.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/fontawesome.css
    new file mode 100644
    index 00000000..68b26ef9
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/fontawesome.css
    @@ -0,0 +1,5 @@
    +/*!
    + * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
    + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
    + */
    +.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:a 2s infinite linear}.fa-pulse{animation:a 1s infinite steps(8)}@keyframes a{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blind:before{content:"\f29d"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-open:before{content:"\f518"}.fa-bookmark:before{content:"\f02e"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-certificate:before{content:"\f0a3"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-concierge-bell:before{content:"\f562"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-credit-card:before{content:"\f09d"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-deviantart:before{content:"\f1bd"}.fa-diagnoses:before{content:"\f470"}.fa-dice:before{content:"\f522"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-gift:before{content:"\f06b"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hashtag:before{content:"\f292"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-houzz:before{content:"\f27c"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-internet-explorer:before{content:"\f26b"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mercury:before{content:"\f223"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-motorcycle:before{content:"\f21c"}.fa-mouse-pointer:before{content:"\f245"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-old-republic:before{content:"\f510"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-people-carry:before{content:"\f4ce"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poo:before{content:"\f2fe"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-r-project:before{content:"\f4f7"}.fa-random:before{content:"\f074"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-rendact:before{content:"\f3e4"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-retweet:before{content:"\f079"}.fa-ribbon:before{content:"\f4d6"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-search:before{content:"\f002"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skull:before{content:"\f54c"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowflake:before{content:"\f2dc"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toolbox:before{content:"\f552"}.fa-tooth:before{content:"\f5c9"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-train:before{content:"\f238"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-moving:before{content:"\f4df"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}
    \ No newline at end of file
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/regular.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/regular.css
    new file mode 100644
    index 00000000..02b22faf
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/regular.css
    @@ -0,0 +1,5 @@
    +/*!
    + * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
    + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
    + */
    +@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:"Font Awesome 5 Free";font-weight:400}
    \ No newline at end of file
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/solid.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/solid.css
    new file mode 100644
    index 00000000..aed56a2f
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/solid.css
    @@ -0,0 +1,5 @@
    +/*!
    + * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
    + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
    + */
    +@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900}
    \ No newline at end of file
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/svg-with-js.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/svg-with-js.css
    new file mode 100644
    index 00000000..504203d7
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/svg-with-js.css
    @@ -0,0 +1,5 @@
    +/*!
    + * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
    + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
    + */
    +.svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;transform:translate(-50%,-50%);transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;transform:scale(.25);transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;transform:scale(.25);transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;transform:scale(.25);transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:a 2s infinite linear}.fa-pulse{animation:a 1s infinite steps(8)}@keyframes a{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1em}.svg-inline--fa.fa-stack-2x{height:2em;width:2em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}
    \ No newline at end of file
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/v4-shims.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/v4-shims.css
    new file mode 100644
    index 00000000..b10f6554
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/v4-shims.css
    @@ -0,0 +1,2170 @@
    +/*!
    + * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
    + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
    + */
    +.fa.fa-glass:before {
    +  content: "\f000"; }
    +
    +.fa.fa-meetup {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-star-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-star-o:before {
    +  content: "\f005"; }
    +
    +.fa.fa-remove:before {
    +  content: "\f00d"; }
    +
    +.fa.fa-close:before {
    +  content: "\f00d"; }
    +
    +.fa.fa-gear:before {
    +  content: "\f013"; }
    +
    +.fa.fa-trash-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-trash-o:before {
    +  content: "\f2ed"; }
    +
    +.fa.fa-file-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-o:before {
    +  content: "\f15b"; }
    +
    +.fa.fa-clock-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-clock-o:before {
    +  content: "\f017"; }
    +
    +.fa.fa-arrow-circle-o-down {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-arrow-circle-o-down:before {
    +  content: "\f358"; }
    +
    +.fa.fa-arrow-circle-o-up {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-arrow-circle-o-up:before {
    +  content: "\f35b"; }
    +
    +.fa.fa-play-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-play-circle-o:before {
    +  content: "\f144"; }
    +
    +.fa.fa-repeat:before {
    +  content: "\f01e"; }
    +
    +.fa.fa-rotate-right:before {
    +  content: "\f01e"; }
    +
    +.fa.fa-refresh:before {
    +  content: "\f021"; }
    +
    +.fa.fa-list-alt {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-dedent:before {
    +  content: "\f03b"; }
    +
    +.fa.fa-video-camera:before {
    +  content: "\f03d"; }
    +
    +.fa.fa-picture-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-picture-o:before {
    +  content: "\f03e"; }
    +
    +.fa.fa-photo {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-photo:before {
    +  content: "\f03e"; }
    +
    +.fa.fa-image {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-image:before {
    +  content: "\f03e"; }
    +
    +.fa.fa-pencil:before {
    +  content: "\f303"; }
    +
    +.fa.fa-map-marker:before {
    +  content: "\f3c5"; }
    +
    +.fa.fa-pencil-square-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-pencil-square-o:before {
    +  content: "\f044"; }
    +
    +.fa.fa-share-square-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-share-square-o:before {
    +  content: "\f14d"; }
    +
    +.fa.fa-check-square-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-check-square-o:before {
    +  content: "\f14a"; }
    +
    +.fa.fa-arrows:before {
    +  content: "\f0b2"; }
    +
    +.fa.fa-times-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-times-circle-o:before {
    +  content: "\f057"; }
    +
    +.fa.fa-check-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-check-circle-o:before {
    +  content: "\f058"; }
    +
    +.fa.fa-mail-forward:before {
    +  content: "\f064"; }
    +
    +.fa.fa-eye {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-eye-slash {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-warning:before {
    +  content: "\f071"; }
    +
    +.fa.fa-calendar:before {
    +  content: "\f073"; }
    +
    +.fa.fa-arrows-v:before {
    +  content: "\f338"; }
    +
    +.fa.fa-arrows-h:before {
    +  content: "\f337"; }
    +
    +.fa.fa-bar-chart {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-bar-chart:before {
    +  content: "\f080"; }
    +
    +.fa.fa-bar-chart-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-bar-chart-o:before {
    +  content: "\f080"; }
    +
    +.fa.fa-twitter-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-facebook-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-gears:before {
    +  content: "\f085"; }
    +
    +.fa.fa-thumbs-o-up {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-thumbs-o-up:before {
    +  content: "\f164"; }
    +
    +.fa.fa-thumbs-o-down {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-thumbs-o-down:before {
    +  content: "\f165"; }
    +
    +.fa.fa-heart-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-heart-o:before {
    +  content: "\f004"; }
    +
    +.fa.fa-sign-out:before {
    +  content: "\f2f5"; }
    +
    +.fa.fa-linkedin-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-linkedin-square:before {
    +  content: "\f08c"; }
    +
    +.fa.fa-thumb-tack:before {
    +  content: "\f08d"; }
    +
    +.fa.fa-external-link:before {
    +  content: "\f35d"; }
    +
    +.fa.fa-sign-in:before {
    +  content: "\f2f6"; }
    +
    +.fa.fa-github-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-lemon-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-lemon-o:before {
    +  content: "\f094"; }
    +
    +.fa.fa-square-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-square-o:before {
    +  content: "\f0c8"; }
    +
    +.fa.fa-bookmark-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-bookmark-o:before {
    +  content: "\f02e"; }
    +
    +.fa.fa-twitter {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-facebook {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-facebook:before {
    +  content: "\f39e"; }
    +
    +.fa.fa-facebook-f {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-facebook-f:before {
    +  content: "\f39e"; }
    +
    +.fa.fa-github {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-credit-card {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-feed:before {
    +  content: "\f09e"; }
    +
    +.fa.fa-hdd-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hdd-o:before {
    +  content: "\f0a0"; }
    +
    +.fa.fa-hand-o-right {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-o-right:before {
    +  content: "\f0a4"; }
    +
    +.fa.fa-hand-o-left {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-o-left:before {
    +  content: "\f0a5"; }
    +
    +.fa.fa-hand-o-up {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-o-up:before {
    +  content: "\f0a6"; }
    +
    +.fa.fa-hand-o-down {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-o-down:before {
    +  content: "\f0a7"; }
    +
    +.fa.fa-arrows-alt:before {
    +  content: "\f31e"; }
    +
    +.fa.fa-group:before {
    +  content: "\f0c0"; }
    +
    +.fa.fa-chain:before {
    +  content: "\f0c1"; }
    +
    +.fa.fa-scissors:before {
    +  content: "\f0c4"; }
    +
    +.fa.fa-files-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-files-o:before {
    +  content: "\f0c5"; }
    +
    +.fa.fa-floppy-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-floppy-o:before {
    +  content: "\f0c7"; }
    +
    +.fa.fa-navicon:before {
    +  content: "\f0c9"; }
    +
    +.fa.fa-reorder:before {
    +  content: "\f0c9"; }
    +
    +.fa.fa-pinterest {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-pinterest-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-google-plus-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-google-plus {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-google-plus:before {
    +  content: "\f0d5"; }
    +
    +.fa.fa-money {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-money:before {
    +  content: "\f3d1"; }
    +
    +.fa.fa-unsorted:before {
    +  content: "\f0dc"; }
    +
    +.fa.fa-sort-desc:before {
    +  content: "\f0dd"; }
    +
    +.fa.fa-sort-asc:before {
    +  content: "\f0de"; }
    +
    +.fa.fa-linkedin {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-linkedin:before {
    +  content: "\f0e1"; }
    +
    +.fa.fa-rotate-left:before {
    +  content: "\f0e2"; }
    +
    +.fa.fa-legal:before {
    +  content: "\f0e3"; }
    +
    +.fa.fa-tachometer:before {
    +  content: "\f3fd"; }
    +
    +.fa.fa-dashboard:before {
    +  content: "\f3fd"; }
    +
    +.fa.fa-comment-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-comment-o:before {
    +  content: "\f075"; }
    +
    +.fa.fa-comments-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-comments-o:before {
    +  content: "\f086"; }
    +
    +.fa.fa-flash:before {
    +  content: "\f0e7"; }
    +
    +.fa.fa-clipboard {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-paste {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-paste:before {
    +  content: "\f328"; }
    +
    +.fa.fa-lightbulb-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-lightbulb-o:before {
    +  content: "\f0eb"; }
    +
    +.fa.fa-exchange:before {
    +  content: "\f362"; }
    +
    +.fa.fa-cloud-download:before {
    +  content: "\f381"; }
    +
    +.fa.fa-cloud-upload:before {
    +  content: "\f382"; }
    +
    +.fa.fa-bell-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-bell-o:before {
    +  content: "\f0f3"; }
    +
    +.fa.fa-cutlery:before {
    +  content: "\f2e7"; }
    +
    +.fa.fa-file-text-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-text-o:before {
    +  content: "\f15c"; }
    +
    +.fa.fa-building-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-building-o:before {
    +  content: "\f1ad"; }
    +
    +.fa.fa-hospital-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hospital-o:before {
    +  content: "\f0f8"; }
    +
    +.fa.fa-tablet:before {
    +  content: "\f3fa"; }
    +
    +.fa.fa-mobile:before {
    +  content: "\f3cd"; }
    +
    +.fa.fa-mobile-phone:before {
    +  content: "\f3cd"; }
    +
    +.fa.fa-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-circle-o:before {
    +  content: "\f111"; }
    +
    +.fa.fa-mail-reply:before {
    +  content: "\f3e5"; }
    +
    +.fa.fa-github-alt {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-folder-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-folder-o:before {
    +  content: "\f07b"; }
    +
    +.fa.fa-folder-open-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-folder-open-o:before {
    +  content: "\f07c"; }
    +
    +.fa.fa-smile-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-smile-o:before {
    +  content: "\f118"; }
    +
    +.fa.fa-frown-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-frown-o:before {
    +  content: "\f119"; }
    +
    +.fa.fa-meh-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-meh-o:before {
    +  content: "\f11a"; }
    +
    +.fa.fa-keyboard-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-keyboard-o:before {
    +  content: "\f11c"; }
    +
    +.fa.fa-flag-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-flag-o:before {
    +  content: "\f024"; }
    +
    +.fa.fa-mail-reply-all:before {
    +  content: "\f122"; }
    +
    +.fa.fa-star-half-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-star-half-o:before {
    +  content: "\f089"; }
    +
    +.fa.fa-star-half-empty {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-star-half-empty:before {
    +  content: "\f089"; }
    +
    +.fa.fa-star-half-full {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-star-half-full:before {
    +  content: "\f089"; }
    +
    +.fa.fa-code-fork:before {
    +  content: "\f126"; }
    +
    +.fa.fa-chain-broken:before {
    +  content: "\f127"; }
    +
    +.fa.fa-shield:before {
    +  content: "\f3ed"; }
    +
    +.fa.fa-calendar-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-calendar-o:before {
    +  content: "\f133"; }
    +
    +.fa.fa-maxcdn {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-html5 {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-css3 {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-ticket:before {
    +  content: "\f3ff"; }
    +
    +.fa.fa-minus-square-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-minus-square-o:before {
    +  content: "\f146"; }
    +
    +.fa.fa-level-up:before {
    +  content: "\f3bf"; }
    +
    +.fa.fa-level-down:before {
    +  content: "\f3be"; }
    +
    +.fa.fa-pencil-square:before {
    +  content: "\f14b"; }
    +
    +.fa.fa-external-link-square:before {
    +  content: "\f360"; }
    +
    +.fa.fa-compass {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-caret-square-o-down {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-caret-square-o-down:before {
    +  content: "\f150"; }
    +
    +.fa.fa-toggle-down {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-toggle-down:before {
    +  content: "\f150"; }
    +
    +.fa.fa-caret-square-o-up {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-caret-square-o-up:before {
    +  content: "\f151"; }
    +
    +.fa.fa-toggle-up {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-toggle-up:before {
    +  content: "\f151"; }
    +
    +.fa.fa-caret-square-o-right {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-caret-square-o-right:before {
    +  content: "\f152"; }
    +
    +.fa.fa-toggle-right {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-toggle-right:before {
    +  content: "\f152"; }
    +
    +.fa.fa-eur:before {
    +  content: "\f153"; }
    +
    +.fa.fa-euro:before {
    +  content: "\f153"; }
    +
    +.fa.fa-gbp:before {
    +  content: "\f154"; }
    +
    +.fa.fa-usd:before {
    +  content: "\f155"; }
    +
    +.fa.fa-dollar:before {
    +  content: "\f155"; }
    +
    +.fa.fa-inr:before {
    +  content: "\f156"; }
    +
    +.fa.fa-rupee:before {
    +  content: "\f156"; }
    +
    +.fa.fa-jpy:before {
    +  content: "\f157"; }
    +
    +.fa.fa-cny:before {
    +  content: "\f157"; }
    +
    +.fa.fa-rmb:before {
    +  content: "\f157"; }
    +
    +.fa.fa-yen:before {
    +  content: "\f157"; }
    +
    +.fa.fa-rub:before {
    +  content: "\f158"; }
    +
    +.fa.fa-ruble:before {
    +  content: "\f158"; }
    +
    +.fa.fa-rouble:before {
    +  content: "\f158"; }
    +
    +.fa.fa-krw:before {
    +  content: "\f159"; }
    +
    +.fa.fa-won:before {
    +  content: "\f159"; }
    +
    +.fa.fa-btc {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-bitcoin {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-bitcoin:before {
    +  content: "\f15a"; }
    +
    +.fa.fa-file-text:before {
    +  content: "\f15c"; }
    +
    +.fa.fa-sort-alpha-asc:before {
    +  content: "\f15d"; }
    +
    +.fa.fa-sort-alpha-desc:before {
    +  content: "\f15e"; }
    +
    +.fa.fa-sort-amount-asc:before {
    +  content: "\f160"; }
    +
    +.fa.fa-sort-amount-desc:before {
    +  content: "\f161"; }
    +
    +.fa.fa-sort-numeric-asc:before {
    +  content: "\f162"; }
    +
    +.fa.fa-sort-numeric-desc:before {
    +  content: "\f163"; }
    +
    +.fa.fa-youtube-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-youtube {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-xing {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-xing-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-youtube-play {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-youtube-play:before {
    +  content: "\f167"; }
    +
    +.fa.fa-dropbox {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-stack-overflow {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-instagram {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-flickr {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-adn {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-bitbucket {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-bitbucket-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-bitbucket-square:before {
    +  content: "\f171"; }
    +
    +.fa.fa-tumblr {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-tumblr-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-long-arrow-down:before {
    +  content: "\f309"; }
    +
    +.fa.fa-long-arrow-up:before {
    +  content: "\f30c"; }
    +
    +.fa.fa-long-arrow-left:before {
    +  content: "\f30a"; }
    +
    +.fa.fa-long-arrow-right:before {
    +  content: "\f30b"; }
    +
    +.fa.fa-apple {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-windows {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-android {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-linux {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-dribbble {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-skype {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-foursquare {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-trello {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-gratipay {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-gittip {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-gittip:before {
    +  content: "\f184"; }
    +
    +.fa.fa-sun-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-sun-o:before {
    +  content: "\f185"; }
    +
    +.fa.fa-moon-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-moon-o:before {
    +  content: "\f186"; }
    +
    +.fa.fa-vk {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-weibo {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-renren {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-pagelines {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-stack-exchange {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-arrow-circle-o-right {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-arrow-circle-o-right:before {
    +  content: "\f35a"; }
    +
    +.fa.fa-arrow-circle-o-left {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-arrow-circle-o-left:before {
    +  content: "\f359"; }
    +
    +.fa.fa-caret-square-o-left {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-caret-square-o-left:before {
    +  content: "\f191"; }
    +
    +.fa.fa-toggle-left {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-toggle-left:before {
    +  content: "\f191"; }
    +
    +.fa.fa-dot-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-dot-circle-o:before {
    +  content: "\f192"; }
    +
    +.fa.fa-vimeo-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-try:before {
    +  content: "\f195"; }
    +
    +.fa.fa-turkish-lira:before {
    +  content: "\f195"; }
    +
    +.fa.fa-plus-square-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-plus-square-o:before {
    +  content: "\f0fe"; }
    +
    +.fa.fa-slack {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wordpress {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-openid {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-institution:before {
    +  content: "\f19c"; }
    +
    +.fa.fa-bank:before {
    +  content: "\f19c"; }
    +
    +.fa.fa-mortar-board:before {
    +  content: "\f19d"; }
    +
    +.fa.fa-yahoo {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-google {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-reddit {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-reddit-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-stumbleupon-circle {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-stumbleupon {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-delicious {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-digg {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-pied-piper-pp {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-pied-piper-alt {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-drupal {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-joomla {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-spoon:before {
    +  content: "\f2e5"; }
    +
    +.fa.fa-behance {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-behance-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-steam {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-steam-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-automobile:before {
    +  content: "\f1b9"; }
    +
    +.fa.fa-cab:before {
    +  content: "\f1ba"; }
    +
    +.fa.fa-envelope-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-envelope-o:before {
    +  content: "\f0e0"; }
    +
    +.fa.fa-deviantart {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-soundcloud {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-file-pdf-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-pdf-o:before {
    +  content: "\f1c1"; }
    +
    +.fa.fa-file-word-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-word-o:before {
    +  content: "\f1c2"; }
    +
    +.fa.fa-file-excel-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-excel-o:before {
    +  content: "\f1c3"; }
    +
    +.fa.fa-file-powerpoint-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-powerpoint-o:before {
    +  content: "\f1c4"; }
    +
    +.fa.fa-file-image-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-image-o:before {
    +  content: "\f1c5"; }
    +
    +.fa.fa-file-photo-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-photo-o:before {
    +  content: "\f1c5"; }
    +
    +.fa.fa-file-picture-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-picture-o:before {
    +  content: "\f1c5"; }
    +
    +.fa.fa-file-archive-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-archive-o:before {
    +  content: "\f1c6"; }
    +
    +.fa.fa-file-zip-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-zip-o:before {
    +  content: "\f1c6"; }
    +
    +.fa.fa-file-audio-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-audio-o:before {
    +  content: "\f1c7"; }
    +
    +.fa.fa-file-sound-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-sound-o:before {
    +  content: "\f1c7"; }
    +
    +.fa.fa-file-video-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-video-o:before {
    +  content: "\f1c8"; }
    +
    +.fa.fa-file-movie-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-movie-o:before {
    +  content: "\f1c8"; }
    +
    +.fa.fa-file-code-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-file-code-o:before {
    +  content: "\f1c9"; }
    +
    +.fa.fa-vine {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-codepen {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-jsfiddle {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-life-ring {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-life-bouy {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-life-bouy:before {
    +  content: "\f1cd"; }
    +
    +.fa.fa-life-buoy {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-life-buoy:before {
    +  content: "\f1cd"; }
    +
    +.fa.fa-life-saver {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-life-saver:before {
    +  content: "\f1cd"; }
    +
    +.fa.fa-support {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-support:before {
    +  content: "\f1cd"; }
    +
    +.fa.fa-circle-o-notch:before {
    +  content: "\f1ce"; }
    +
    +.fa.fa-rebel {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-ra {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-ra:before {
    +  content: "\f1d0"; }
    +
    +.fa.fa-resistance {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-resistance:before {
    +  content: "\f1d0"; }
    +
    +.fa.fa-empire {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-ge {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-ge:before {
    +  content: "\f1d1"; }
    +
    +.fa.fa-git-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-git {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-hacker-news {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-y-combinator-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-y-combinator-square:before {
    +  content: "\f1d4"; }
    +
    +.fa.fa-yc-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-yc-square:before {
    +  content: "\f1d4"; }
    +
    +.fa.fa-tencent-weibo {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-qq {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-weixin {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wechat {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wechat:before {
    +  content: "\f1d7"; }
    +
    +.fa.fa-send:before {
    +  content: "\f1d8"; }
    +
    +.fa.fa-paper-plane-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-paper-plane-o:before {
    +  content: "\f1d8"; }
    +
    +.fa.fa-send-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-send-o:before {
    +  content: "\f1d8"; }
    +
    +.fa.fa-circle-thin {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-circle-thin:before {
    +  content: "\f111"; }
    +
    +.fa.fa-header:before {
    +  content: "\f1dc"; }
    +
    +.fa.fa-sliders:before {
    +  content: "\f1de"; }
    +
    +.fa.fa-futbol-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-futbol-o:before {
    +  content: "\f1e3"; }
    +
    +.fa.fa-soccer-ball-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-soccer-ball-o:before {
    +  content: "\f1e3"; }
    +
    +.fa.fa-slideshare {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-twitch {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-yelp {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-newspaper-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-newspaper-o:before {
    +  content: "\f1ea"; }
    +
    +.fa.fa-paypal {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-google-wallet {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-cc-visa {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-cc-mastercard {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-cc-discover {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-cc-amex {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-cc-paypal {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-cc-stripe {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-bell-slash-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-bell-slash-o:before {
    +  content: "\f1f6"; }
    +
    +.fa.fa-trash:before {
    +  content: "\f2ed"; }
    +
    +.fa.fa-copyright {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-eyedropper:before {
    +  content: "\f1fb"; }
    +
    +.fa.fa-area-chart:before {
    +  content: "\f1fe"; }
    +
    +.fa.fa-pie-chart:before {
    +  content: "\f200"; }
    +
    +.fa.fa-line-chart:before {
    +  content: "\f201"; }
    +
    +.fa.fa-lastfm {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-lastfm-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-ioxhost {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-angellist {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-cc {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-cc:before {
    +  content: "\f20a"; }
    +
    +.fa.fa-ils:before {
    +  content: "\f20b"; }
    +
    +.fa.fa-shekel:before {
    +  content: "\f20b"; }
    +
    +.fa.fa-sheqel:before {
    +  content: "\f20b"; }
    +
    +.fa.fa-meanpath {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-meanpath:before {
    +  content: "\f2b4"; }
    +
    +.fa.fa-buysellads {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-connectdevelop {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-dashcube {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-forumbee {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-leanpub {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-sellsy {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-shirtsinbulk {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-simplybuilt {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-skyatlas {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-diamond {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-diamond:before {
    +  content: "\f3a5"; }
    +
    +.fa.fa-intersex:before {
    +  content: "\f224"; }
    +
    +.fa.fa-facebook-official {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-facebook-official:before {
    +  content: "\f09a"; }
    +
    +.fa.fa-pinterest-p {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-whatsapp {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-hotel:before {
    +  content: "\f236"; }
    +
    +.fa.fa-viacoin {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-medium {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-y-combinator {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-yc {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-yc:before {
    +  content: "\f23b"; }
    +
    +.fa.fa-optin-monster {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-opencart {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-expeditedssl {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-battery-4:before {
    +  content: "\f240"; }
    +
    +.fa.fa-battery:before {
    +  content: "\f240"; }
    +
    +.fa.fa-battery-3:before {
    +  content: "\f241"; }
    +
    +.fa.fa-battery-2:before {
    +  content: "\f242"; }
    +
    +.fa.fa-battery-1:before {
    +  content: "\f243"; }
    +
    +.fa.fa-battery-0:before {
    +  content: "\f244"; }
    +
    +.fa.fa-object-group {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-object-ungroup {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-sticky-note-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-sticky-note-o:before {
    +  content: "\f249"; }
    +
    +.fa.fa-cc-jcb {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-cc-diners-club {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-clone {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hourglass-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hourglass-o:before {
    +  content: "\f254"; }
    +
    +.fa.fa-hourglass-1:before {
    +  content: "\f251"; }
    +
    +.fa.fa-hourglass-2:before {
    +  content: "\f252"; }
    +
    +.fa.fa-hourglass-3:before {
    +  content: "\f253"; }
    +
    +.fa.fa-hand-rock-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-rock-o:before {
    +  content: "\f255"; }
    +
    +.fa.fa-hand-grab-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-grab-o:before {
    +  content: "\f255"; }
    +
    +.fa.fa-hand-paper-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-paper-o:before {
    +  content: "\f256"; }
    +
    +.fa.fa-hand-stop-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-stop-o:before {
    +  content: "\f256"; }
    +
    +.fa.fa-hand-scissors-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-scissors-o:before {
    +  content: "\f257"; }
    +
    +.fa.fa-hand-lizard-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-lizard-o:before {
    +  content: "\f258"; }
    +
    +.fa.fa-hand-spock-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-spock-o:before {
    +  content: "\f259"; }
    +
    +.fa.fa-hand-pointer-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-pointer-o:before {
    +  content: "\f25a"; }
    +
    +.fa.fa-hand-peace-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-hand-peace-o:before {
    +  content: "\f25b"; }
    +
    +.fa.fa-registered {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-creative-commons {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-gg {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-gg-circle {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-tripadvisor {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-odnoklassniki {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-odnoklassniki-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-get-pocket {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wikipedia-w {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-safari {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-chrome {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-firefox {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-opera {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-internet-explorer {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-television:before {
    +  content: "\f26c"; }
    +
    +.fa.fa-contao {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-500px {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-amazon {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-calendar-plus-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-calendar-plus-o:before {
    +  content: "\f271"; }
    +
    +.fa.fa-calendar-minus-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-calendar-minus-o:before {
    +  content: "\f272"; }
    +
    +.fa.fa-calendar-times-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-calendar-times-o:before {
    +  content: "\f273"; }
    +
    +.fa.fa-calendar-check-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-calendar-check-o:before {
    +  content: "\f274"; }
    +
    +.fa.fa-map-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-map-o:before {
    +  content: "\f279"; }
    +
    +.fa.fa-commenting {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-commenting:before {
    +  content: "\f4ad"; }
    +
    +.fa.fa-commenting-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-commenting-o:before {
    +  content: "\f4ad"; }
    +
    +.fa.fa-houzz {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-vimeo {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-vimeo:before {
    +  content: "\f27d"; }
    +
    +.fa.fa-black-tie {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-fonticons {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-reddit-alien {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-edge {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-credit-card-alt:before {
    +  content: "\f09d"; }
    +
    +.fa.fa-codiepie {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-modx {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-fort-awesome {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-usb {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-product-hunt {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-mixcloud {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-scribd {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-pause-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-pause-circle-o:before {
    +  content: "\f28b"; }
    +
    +.fa.fa-stop-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-stop-circle-o:before {
    +  content: "\f28d"; }
    +
    +.fa.fa-bluetooth {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-bluetooth-b {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-gitlab {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wpbeginner {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wpforms {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-envira {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wheelchair-alt {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wheelchair-alt:before {
    +  content: "\f368"; }
    +
    +.fa.fa-question-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-question-circle-o:before {
    +  content: "\f059"; }
    +
    +.fa.fa-volume-control-phone:before {
    +  content: "\f2a0"; }
    +
    +.fa.fa-asl-interpreting:before {
    +  content: "\f2a3"; }
    +
    +.fa.fa-deafness:before {
    +  content: "\f2a4"; }
    +
    +.fa.fa-hard-of-hearing:before {
    +  content: "\f2a4"; }
    +
    +.fa.fa-glide {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-glide-g {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-signing:before {
    +  content: "\f2a7"; }
    +
    +.fa.fa-viadeo {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-viadeo-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-snapchat {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-snapchat-ghost {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-snapchat-square {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-pied-piper {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-first-order {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-yoast {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-themeisle {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-google-plus-official {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-google-plus-official:before {
    +  content: "\f2b3"; }
    +
    +.fa.fa-google-plus-circle {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-google-plus-circle:before {
    +  content: "\f2b3"; }
    +
    +.fa.fa-font-awesome {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-fa {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-fa:before {
    +  content: "\f2b4"; }
    +
    +.fa.fa-handshake-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-handshake-o:before {
    +  content: "\f2b5"; }
    +
    +.fa.fa-envelope-open-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-envelope-open-o:before {
    +  content: "\f2b6"; }
    +
    +.fa.fa-linode {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-address-book-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-address-book-o:before {
    +  content: "\f2b9"; }
    +
    +.fa.fa-vcard:before {
    +  content: "\f2bb"; }
    +
    +.fa.fa-address-card-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-address-card-o:before {
    +  content: "\f2bb"; }
    +
    +.fa.fa-vcard-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-vcard-o:before {
    +  content: "\f2bb"; }
    +
    +.fa.fa-user-circle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-user-circle-o:before {
    +  content: "\f2bd"; }
    +
    +.fa.fa-user-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-user-o:before {
    +  content: "\f007"; }
    +
    +.fa.fa-id-badge {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-drivers-license:before {
    +  content: "\f2c2"; }
    +
    +.fa.fa-id-card-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-id-card-o:before {
    +  content: "\f2c2"; }
    +
    +.fa.fa-drivers-license-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-drivers-license-o:before {
    +  content: "\f2c2"; }
    +
    +.fa.fa-quora {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-free-code-camp {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-telegram {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-thermometer-4:before {
    +  content: "\f2c7"; }
    +
    +.fa.fa-thermometer:before {
    +  content: "\f2c7"; }
    +
    +.fa.fa-thermometer-3:before {
    +  content: "\f2c8"; }
    +
    +.fa.fa-thermometer-2:before {
    +  content: "\f2c9"; }
    +
    +.fa.fa-thermometer-1:before {
    +  content: "\f2ca"; }
    +
    +.fa.fa-thermometer-0:before {
    +  content: "\f2cb"; }
    +
    +.fa.fa-bathtub:before {
    +  content: "\f2cd"; }
    +
    +.fa.fa-s15:before {
    +  content: "\f2cd"; }
    +
    +.fa.fa-window-maximize {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-window-restore {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-times-rectangle:before {
    +  content: "\f410"; }
    +
    +.fa.fa-window-close-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-window-close-o:before {
    +  content: "\f410"; }
    +
    +.fa.fa-times-rectangle-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-times-rectangle-o:before {
    +  content: "\f410"; }
    +
    +.fa.fa-bandcamp {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-grav {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-etsy {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-imdb {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-ravelry {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-eercast {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-eercast:before {
    +  content: "\f2da"; }
    +
    +.fa.fa-snowflake-o {
    +  font-family: 'Font Awesome 5 Free';
    +  font-weight: 400; }
    +
    +.fa.fa-snowflake-o:before {
    +  content: "\f2dc"; }
    +
    +.fa.fa-superpowers {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-wpexplorer {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    +
    +.fa.fa-spotify {
    +  font-family: 'Font Awesome 5 Brands';
    +  font-weight: 400; }
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/v4-shims.min.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/v4-shims.min.css
    new file mode 100644
    index 00000000..a47c8e25
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/css/v4-shims.min.css
    @@ -0,0 +1,5 @@
    +/*!
    + * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
    + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
    + */
    +.fa.fa-glass:before{content:"\f000"}.fa.fa-meetup{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-star-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-o:before{content:"\f005"}.fa.fa-close:before,.fa.fa-remove:before{content:"\f00d"}.fa.fa-gear:before{content:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-trash-o:before{content:"\f2ed"}.fa.fa-file-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-o:before{content:"\f15b"}.fa.fa-clock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-clock-o:before{content:"\f017"}.fa.fa-arrow-circle-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:"\f358"}.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-play-circle-o:before{content:"\f144"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:"\f01e"}.fa.fa-refresh:before{content:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dedent:before{content:"\f03b"}.fa.fa-video-camera:before{content:"\f03d"}.fa.fa-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-picture-o:before{content:"\f03e"}.fa.fa-photo{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-photo:before{content:"\f03e"}.fa.fa-image{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-image:before{content:"\f03e"}.fa.fa-pencil:before{content:"\f303"}.fa.fa-map-marker:before{content:"\f3c5"}.fa.fa-pencil-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pencil-square-o:before{content:"\f044"}.fa.fa-share-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-share-square-o:before{content:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-square-o:before{content:"\f14a"}.fa.fa-arrows:before{content:"\f0b2"}.fa.fa-times-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-circle-o:before{content:"\f057"}.fa.fa-check-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-circle-o:before{content:"\f058"}.fa.fa-mail-forward:before{content:"\f064"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-warning:before{content:"\f071"}.fa.fa-calendar:before{content:"\f073"}.fa.fa-arrows-v:before{content:"\f338"}.fa.fa-arrows-h:before{content:"\f337"}.fa.fa-bar-chart{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart:before{content:"\f080"}.fa.fa-bar-chart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart-o:before{content:"\f080"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gears:before{content:"\f085"}.fa.fa-thumbs-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-up:before{content:"\f164"}.fa.fa-thumbs-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-down:before{content:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-heart-o:before{content:"\f004"}.fa.fa-sign-out:before{content:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin-square:before{content:"\f08c"}.fa.fa-thumb-tack:before{content:"\f08d"}.fa.fa-external-link:before{content:"\f35d"}.fa.fa-sign-in:before{content:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-lemon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lemon-o:before{content:"\f094"}.fa.fa-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-square-o:before{content:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bookmark-o:before{content:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook:before{content:"\f39e"}.fa.fa-facebook-f{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-f:before{content:"\f39e"}.fa.fa-github{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-feed:before{content:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hdd-o:before{content:"\f0a0"}.fa.fa-hand-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-right:before{content:"\f0a4"}.fa.fa-hand-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-left:before{content:"\f0a5"}.fa.fa-hand-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-up:before{content:"\f0a6"}.fa.fa-hand-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-down:before{content:"\f0a7"}.fa.fa-arrows-alt:before{content:"\f31e"}.fa.fa-group:before{content:"\f0c0"}.fa.fa-chain:before{content:"\f0c1"}.fa.fa-scissors:before{content:"\f0c4"}.fa.fa-files-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-files-o:before{content:"\f0c5"}.fa.fa-floppy-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-floppy-o:before{content:"\f0c7"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:"\f0c9"}.fa.fa-google-plus,.fa.fa-google-plus-square,.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus:before{content:"\f0d5"}.fa.fa-money{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-money:before{content:"\f3d1"}.fa.fa-unsorted:before{content:"\f0dc"}.fa.fa-sort-desc:before{content:"\f0dd"}.fa.fa-sort-asc:before{content:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin:before{content:"\f0e1"}.fa.fa-rotate-left:before{content:"\f0e2"}.fa.fa-legal:before{content:"\f0e3"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:"\f3fd"}.fa.fa-comment-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comment-o:before{content:"\f075"}.fa.fa-comments-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comments-o:before{content:"\f086"}.fa.fa-flash:before{content:"\f0e7"}.fa.fa-clipboard,.fa.fa-paste{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paste:before{content:"\f328"}.fa.fa-lightbulb-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lightbulb-o:before{content:"\f0eb"}.fa.fa-exchange:before{content:"\f362"}.fa.fa-cloud-download:before{content:"\f381"}.fa.fa-cloud-upload:before{content:"\f382"}.fa.fa-bell-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-o:before{content:"\f0f3"}.fa.fa-cutlery:before{content:"\f2e7"}.fa.fa-file-text-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-text-o:before{content:"\f15c"}.fa.fa-building-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-building-o:before{content:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hospital-o:before{content:"\f0f8"}.fa.fa-tablet:before{content:"\f3fa"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-o:before{content:"\f111"}.fa.fa-mail-reply:before{content:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-folder-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-o:before{content:"\f07b"}.fa.fa-folder-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-open-o:before{content:"\f07c"}.fa.fa-smile-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-smile-o:before{content:"\f118"}.fa.fa-frown-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-frown-o:before{content:"\f119"}.fa.fa-meh-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-meh-o:before{content:"\f11a"}.fa.fa-keyboard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-keyboard-o:before{content:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-flag-o:before{content:"\f024"}.fa.fa-mail-reply-all:before{content:"\f122"}.fa.fa-star-half-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-o:before{content:"\f089"}.fa.fa-star-half-empty{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-empty:before{content:"\f089"}.fa.fa-star-half-full{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-full:before{content:"\f089"}.fa.fa-code-fork:before{content:"\f126"}.fa.fa-chain-broken:before{content:"\f127"}.fa.fa-shield:before{content:"\f3ed"}.fa.fa-calendar-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-o:before{content:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ticket:before{content:"\f3ff"}.fa.fa-minus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-minus-square-o:before{content:"\f146"}.fa.fa-level-up:before{content:"\f3bf"}.fa.fa-level-down:before{content:"\f3be"}.fa.fa-pencil-square:before{content:"\f14b"}.fa.fa-external-link-square:before{content:"\f360"}.fa.fa-compass{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down:before{content:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-down:before{content:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-up:before{content:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-up:before{content:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-right:before{content:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-right:before{content:"\f152"}.fa.fa-eur:before,.fa.fa-euro:before{content:"\f153"}.fa.fa-gbp:before{content:"\f154"}.fa.fa-dollar:before,.fa.fa-usd:before{content:"\f155"}.fa.fa-inr:before,.fa.fa-rupee:before{content:"\f156"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:"\f157"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:"\f158"}.fa.fa-krw:before,.fa.fa-won:before{content:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitcoin:before{content:"\f15a"}.fa.fa-file-text:before{content:"\f15c"}.fa.fa-sort-alpha-asc:before{content:"\f15d"}.fa.fa-sort-alpha-desc:before{content:"\f15e"}.fa.fa-sort-amount-asc:before{content:"\f160"}.fa.fa-sort-amount-desc:before{content:"\f161"}.fa.fa-sort-numeric-asc:before{content:"\f162"}.fa.fa-sort-numeric-desc:before{content:"\f163"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-play,.fa.fa-youtube-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-youtube-play:before{content:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitbucket-square:before{content:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-long-arrow-down:before{content:"\f309"}.fa.fa-long-arrow-up:before{content:"\f30c"}.fa.fa-long-arrow-left:before{content:"\f30a"}.fa.fa-long-arrow-right:before{content:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gittip:before{content:"\f184"}.fa.fa-sun-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sun-o:before{content:"\f185"}.fa.fa-moon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-moon-o:before{content:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:"\f35a"}.fa.fa-arrow-circle-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-left:before{content:"\f191"}.fa.fa-toggle-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-left:before{content:"\f191"}.fa.fa-dot-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dot-circle-o:before{content:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:"\f195"}.fa.fa-plus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-plus-square-o:before{content:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:"\f19c"}.fa.fa-mortar-board:before{content:"\f19d"}.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-google,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle,.fa.fa-yahoo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-spoon:before{content:"\f2e5"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-steam,.fa.fa-steam-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-automobile:before{content:"\f1b9"}.fa.fa-cab:before{content:"\f1ba"}.fa.fa-envelope-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-o:before{content:"\f0e0"}.fa.fa-deviantart,.fa.fa-soundcloud{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-file-pdf-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-pdf-o:before{content:"\f1c1"}.fa.fa-file-word-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-word-o:before{content:"\f1c2"}.fa.fa-file-excel-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-excel-o:before{content:"\f1c3"}.fa.fa-file-powerpoint-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-powerpoint-o:before{content:"\f1c4"}.fa.fa-file-image-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-image-o:before{content:"\f1c5"}.fa.fa-file-photo-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-photo-o:before{content:"\f1c5"}.fa.fa-file-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-picture-o:before{content:"\f1c5"}.fa.fa-file-archive-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-archive-o:before{content:"\f1c6"}.fa.fa-file-zip-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-zip-o:before{content:"\f1c6"}.fa.fa-file-audio-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-audio-o:before{content:"\f1c7"}.fa.fa-file-sound-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-sound-o:before{content:"\f1c7"}.fa.fa-file-video-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-video-o:before{content:"\f1c8"}.fa.fa-file-movie-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-movie-o:before{content:"\f1c8"}.fa.fa-file-code-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-code-o:before{content:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-life-bouy,.fa.fa-life-ring{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-bouy:before{content:"\f1cd"}.fa.fa-life-buoy{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-buoy:before{content:"\f1cd"}.fa.fa-life-saver{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-saver:before{content:"\f1cd"}.fa.fa-support{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-support:before{content:"\f1cd"}.fa.fa-circle-o-notch:before{content:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ra:before{content:"\f1d0"}.fa.fa-resistance{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-resistance:before{content:"\f1d0"}.fa.fa-empire,.fa.fa-ge{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ge:before{content:"\f1d1"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-y-combinator-square:before{content:"\f1d4"}.fa.fa-yc-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc-square:before{content:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wechat:before{content:"\f1d7"}.fa.fa-send:before{content:"\f1d8"}.fa.fa-paper-plane-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paper-plane-o:before{content:"\f1d8"}.fa.fa-send-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-send-o:before{content:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-thin:before{content:"\f111"}.fa.fa-header:before{content:"\f1dc"}.fa.fa-sliders:before{content:"\f1de"}.fa.fa-futbol-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-futbol-o:before{content:"\f1e3"}.fa.fa-soccer-ball-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-soccer-ball-o:before{content:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-newspaper-o:before{content:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-slash-o:before{content:"\f1f6"}.fa.fa-trash:before{content:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-eyedropper:before{content:"\f1fb"}.fa.fa-area-chart:before{content:"\f1fe"}.fa.fa-pie-chart:before{content:"\f200"}.fa.fa-line-chart:before{content:"\f201"}.fa.fa-angellist,.fa.fa-ioxhost,.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-cc:before{content:"\f20a"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:"\f20b"}.fa.fa-meanpath{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-meanpath:before{content:"\f2b4"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-diamond:before{content:"\f3a5"}.fa.fa-intersex:before{content:"\f224"}.fa.fa-facebook-official{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-official:before{content:"\f09a"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-hotel:before{content:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc:before{content:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:"\f240"}.fa.fa-battery-3:before{content:"\f241"}.fa.fa-battery-2:before{content:"\f242"}.fa.fa-battery-1:before{content:"\f243"}.fa.fa-battery-0:before{content:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sticky-note-o:before{content:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-clone,.fa.fa-hourglass-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hourglass-o:before{content:"\f254"}.fa.fa-hourglass-1:before{content:"\f251"}.fa.fa-hourglass-2:before{content:"\f252"}.fa.fa-hourglass-3:before{content:"\f253"}.fa.fa-hand-rock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-rock-o:before{content:"\f255"}.fa.fa-hand-grab-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-grab-o:before{content:"\f255"}.fa.fa-hand-paper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-paper-o:before{content:"\f256"}.fa.fa-hand-stop-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-stop-o:before{content:"\f256"}.fa.fa-hand-scissors-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-scissors-o:before{content:"\f257"}.fa.fa-hand-lizard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-lizard-o:before{content:"\f258"}.fa.fa-hand-spock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-spock-o:before{content:"\f259"}.fa.fa-hand-pointer-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-pointer-o:before{content:"\f25a"}.fa.fa-hand-peace-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-peace-o:before{content:"\f25b"}.fa.fa-registered{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-chrome,.fa.fa-creative-commons,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-internet-explorer,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square,.fa.fa-opera,.fa.fa-safari,.fa.fa-tripadvisor,.fa.fa-wikipedia-w{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-television:before{content:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-calendar-plus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-plus-o:before{content:"\f271"}.fa.fa-calendar-minus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-minus-o:before{content:"\f272"}.fa.fa-calendar-times-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-times-o:before{content:"\f273"}.fa.fa-calendar-check-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-check-o:before{content:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-map-o:before{content:"\f279"}.fa.fa-commenting{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-commenting:before{content:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-commenting-o:before{content:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-vimeo:before{content:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card-alt:before{content:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-pause-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pause-circle-o:before{content:"\f28b"}.fa.fa-stop-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-stop-circle-o:before{content:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wheelchair-alt:before{content:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-question-circle-o:before{content:"\f059"}.fa.fa-volume-control-phone:before{content:"\f2a0"}.fa.fa-asl-interpreting:before{content:"\f2a3"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-signing:before{content:"\f2a7"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat,.fa.fa-snapchat-ghost,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-viadeo,.fa.fa-viadeo-square,.fa.fa-yoast{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-official:before{content:"\f2b3"}.fa.fa-google-plus-circle{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-circle:before{content:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-fa:before{content:"\f2b4"}.fa.fa-handshake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-handshake-o:before{content:"\f2b5"}.fa.fa-envelope-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-open-o:before{content:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-book-o:before{content:"\f2b9"}.fa.fa-vcard:before{content:"\f2bb"}.fa.fa-address-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-card-o:before{content:"\f2bb"}.fa.fa-vcard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-vcard-o:before{content:"\f2bb"}.fa.fa-user-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-circle-o:before{content:"\f2bd"}.fa.fa-user-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-o:before{content:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license:before{content:"\f2c2"}.fa.fa-id-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-id-card-o:before{content:"\f2c2"}.fa.fa-drivers-license-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license-o:before{content:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:"\f2c7"}.fa.fa-thermometer-3:before{content:"\f2c8"}.fa.fa-thermometer-2:before{content:"\f2c9"}.fa.fa-thermometer-1:before{content:"\f2ca"}.fa.fa-thermometer-0:before{content:"\f2cb"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle:before{content:"\f410"}.fa.fa-window-close-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-window-close-o:before{content:"\f410"}.fa.fa-times-rectangle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle-o:before{content:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-eercast:before{content:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-snowflake-o:before{content:"\f2dc"}.fa.fa-spotify,.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 5 Brands";font-weight:400}
    \ No newline at end of file
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.eot b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.eot
    new file mode 100644
    index 00000000..f8e48185
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.eot differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.svg b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.svg
    new file mode 100644
    index 00000000..68eb65a1
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.svg
    @@ -0,0 +1,1127 @@
    + 
    +
    +
    +
    +  
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +  
    +
    +
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.ttf b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.ttf
    new file mode 100644
    index 00000000..2b00dae7
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.ttf differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.woff b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.woff
    new file mode 100644
    index 00000000..9e4b7e1c
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.woff differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.woff2 b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.woff2
    new file mode 100644
    index 00000000..b9e58c5e
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-brands-400.woff2 differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.eot b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.eot
    new file mode 100644
    index 00000000..5217c95f
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.eot differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.svg b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.svg
    new file mode 100644
    index 00000000..5f495431
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.svg
    @@ -0,0 +1,467 @@
    + 
    +
    +
    +
    +  
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +  
    +
    +
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.ttf b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.ttf
    new file mode 100644
    index 00000000..cefbd50f
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.ttf differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.woff b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.woff
    new file mode 100644
    index 00000000..954b0593
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.woff differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.woff2 b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.woff2
    new file mode 100644
    index 00000000..bd35950e
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-regular-400.woff2 differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.eot b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.eot
    new file mode 100644
    index 00000000..cc691d63
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.eot differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.svg b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.svg
    new file mode 100644
    index 00000000..1534b64b
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.svg
    @@ -0,0 +1,2231 @@
    + 
    +
    +
    +
    +  
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +    
    +  
    +
    +
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.ttf b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.ttf
    new file mode 100644
    index 00000000..618136ab
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.ttf differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.woff b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.woff
    new file mode 100644
    index 00000000..af476578
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.woff differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.woff2 b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.woff2
    new file mode 100644
    index 00000000..9ef566a9
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/font-awesome/webfonts/fa-solid-900.woff2 differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/blackboard.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/blackboard.png
    new file mode 100644
    index 00000000..50a2f643
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/blackboard.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-black.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-black.png
    new file mode 100644
    index 00000000..170b5200
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-black.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-blue.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-blue.png
    new file mode 100644
    index 00000000..32f3ff8f
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-blue.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-green.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-green.png
    new file mode 100644
    index 00000000..28a42218
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-green.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-orange.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-orange.png
    new file mode 100644
    index 00000000..7e8c2d2b
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-orange.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-purple.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-purple.png
    new file mode 100644
    index 00000000..637066ca
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-purple.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-red.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-red.png
    new file mode 100644
    index 00000000..713d6cd0
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-red.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-yellow.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-yellow.png
    new file mode 100644
    index 00000000..23e87f52
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/boardmarker-yellow.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-blue.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-blue.png
    new file mode 100644
    index 00000000..f70c2991
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-blue.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-green.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-green.png
    new file mode 100644
    index 00000000..39f3b20f
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-green.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-orange.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-orange.png
    new file mode 100644
    index 00000000..488c847a
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-orange.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-purple.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-purple.png
    new file mode 100644
    index 00000000..5bd29fb8
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-purple.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-red.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-red.png
    new file mode 100644
    index 00000000..18d4dc78
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-red.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-white.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-white.png
    new file mode 100644
    index 00000000..fed89a3c
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-white.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-yellow.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-yellow.png
    new file mode 100644
    index 00000000..0186bec0
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/chalk-yellow.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/sponge.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/sponge.png
    new file mode 100644
    index 00000000..cbfb2691
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/sponge.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/whiteboard.png b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/whiteboard.png
    new file mode 100644
    index 00000000..dbf570a9
    Binary files /dev/null and b/2311/site_libs/revealjs/plugin/reveal-chalkboard/img/whiteboard.png differ
    diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/plugin.js b/2311/site_libs/revealjs/plugin/reveal-chalkboard/plugin.js
    new file mode 100644
    index 00000000..76b736e2
    --- /dev/null
    +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/plugin.js
    @@ -0,0 +1,1976 @@
    +/*****************************************************************
    + ** Author: Asvin Goel, goel@telematique.eu
    + **
    + ** A plugin for reveal.js adding a chalkboard.
    + **
    + ** Version: 2.1.0
    + **
    + ** License: MIT license (see LICENSE.md)
    + **
    + ** Credits:
    + ** Chalkboard effect by Mohamed Moustafa https://github.com/mmoustafa/Chalkboard
    + ** Multi color support initially added by Kurt Rinnert https://github.com/rinnert
    + ** Compatibility with reveal.js v4 by Hakim El Hattab https://github.com/hakimel
    + ******************************************************************/
    +
    +window.RevealChalkboard = window.RevealChalkboard || {
    +	id: 'RevealChalkboard',
    +	init: function ( deck ) {
    +		initChalkboard( deck );
    +	},
    +	configure: function ( config ) {
    +		configure( config );
    +	},
    +	toggleNotesCanvas: function () {
    +		toggleNotesCanvas();
    +	},
    +	toggleChalkboard: function () {
    +		toggleChalkboard();
    +	},
    +	colorIndex: function () {
    +		colorIndex();
    +	},
    +	colorNext: function () {
    +		colorNext();
    +	},
    +	colorPrev: function () {
    +		colorPrev();
    +	},
    +	clear: function () {
    +		clear();
    +	},
    +	reset: function () {
    +		reset();
    +	},
    +	resetAll: function () {
    +		resetAll();
    +	},
    +	updateStorage: function () {
    +		updateStorage();
    +	},
    +	getData: function () {
    +		return getData();
    +	},
    +	download: function () {
    +		download();
    +	},
    +};
    +
    +function scriptPath() {
    +	// obtain plugin path from the script element
    +	var src;
    +	if ( document.currentScript ) {
    +		src = document.currentScript.src;
    +	} else {
    +		var sel = document.querySelector( 'script[src$="/chalkboard/plugin.js"]' )
    +		if ( sel ) {
    +			src = sel.src;
    +		}
    +	}
    +	var path = ( src === undefined ) ? "" : src.slice( 0, src.lastIndexOf( "/" ) + 1 );
    +//console.log("Path: " + path);
    +	return path;
    +}
    +var path = scriptPath();
    +
    +const initChalkboard = function ( Reveal ) {
    +//console.warn(path);
    +	/* Feature detection for passive event handling*/
    +	var passiveSupported = false;
    +
    +	try {
    +		window.addEventListener( 'test', null, Object.defineProperty( {}, 'passive', {
    +			get: function () {
    +				passiveSupported = true;
    +			}
    +		} ) );
    +	} catch ( err ) {}
    +
    +
    +/*****************************************************************
    + ** Configuration
    + ******************************************************************/
    +	var background, pen, draw, color;
    +	var grid = false;
    +	var boardmarkerWidth = 3;
    +	var chalkWidth = 7;
    +	var chalkEffect = 1.0;
    +	var rememberColor = [ true, false ];
    +	var eraser = {
    +		src: path + 'img/sponge.png',
    +		radius: 20
    +	};
    +	var boardmarkers = [ {
    +			color: 'rgba(100,100,100,1)',
    +			cursor: 'url(' + path + 'img/boardmarker-black.png), auto'
    +		},
    +		{
    +			color: 'rgba(30,144,255, 1)',
    +			cursor: 'url(' + path + 'img/boardmarker-blue.png), auto'
    +		},
    +		{
    +			color: 'rgba(220,20,60,1)',
    +			cursor: 'url(' + path + 'img/boardmarker-red.png), auto'
    +		},
    +		{
    +			color: 'rgba(50,205,50,1)',
    +			cursor: 'url(' + path + 'img/boardmarker-green.png), auto'
    +		},
    +		{
    +			color: 'rgba(255,140,0,1)',
    +			cursor: 'url(' + path + 'img/boardmarker-orange.png), auto'
    +		},
    +		{
    +			color: 'rgba(150,0,20150,1)',
    +			cursor: 'url(' + path + 'img/boardmarker-purple.png), auto'
    +		},
    +		{
    +			color: 'rgba(255,220,0,1)',
    +			cursor: 'url(' + path + 'img/boardmarker-yellow.png), auto'
    +		}
    +	];
    +	var chalks = [ {
    +			color: 'rgba(255,255,255,0.5)',
    +			cursor: 'url(' + path + 'img/chalk-white.png), auto'
    +		},
    +		{
    +			color: 'rgba(96, 154, 244, 0.5)',
    +			cursor: 'url(' + path + 'img/chalk-blue.png), auto'
    +		},
    +		{
    +			color: 'rgba(237, 20, 28, 0.5)',
    +			cursor: 'url(' + path + 'img/chalk-red.png), auto'
    +		},
    +		{
    +			color: 'rgba(20, 237, 28, 0.5)',
    +			cursor: 'url(' + path + 'img/chalk-green.png), auto'
    +		},
    +		{
    +			color: 'rgba(220, 133, 41, 0.5)',
    +			cursor: 'url(' + path + 'img/chalk-orange.png), auto'
    +		},
    +		{
    +			color: 'rgba(220,0,220,0.5)',
    +			cursor: 'url(' + path + 'img/chalk-purple.png), auto'
    +		},
    +		{
    +			color: 'rgba(255,220,0,0.5)',
    +			cursor: 'url(' + path + 'img/chalk-yellow.png), auto'
    +		}
    +	];
    +	var keyBindings = {
    +		toggleNotesCanvas: {
    +			keyCode: 67,
    +			key: 'C',
    +			description: 'Toggle notes canvas'
    +		},
    +		toggleChalkboard: {
    +			keyCode: 66,
    +			key: 'B',
    +			description: 'Toggle chalkboard'
    +		},
    +		clear: {
    +			keyCode: 46,
    +			key: 'DEL',
    +			description: 'Clear drawings on slide'
    +		},
    +/*
    +		reset: {
    +			keyCode: 173,
    +			key: '-',
    +			description: 'Reset drawings on slide'
    +		},
    +*/
    +		resetAll: {
    +			keyCode: 8,
    +			key: 'BACKSPACE',
    +			description: 'Reset all drawings'
    +		},
    +		colorNext: {
    +			keyCode: 88,
    +			key: 'X',
    +			description: 'Next color'
    +		},
    +		colorPrev: {
    +			keyCode: 89,
    +			key: 'Y',
    +			description: 'Previous color'
    +		},
    +		download: {
    +			keyCode: 68,
    +			key: 'D',
    +			description: 'Download drawings'
    +		}
    +	};
    +
    +
    +	var theme = 'chalkboard';
    +	var color = [ 0, 0 ];
    +	var toggleChalkboardButton = false;
    +	var toggleNotesButton = false;
    +	var colorButtons = true;
    +	var boardHandle = true;
    +	var transition = 800;
    +
    +	var readOnly = false;
    +	var messageType = 'broadcast';
    +
    +	var config = configure( Reveal.getConfig().chalkboard || {} );
    +	if ( config.keyBindings ) {
    +		for ( var key in config.keyBindings ) {
    +			keyBindings[ key ] = config.keyBindings[ key ];
    +		};
    +	}
    +
    +	function configure( config ) {
    +
    +		if ( config.boardmarkerWidth || config.penWidth ) boardmarkerWidth = config.boardmarkerWidth || config.penWidth;
    +		if ( config.chalkWidth ) chalkWidth = config.chalkWidth;
    +		if ( config.chalkEffect ) chalkEffect = config.chalkEffect;
    +		if ( config.rememberColor ) rememberColor = config.rememberColor;
    +		if ( config.eraser ) eraser = config.eraser;
    +		if ( config.boardmarkers ) boardmarkers = config.boardmarkers;
    +		if ( config.chalks ) chalks = config.chalks;
    +
    +		if ( config.theme ) theme = config.theme;
    +		switch ( theme ) {
    +		case 'whiteboard':
    +			background = [ 'rgba(127,127,127,.1)', path + 'img/whiteboard.png' ];
    +			draw = [ drawWithBoardmarker, drawWithBoardmarker ];
    +			pens = [ boardmarkers, boardmarkers ];
    +			grid = {
    +				color: 'rgb(127,127,255,0.1)',
    +				distance: 40,
    +				width: 2
    +			};
    +			break;
    +		case 'chalkboard':
    +		default:
    +			background = [ 'rgba(127,127,127,.1)', path + 'img/blackboard.png' ];
    +			draw = [ drawWithBoardmarker, drawWithChalk ];
    +			pens = [ boardmarkers, chalks ];
    +			grid = {
    +				color: 'rgb(50,50,10,0.5)',
    +				distance: 80,
    +				width: 2
    +			};
    +		}
    +
    +		if ( config.background ) background = config.background;
    +		if ( config.grid != undefined ) grid = config.grid;
    +
    +		if ( config.toggleChalkboardButton != undefined ) toggleChalkboardButton = config.toggleChalkboardButton;
    +		if ( config.toggleNotesButton != undefined ) toggleNotesButton = config.toggleNotesButton;
    +		if ( config.colorButtons != undefined ) colorButtons = config.colorButtons;
    +		if ( config.boardHandle != undefined ) boardHandle = config.boardHandle;
    +		if ( config.transition ) transition = config.transition;
    +
    +		if ( config.readOnly != undefined ) readOnly = config.readOnly;
    +		if ( config.messageType ) messageType = config.messageType;
    +
    +		if ( drawingCanvas && ( config.theme || config.background || config.grid ) ) {
    +			var canvas = document.getElementById( drawingCanvas[ 1 ].id );
    +			canvas.style.background = 'url("' + background[ 1 ] + '") repeat';
    +			clearCanvas( 1 );
    +			drawGrid();
    +		}
    +
    +		return config;
    +	}
    +/*****************************************************************
    + ** Setup
    + ******************************************************************/
    +
    +	function whenReady( callback ) {
    +		// wait for markdown to be parsed and code to be highlighted
    +		if ( !document.querySelector( 'section[data-markdown]:not([data-markdown-parsed])' ) 
    +		     && !document.querySelector( 'code[data-line-numbers*="|"]') 	
    +		) {
    +			callback();
    +		} else {
    +			console.log( "Wait for markdown to be parsed and code to be highlighted" );
    +			setTimeout( whenReady, 500, callback )
    +		}
    +	}
    +
    +	function whenLoaded( callback ) {
    +		// wait for drawings to be loaded and markdown to be parsed
    +		if ( loaded !== null ) {
    +			callback();
    +		} else {
    +			console.log( "Wait for drawings to be loaded" );
    +			setTimeout( whenLoaded, 500, callback )
    +		}
    +	}
    +
    +	if ( toggleChalkboardButton ) {
    +console.warn( "toggleChalkboardButton is deprecated, use customcontrols plugin instead!" );
    +//console.log("toggleChalkboardButton")
    +		var button = document.createElement( 'div' );
    +		button.className = "chalkboard-button";
    +		button.id = "toggle-chalkboard";
    +		button.style.visibility = "visible";
    +		button.style.position = "absolute";
    +		button.style.zIndex = 30;
    +		button.style.fontSize = "24px";
    +
    +		button.style.left = toggleChalkboardButton.left || "30px";
    +		button.style.bottom = toggleChalkboardButton.bottom || "30px";
    +		button.style.top = toggleChalkboardButton.top || "auto";
    +		button.style.right = toggleChalkboardButton.right || "auto";
    +
    +		button.innerHTML = ''
    +		document.querySelector( ".reveal" ).appendChild( button );
    +	}
    +	if ( toggleNotesButton ) {
    +console.warn( "toggleNotesButton is deprecated, use customcontrols plugin instead!" );
    +//console.log("toggleNotesButton")
    +		var button = document.createElement( 'div' );
    +		button.className = "chalkboard-button";
    +		button.id = "toggle-notes";
    +		button.style.position = "absolute";
    +		button.style.zIndex = 30;
    +		button.style.fontSize = "24px";
    +
    +		button.style.left = toggleNotesButton.left || "70px";
    +		button.style.bottom = toggleNotesButton.bottom || "30px";
    +		button.style.top = toggleNotesButton.top || "auto";
    +		button.style.right = toggleNotesButton.right || "auto";
    +
    +		button.innerHTML = ''
    +		document.querySelector( ".reveal" ).appendChild( button );
    +	}
    +
    +	var drawingCanvas = [ {
    +		id: 'notescanvas'
    +	}, {
    +		id: 'chalkboard'
    +	} ];
    +	setupDrawingCanvas( 0 );
    +	setupDrawingCanvas( 1 );
    +
    +	var mode = 0; // 0: notes canvas, 1: chalkboard
    +	var board = 0; // board index (only for chalkboard)
    +
    +	var mouseX = 0;
    +	var mouseY = 0;
    +	var lastX = null;
    +	var lastY = null;
    +
    +	var drawing = false;
    +	var erasing = false;
    +
    +	var slideStart = Date.now();
    +	var slideIndices = {
    +		h: 0,
    +		v: 0
    +	};
    +
    +	var timeouts = [
    +		[],
    +		[]
    +	];
    +	var touchTimeout = null;
    +	var slidechangeTimeout = null;
    +	var updateStorageTimeout = null;
    +	var playback = false;
    +
    +	function createPalette( colors, length ) {
    +		if ( length === true || length > colors.length ) {
    +			length = colors.length;
    +		}
    +		var palette = document.createElement( 'div' );
    +		palette.classList.add( 'palette' );
    +		var list = document.createElement( 'ul' );
    +		// color pickers
    +		for ( var i = 0; i < length; i++ ) {
    +			var colorButton = document.createElement( 'li' );
    +			colorButton.setAttribute( 'data-color', i );
    +			colorButton.innerHTML = '';
    +			colorButton.style.color = colors[ i ].color;
    +			colorButton.addEventListener( 'click', function ( e ) {
    +				var element = e.target;
    +				while ( !element.hasAttribute( 'data-color' ) ) {
    +					element = element.parentElement;
    +				}
    +				colorIndex( parseInt( element.getAttribute( 'data-color' ) ) );
    +			} );
    +			colorButton.addEventListener( 'touchstart', function ( e ) {
    +				var element = e.target;
    +				while ( !element.hasAttribute( 'data-color' ) ) {
    +					element = element.parentElement;
    +				}
    +				colorIndex( parseInt( element.getAttribute( 'data-color' ) ) );
    +			} );
    +			list.appendChild( colorButton );
    +		}
    +		palette.appendChild( list );
    +		return palette;
    +	};
    +
    +	function switchBoard( boardIdx ) {
    +		selectBoard( boardIdx, true );
    +		// broadcast
    +		var message = new CustomEvent( messageType );
    +			message.content = {
    +			sender: 'chalkboard-plugin',
    +			type: 'selectboard',
    +			timestamp: Date.now() - slideStart,
    +			mode,
    +			board
    +		};
    +		document.dispatchEvent( message );	
    +	}
    +
    +	function setupDrawingCanvas( id ) {
    +		var container = document.createElement( 'div' );
    +		container.id = drawingCanvas[ id ].id;
    +		container.classList.add( 'overlay' );
    +		container.setAttribute( 'data-prevent-swipe', 'true' );
    +		container.oncontextmenu = function () {
    +			return false;
    +		}
    +		container.style.cursor = pens[ id ][ color[ id ] ].cursor;
    +
    +		drawingCanvas[ id ].width = window.innerWidth;
    +		drawingCanvas[ id ].height = window.innerHeight;
    +		drawingCanvas[ id ].scale = 1;
    +		drawingCanvas[ id ].xOffset = 0;
    +		drawingCanvas[ id ].yOffset = 0;
    +
    +		if ( id == "0" ) {
    +			container.style.background = 'rgba(0,0,0,0)';
    +			container.style.zIndex = 24;
    +			container.style.opacity = 1;
    +			container.style.visibility = 'visible';
    +			container.style.pointerEvents = 'none';
    +
    +			var slides = document.querySelector( '.slides' );
    +			var aspectRatio = Reveal.getConfig().width / Reveal.getConfig().height;
    +			if ( drawingCanvas[ id ].width > drawingCanvas[ id ].height * aspectRatio ) {
    +				drawingCanvas[ id ].xOffset = ( drawingCanvas[ id ].width - drawingCanvas[ id ].height * aspectRatio ) / 2;
    +			} else if ( drawingCanvas[ id ].height > drawingCanvas[ id ].width / aspectRatio ) {
    +				drawingCanvas[ id ].yOffset = ( drawingCanvas[ id ].height - drawingCanvas[ id ].width / aspectRatio ) / 2;
    +			}
    +
    +			if ( colorButtons ) {
    +				var palette = createPalette( boardmarkers, colorButtons );
    +				palette.style.visibility = 'hidden'; // only show palette in drawing mode
    +				container.appendChild( palette );
    +			}
    +		} else {
    +			container.style.background = 'url("' + background[ id ] + '") repeat';
    +			container.style.zIndex = 26;
    +			container.style.opacity = 0;
    +			container.style.visibility = 'hidden';
    +
    +			if ( colorButtons ) {
    +				var palette = createPalette( chalks, colorButtons );
    +				container.appendChild( palette );
    +			}
    +			if ( boardHandle ) {
    +				var handle = document.createElement( 'div' );
    +				handle.classList.add( 'boardhandle' );
    +				handle.innerHTML = '
    '; + handle.querySelector( '#previousboard' ).addEventListener( 'click', function ( e ) { + e.preventDefault(); + switchBoard( board - 1 ); + } ); + handle.querySelector( '#nextboard' ).addEventListener( 'click', function ( e ) { + e.preventDefault(); + switchBoard( board + 1 ); + } ); + handle.querySelector( '#previousboard' ).addEventListener( 'touchstart', function ( e ) { + e.preventDefault(); + switchBoard( board - 1 ); + } ); + handle.querySelector( '#nextboard' ).addEventListener( 'touchstart', function ( e ) { + e.preventDefault(); + switchBoard( board + 1 ); + } ); + + container.appendChild( handle ); + } + } + + + var sponge = document.createElement( 'img' ); + sponge.src = eraser.src; + sponge.id = 'sponge'; + sponge.style.visibility = 'hidden'; + sponge.style.position = 'absolute'; + container.appendChild( sponge ); + drawingCanvas[ id ].sponge = sponge; + + var canvas = document.createElement( 'canvas' ); + canvas.width = drawingCanvas[ id ].width; + canvas.height = drawingCanvas[ id ].height; + canvas.setAttribute( 'data-chalkboard', id ); + canvas.style.cursor = pens[ id ][ color[ id ] ].cursor; + container.appendChild( canvas ); + drawingCanvas[ id ].canvas = canvas; + + drawingCanvas[ id ].context = canvas.getContext( '2d' ); + + setupCanvasEvents( container ); + + document.querySelector( '.reveal' ).appendChild( container ); + drawingCanvas[ id ].container = container; + } + + +/***************************************************************** + ** Storage + ******************************************************************/ + + var storage = [ { + width: Reveal.getConfig().width, + height: Reveal.getConfig().height, + data: [] + }, + { + width: Reveal.getConfig().width, + height: Reveal.getConfig().height, + data: [] + } + ]; + + var loaded = null; + + if ( config.storage ) { + // Get chalkboard drawings from session storage + loaded = initStorage( sessionStorage.getItem( config.storage ) ); + } + + if ( !loaded && config.src != null ) { + // Get chalkboard drawings from the given file + loadData( config.src ); + } + + /** + * Initialize storage. + */ + function initStorage( json ) { + var success = false; + try { + var data = JSON.parse( json ); + for ( var id = 0; id < data.length; id++ ) { + if ( drawingCanvas[ id ].width != data[ id ].width || drawingCanvas[ id ].height != data[ id ].height ) { + drawingCanvas[ id ].scale = Math.min( drawingCanvas[ id ].width / data[ id ].width, drawingCanvas[ id ].height / data[ id ].height ); + drawingCanvas[ id ].xOffset = ( drawingCanvas[ id ].width - data[ id ].width * drawingCanvas[ id ].scale ) / 2; + drawingCanvas[ id ].yOffset = ( drawingCanvas[ id ].height - data[ id ].height * drawingCanvas[ id ].scale ) / 2; + } + if ( config.readOnly ) { + drawingCanvas[ id ].container.style.cursor = 'default'; + drawingCanvas[ id ].canvas.style.cursor = 'default'; + } + } + success = true; + storage = data; + } catch ( err ) { + console.warn( "Cannot initialise storage!" ); + } + return success; + } + + + /** + * Load data. + */ + function loadData( filename ) { + var xhr = new XMLHttpRequest(); + xhr.onload = function () { + if ( xhr.readyState === 4 && xhr.status != 404 ) { + loaded = initStorage( xhr.responseText ); + updateStorage(); + console.log( "Drawings loaded from file" ); + } else { + config.readOnly = undefined; + readOnly = undefined; + console.warn( 'Failed to get file ' + filename + '. ReadyState: ' + xhr.readyState + ', Status: ' + xhr.status ); + loaded = false; + } + }; + + xhr.open( 'GET', filename, true ); + try { + xhr.send(); + } catch ( error ) { + config.readOnly = undefined; + readOnly = undefined; + console.warn( 'Failed to get file ' + filename + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + error ); + loaded = false; + } + } + + + function storageChanged( now ) { + if ( !now ) { + // create or update timer + if ( updateStorageTimeout ) { + clearTimeout( updateStorageTimeout ); + } + updateStorageTimeout = setTimeout( storageChanged, 1000, true); + } + else { +// console.log("Update storage", updateStorageTimeout, Date.now()); + updateStorage(); + updateStorageTimeout = null; + } + } + + function updateStorage() { + var json = JSON.stringify( storage ) + if ( config.storage ) { + sessionStorage.setItem( config.storage, json ) + } + return json; + } + + function recordEvent( event ) { +//console.log(event); + event.time = Date.now() - slideStart; + if ( mode == 1 ) event.board = board; + var slideData = getSlideData(); + var i = slideData.events.length; + while ( i > 0 && event.time < slideData.events[ i - 1 ].time ) { + i--; + } + slideData.events.splice( i, 0, event ); + slideData.duration = Math.max( slideData.duration, Date.now() - slideStart ) + 1; + + storageChanged(); + } + + /** + * Get data as json string. + */ + function getData() { + // cleanup slide data without events + for ( var id = 0; id < 2; id++ ) { + for ( var i = storage[ id ].data.length - 1; i >= 0; i-- ) { + if ( storage[ id ].data[ i ].events.length == 0 ) { + storage[ id ].data.splice( i, 1 ); + } + } + } + + return updateStorage(); + } + + /** + * Download data. + */ + function downloadData() { + var a = document.createElement( 'a' ); + document.body.appendChild( a ); + try { + a.download = 'chalkboard.json'; + var blob = new Blob( [ getData() ], { + type: 'application/json' + } ); + a.href = window.URL.createObjectURL( blob ); + } catch ( error ) { + a.innerHTML += ' (' + error + ')'; + } + a.click(); + document.body.removeChild( a ); + } + + /** + * Returns data object for the slide with the given indices. + */ + function getSlideData( indices, id ) { + if ( id == undefined ) id = mode; + if ( !indices ) indices = slideIndices; + var data; + for ( var i = 0; i < storage[ id ].data.length; i++ ) { + if ( storage[ id ].data[ i ].slide.h === indices.h && storage[ id ].data[ i ].slide.v === indices.v && storage[ id ].data[ i ].slide.f === indices.f ) { + data = storage[ id ].data[ i ]; + return data; + } + } + var page = Number( Reveal.getCurrentSlide().getAttribute('data-pdf-page-number') ); +//console.log( indices, Reveal.getCurrentSlide() ); + storage[ id ].data.push( { + slide: indices, + page, + events: [], + duration: 0 + } ); + data = storage[ id ].data[ storage[ id ].data.length - 1 ]; + return data; + } + + /** + * Returns maximum duration of slide playback for both modes + */ + function getSlideDuration( indices ) { + if ( !indices ) indices = slideIndices; + var duration = 0; + for ( var id = 0; id < 2; id++ ) { + for ( var i = 0; i < storage[ id ].data.length; i++ ) { + if ( storage[ id ].data[ i ].slide.h === indices.h && storage[ id ].data[ i ].slide.v === indices.v && storage[ id ].data[ i ].slide.f === indices.f ) { + duration = Math.max( duration, storage[ id ].data[ i ].duration ); + break; + } + } + } +//console.log( duration ); + return duration; + } + +/***************************************************************** + ** Print + ******************************************************************/ + var printMode = ( /print-pdf/gi ).test( window.location.search ); +//console.log("createPrintout" + printMode) + + function addPageNumbers() { + // determine page number for printouts with fragments serialised + var slides = Reveal.getSlides(); + var page = 0; + for ( var i=0; i < slides.length; i++) { + slides[i].setAttribute('data-pdf-page-number',page.toString()); + // add number of fragments without fragment indices + var count = slides[i].querySelectorAll('.fragment:not([data-fragment-index])').length; + var fragments = slides[i].querySelectorAll('.fragment[data-fragment-index]'); + for ( var j=0; j < fragments.length; j++) { + // increasenumber of fragments by highest fragment index (which start at 0) + if ( Number(fragments[j].getAttribute('data-fragment-index')) + 1 > count ) { + count = Number(fragments[j].getAttribute('data-fragment-index')) + 1; + } + } +//console.log(count,fragments.length,( slides[i].querySelector('h1,h2,h3,h4')||{}).innerHTML, page); + page += count + 1; + } + } + + function createPrintout() { + //console.warn(Reveal.getTotalSlides(),Reveal.getSlidesElement()); + if ( storage[ 1 ].data.length == 0 ) return; + console.log( 'Create printout(s) for ' + storage[ 1 ].data.length + " slides" ); + drawingCanvas[ 0 ].container.style.opacity = 0; // do not print notes canvas + drawingCanvas[ 0 ].container.style.visibility = 'hidden'; + + var patImg = new Image(); + patImg.onload = function () { + var slides = Reveal.getSlides(); +//console.log(slides); + for ( var i = storage[ 1 ].data.length - 1; i >= 0; i-- ) { + console.log( 'Create printout for slide ' + storage[ 1 ].data[ i ].slide.h + '.' + storage[ 1 ].data[ i ].slide.v ); + var slideData = getSlideData( storage[ 1 ].data[ i ].slide, 1 ); + var drawings = createDrawings( slideData, patImg ); +//console.log("Page:", storage[ 1 ].data[ i ].page ); +//console.log("Slide:", slides[storage[ 1 ].data[ i ].page] ); + addDrawings( slides[storage[ 1 ].data[ i ].page], drawings ); + + } +// Reveal.sync(); + }; + patImg.src = background[ 1 ]; + } + + + function cloneCanvas( oldCanvas ) { + //create a new canvas + var newCanvas = document.createElement( 'canvas' ); + var context = newCanvas.getContext( '2d' ); + //set dimensions + newCanvas.width = oldCanvas.width; + newCanvas.height = oldCanvas.height; + //apply the old canvas to the new one + context.drawImage( oldCanvas, 0, 0 ); + //return the new canvas + return newCanvas; + } + + function getCanvas( template, container, board ) { + var idx = container.findIndex( element => element.board === board ); + if ( idx === -1 ) { + var canvas = cloneCanvas( template ); + if ( !container.length ) { + idx = 0; + container.push( { + board, + canvas + } ); + } else if ( board < container[ 0 ].board ) { + idx = 0; + container.unshift( { + board, + canvas + } ); + } else if ( board > container[ container.length - 1 ].board ) { + idx = container.length; + container.push( { + board, + canvas + } ); + } + } + + return container[ idx ].canvas; + } + + function createDrawings( slideData, patImg ) { + var width = Reveal.getConfig().width; + var height = Reveal.getConfig().height; + var scale = 1; + var xOffset = 0; + var yOffset = 0; + if ( width != storage[ 1 ].width || height != storage[ 1 ].height ) { + scale = Math.min( width / storage[ 1 ].width, height / storage[ 1 ].height ); + xOffset = ( width - storage[ 1 ].width * scale ) / 2; + yOffset = ( height - storage[ 1 ].height * scale ) / 2; + } + mode = 1; + board = 0; +// console.log( 'Create printout(s) for slide ', slideData ); + + var drawings = []; + var template = document.createElement( 'canvas' ); + template.width = width; + template.height = height; + + var imgCtx = template.getContext( '2d' ); + imgCtx.fillStyle = imgCtx.createPattern( patImg, 'repeat' ); + imgCtx.rect( 0, 0, width, height ); + imgCtx.fill(); + + for ( var j = 0; j < slideData.events.length; j++ ) { + switch ( slideData.events[ j ].type ) { + case 'draw': + draw[ 1 ]( getCanvas( template, drawings, board ).getContext( '2d' ), + xOffset + slideData.events[ j ].x1 * scale, + yOffset + slideData.events[ j ].y1 * scale, + xOffset + slideData.events[ j ].x2 * scale, + yOffset + slideData.events[ j ].y2 * scale, + yOffset + slideData.events[ j ].color + ); + break; + case 'erase': + eraseWithSponge( getCanvas( template, drawings, board ).getContext( '2d' ), + xOffset + slideData.events[ j ].x * scale, + yOffset + slideData.events[ j ].y * scale + ); + break; + case 'selectboard': + selectBoard( slideData.events[ j ].board ); + break; + case 'clear': + getCanvas( template, drawings, board ).getContext( '2d' ).clearRect( 0, 0, width, height ); + getCanvas( template, drawings, board ).getContext( '2d' ).fill(); + break; + default: + break; + } + } + + drawings = drawings.sort( ( a, b ) => a.board > b.board && 1 || -1 ); + + mode = 0; + + return drawings; + } + + function addDrawings( slide, drawings ) { + var parent = slide.parentElement.parentElement; + var nextSlide = slide.parentElement.nextElementSibling; + + for ( var i = 0; i < drawings.length; i++ ) { + var newPDFPage = document.createElement( 'div' ); + newPDFPage.classList.add( 'pdf-page' ); + newPDFPage.style.height = Reveal.getConfig().height; + newPDFPage.append( drawings[ i ].canvas ); +//console.log("Add drawing", newPDFPage); + if ( nextSlide != null ) { + parent.insertBefore( newPDFPage, nextSlide ); + } else { + parent.append( newPDFPage ); + } + } + } + + /***************************************************************** + ** Drawings + ******************************************************************/ + + function drawWithBoardmarker( context, fromX, fromY, toX, toY, colorIdx ) { + if ( colorIdx == undefined ) colorIdx = color[ mode ]; + context.lineWidth = boardmarkerWidth; + context.lineCap = 'round'; + context.strokeStyle = boardmarkers[ colorIdx ].color; + context.beginPath(); + context.moveTo( fromX, fromY ); + context.lineTo( toX, toY ); + context.stroke(); + } + + function drawWithChalk( context, fromX, fromY, toX, toY, colorIdx ) { + if ( colorIdx == undefined ) colorIdx = color[ mode ]; + var brushDiameter = chalkWidth; + context.lineWidth = brushDiameter; + context.lineCap = 'round'; + context.fillStyle = chalks[ colorIdx ].color; // 'rgba(255,255,255,0.5)'; + context.strokeStyle = chalks[ colorIdx ].color; + /*var opacity = Math.min(0.8, Math.max(0,color[1].replace(/^.*,(.+)\)/,'$1') - 0.1)) + Math.random()*0.2;*/ + var opacity = 1.0; + context.strokeStyle = context.strokeStyle.replace( /[\d\.]+\)$/g, opacity + ')' ); + context.beginPath(); + context.moveTo( fromX, fromY ); + context.lineTo( toX, toY ); + context.stroke(); + // Chalk Effect + var length = Math.round( Math.sqrt( Math.pow( toX - fromX, 2 ) + Math.pow( toY - fromY, 2 ) ) / ( 5 / brushDiameter ) ); + var xUnit = ( toX - fromX ) / length; + var yUnit = ( toY - fromY ) / length; + for ( var i = 0; i < length; i++ ) { + if ( chalkEffect > ( Math.random() * 0.9 ) ) { + var xCurrent = fromX + ( i * xUnit ); + var yCurrent = fromY + ( i * yUnit ); + var xRandom = xCurrent + ( Math.random() - 0.5 ) * brushDiameter * 1.2; + var yRandom = yCurrent + ( Math.random() - 0.5 ) * brushDiameter * 1.2; + context.clearRect( xRandom, yRandom, Math.random() * 2 + 2, Math.random() + 1 ); + } + } + } + + function eraseWithSponge( context, x, y ) { + context.save(); + context.beginPath(); + context.arc( x, y, eraser.radius, 0, 2 * Math.PI, false ); + context.clip(); + context.clearRect( x - eraser.radius - 1, y - eraser.radius - 1, eraser.radius * 2 + 2, eraser.radius * 2 + 2 ); + context.restore(); + if ( mode == 1 && grid ) { + redrawGrid( x, y, eraser.radius ); + } + } + + + /** + * Show an overlay for the chalkboard. + */ + function showChalkboard() { +//console.log("showChalkboard"); + clearTimeout( touchTimeout ); + touchTimeout = null; + drawingCanvas[ 0 ].sponge.style.visibility = 'hidden'; // make sure that the sponge from touch events is hidden + drawingCanvas[ 1 ].sponge.style.visibility = 'hidden'; // make sure that the sponge from touch events is hidden + drawingCanvas[ 1 ].container.style.opacity = 1; + drawingCanvas[ 1 ].container.style.visibility = 'visible'; + mode = 1; + } + + + /** + * Closes open chalkboard. + */ + function closeChalkboard() { + clearTimeout( touchTimeout ); + touchTimeout = null; + drawingCanvas[ 0 ].sponge.style.visibility = 'hidden'; // make sure that the sponge from touch events is hidden + drawingCanvas[ 1 ].sponge.style.visibility = 'hidden'; // make sure that the sponge from touch events is hidden + drawingCanvas[ 1 ].container.style.opacity = 0; + drawingCanvas[ 1 ].container.style.visibility = 'hidden'; + lastX = null; + lastY = null; + mode = 0; + } + + /** + * Clear current canvas. + */ + function clearCanvas( id ) { + if ( id == 0 ) clearTimeout( slidechangeTimeout ); + drawingCanvas[ id ].context.clearRect( 0, 0, drawingCanvas[ id ].width, drawingCanvas[ id ].height ); + if ( id == 1 && grid ) drawGrid(); + } + + /** + * Draw grid on background + */ + function drawGrid() { + var context = drawingCanvas[ 1 ].context; + + drawingCanvas[ 1 ].scale = Math.min( drawingCanvas[ 1 ].width / storage[ 1 ].width, drawingCanvas[ 1 ].height / storage[ 1 ].height ); + drawingCanvas[ 1 ].xOffset = ( drawingCanvas[ 1 ].width - storage[ 1 ].width * drawingCanvas[ 1 ].scale ) / 2; + drawingCanvas[ 1 ].yOffset = ( drawingCanvas[ 1 ].height - storage[ 1 ].height * drawingCanvas[ 1 ].scale ) / 2; + + var scale = drawingCanvas[ 1 ].scale; + var xOffset = drawingCanvas[ 1 ].xOffset; + var yOffset = drawingCanvas[ 1 ].yOffset; + + var distance = grid.distance * scale; + + var fromX = drawingCanvas[ 1 ].width / 2 - distance / 2 - Math.floor( ( drawingCanvas[ 1 ].width - distance ) / 2 / distance ) * distance; + for ( var x = fromX; x < drawingCanvas[ 1 ].width; x += distance ) { + context.beginPath(); + context.lineWidth = grid.width * scale; + context.lineCap = 'round'; + context.fillStyle = grid.color; + context.strokeStyle = grid.color; + context.moveTo( x, 0 ); + context.lineTo( x, drawingCanvas[ 1 ].height ); + context.stroke(); + } + var fromY = drawingCanvas[ 1 ].height / 2 - distance / 2 - Math.floor( ( drawingCanvas[ 1 ].height - distance ) / 2 / distance ) * distance; + + for ( var y = fromY; y < drawingCanvas[ 1 ].height; y += distance ) { + context.beginPath(); + context.lineWidth = grid.width * scale; + context.lineCap = 'round'; + context.fillStyle = grid.color; + context.strokeStyle = grid.color; + context.moveTo( 0, y ); + context.lineTo( drawingCanvas[ 1 ].width, y ); + context.stroke(); + } + } + + function redrawGrid( centerX, centerY, diameter ) { + var context = drawingCanvas[ 1 ].context; + + drawingCanvas[ 1 ].scale = Math.min( drawingCanvas[ 1 ].width / storage[ 1 ].width, drawingCanvas[ 1 ].height / storage[ 1 ].height ); + drawingCanvas[ 1 ].xOffset = ( drawingCanvas[ 1 ].width - storage[ 1 ].width * drawingCanvas[ 1 ].scale ) / 2; + drawingCanvas[ 1 ].yOffset = ( drawingCanvas[ 1 ].height - storage[ 1 ].height * drawingCanvas[ 1 ].scale ) / 2; + + var scale = drawingCanvas[ 1 ].scale; + var xOffset = drawingCanvas[ 1 ].xOffset; + var yOffset = drawingCanvas[ 1 ].yOffset; + + var distance = grid.distance * scale; + + var fromX = drawingCanvas[ 1 ].width / 2 - distance / 2 - Math.floor( ( drawingCanvas[ 1 ].width - distance ) / 2 / distance ) * distance; + + for ( var x = fromX + distance * Math.ceil( ( centerX - diameter - fromX ) / distance ); x <= fromX + distance * Math.floor( ( centerX + diameter - fromX ) / distance ); x += distance ) { + context.beginPath(); + context.lineWidth = grid.width * scale; + context.lineCap = 'round'; + context.fillStyle = grid.color; + context.strokeStyle = grid.color; + context.moveTo( x, centerY - Math.sqrt( diameter * diameter - ( centerX - x ) * ( centerX - x ) ) ); + context.lineTo( x, centerY + Math.sqrt( diameter * diameter - ( centerX - x ) * ( centerX - x ) ) ); + context.stroke(); + } + var fromY = drawingCanvas[ 1 ].height / 2 - distance / 2 - Math.floor( ( drawingCanvas[ 1 ].height - distance ) / 2 / distance ) * distance; + for ( var y = fromY + distance * Math.ceil( ( centerY - diameter - fromY ) / distance ); y <= fromY + distance * Math.floor( ( centerY + diameter - fromY ) / distance ); y += distance ) { + context.beginPath(); + context.lineWidth = grid.width * scale; + context.lineCap = 'round'; + context.fillStyle = grid.color; + context.strokeStyle = grid.color; + context.moveTo( centerX - Math.sqrt( diameter * diameter - ( centerY - y ) * ( centerY - y ) ), y ); + context.lineTo( centerX + Math.sqrt( diameter * diameter - ( centerY - y ) * ( centerY - y ) ), y ); + context.stroke(); + } + } + + /** + * Set the color + */ + function setColor( index, record ) { + // protect against out of bounds (this could happen when + // replaying events recorded with different color settings). + if ( index >= pens[ mode ].length ) index = 0; + color[ mode ] = index; + drawingCanvas[ mode ].canvas.style.cursor = pens[ mode ][ color[ mode ] ].cursor; + } + + /** + * Set the board + */ + function selectBoard( boardIdx, record ) { +//console.log("Set board",boardIdx); + if ( board == boardIdx ) return; + + board = boardIdx; + redrawChalkboard( boardIdx ); + if ( record ) { + recordEvent( { type: 'selectboard' } ); + } + } + + function redrawChalkboard( boardIdx ) { + clearCanvas( 1 ); + var slideData = getSlideData( slideIndices, 1 ); + var index = 0; + var play = ( boardIdx == 0 ); + while ( index < slideData.events.length && slideData.events[ index ].time < Date.now() - slideStart ) { + if ( boardIdx == slideData.events[ index ].board ) { + playEvent( 1, slideData.events[ index ], Date.now() - slideStart ); + } + + index++; + } + } + + + /** + * Forward cycle color + */ + function cycleColorNext() { + color[ mode ] = ( color[ mode ] + 1 ) % pens[ mode ].length; + return color[ mode ]; + } + + /** + * Backward cycle color + */ + function cycleColorPrev() { + color[ mode ] = ( color[ mode ] + ( pens[ mode ].length - 1 ) ) % pens[ mode ].length; + return color[ mode ]; + } + +/***************************************************************** + ** Broadcast + ******************************************************************/ + + var eventQueue = []; + + document.addEventListener( 'received', function ( message ) { + if ( message.content && message.content.sender == 'chalkboard-plugin' ) { + // add message to queue + eventQueue.push( message ); + console.log( JSON.stringify( message ) ); + } + if ( eventQueue.length == 1 ) processQueue(); + } ); + + function processQueue() { + // take first message from queue + var message = eventQueue.shift(); + + // synchronize time with seminar host + slideStart = Date.now() - message.content.timestamp; + // set status + if ( mode < message.content.mode ) { + // open chalkboard + showChalkboard(); + } else if ( mode > message.content.mode ) { + // close chalkboard + closeChalkboard(); + } + if ( board != message.content.board ) { + board = message.content.board; + redrawChalkboard( board ); + }; + + switch ( message.content.type ) { + case 'showChalkboard': + showChalkboard(); + break; + case 'closeChalkboard': + closeChalkboard(); + break; + case 'erase': + erasePoint( message.content.x, message.content.y ); + break; + case 'draw': + drawSegment( message.content.fromX, message.content.fromY, message.content.toX, message.content.toY, message.content.color ); + break; + case 'clear': + clearSlide(); + break; + case 'selectboard': + selectBoard( message.content.board, true ); + break; + case 'resetSlide': + resetSlideDrawings(); + break; + case 'init': + storage = message.content.storage; + for ( var id = 0; id < 2; id++ ) { + drawingCanvas[ id ].scale = Math.min( drawingCanvas[ id ].width / storage[ id ].width, drawingCanvas[ id ].height / storage[ id ].height ); + drawingCanvas[ id ].xOffset = ( drawingCanvas[ id ].width - storage[ id ].width * drawingCanvas[ id ].scale ) / 2; + drawingCanvas[ id ].yOffset = ( drawingCanvas[ id ].height - storage[ id ].height * drawingCanvas[ id ].scale ) / 2; + } + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( !playback ) { + slidechangeTimeout = setTimeout( startPlayback, transition, getSlideDuration(), 0 ); + } + if ( mode == 1 && message.content.mode == 0 ) { + setTimeout( closeChalkboard, transition + 50 ); + } + if ( mode == 0 && message.content.mode == 1 ) { + setTimeout( showChalkboard, transition + 50 ); + } + mode = message.content.mode; + board = message.content.board; + break; + default: + break; + } + + // continue with next message if queued + if ( eventQueue.length > 0 ) { + processQueue(); + } else { + storageChanged(); + } + } + + document.addEventListener( 'welcome', function ( user ) { + // broadcast storage + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + recipient: user.id, + type: 'init', + timestamp: Date.now() - slideStart, + storage: storage, + mode, + board + }; + document.dispatchEvent( message ); + } ); + + /***************************************************************** + ** Playback + ******************************************************************/ + + document.addEventListener( 'seekplayback', function ( event ) { +//console.log('event seekplayback ' + event.timestamp); + stopPlayback(); + if ( !playback || event.timestamp == 0 ) { + // in other cases startplayback fires after seeked + startPlayback( event.timestamp ); + } + //console.log('seeked'); + } ); + + + document.addEventListener( 'startplayback', function ( event ) { +//console.log('event startplayback ' + event.timestamp); + stopPlayback(); + playback = true; + startPlayback( event.timestamp ); + } ); + + document.addEventListener( 'stopplayback', function ( event ) { +//console.log('event stopplayback ' + (Date.now() - slideStart) ); + playback = false; + stopPlayback(); + } ); + + document.addEventListener( 'startrecording', function ( event ) { +//console.log('event startrecording ' + event.timestamp); + startRecording(); + } ); + + + function startRecording() { + resetSlide( true ); + slideStart = Date.now(); + } + + function startPlayback( timestamp, finalMode ) { +//console.log("playback " + timestamp ); + slideStart = Date.now() - timestamp; + closeChalkboard(); + mode = 0; + board = 0; + for ( var id = 0; id < 2; id++ ) { + clearCanvas( id ); + var slideData = getSlideData( slideIndices, id ); +//console.log( timestamp +" / " + JSON.stringify(slideData)); + var index = 0; + while ( index < slideData.events.length && slideData.events[ index ].time < ( Date.now() - slideStart ) ) { + playEvent( id, slideData.events[ index ], timestamp ); + index++; + } + + while ( playback && index < slideData.events.length ) { + timeouts[ id ].push( setTimeout( playEvent, slideData.events[ index ].time - ( Date.now() - slideStart ), id, slideData.events[ index ], timestamp ) ); + index++; + } + } +//console.log("Mode: " + finalMode + "/" + mode ); + if ( finalMode != undefined ) { + mode = finalMode; + } + if ( mode == 1 ) showChalkboard(); +//console.log("playback (ok)"); + + }; + + function stopPlayback() { +//console.log("stopPlayback"); +//console.log("Timeouts: " + timeouts[0].length + "/"+ timeouts[1].length); + for ( var id = 0; id < 2; id++ ) { + for ( var i = 0; i < timeouts[ id ].length; i++ ) { + clearTimeout( timeouts[ id ][ i ] ); + } + timeouts[ id ] = []; + } + }; + + function playEvent( id, event, timestamp ) { +//console.log( timestamp +" / " + JSON.stringify(event)); +//console.log( id + ": " + timestamp +" / " + event.time +" / " + event.type +" / " + mode ); + switch ( event.type ) { + case 'open': + if ( timestamp <= event.time ) { + showChalkboard(); + } else { + mode = 1; + } + + break; + case 'close': + if ( timestamp < event.time ) { + closeChalkboard(); + } else { + mode = 0; + } + break; + case 'clear': + clearCanvas( id ); + break; + case 'selectboard': + selectBoard( event.board ); + break; + case 'draw': + drawLine( id, event, timestamp ); + break; + case 'erase': + eraseCircle( id, event, timestamp ); + break; + } + }; + + function drawLine( id, event, timestamp ) { + var ctx = drawingCanvas[ id ].context; + var scale = drawingCanvas[ id ].scale; + var xOffset = drawingCanvas[ id ].xOffset; + var yOffset = drawingCanvas[ id ].yOffset; + draw[ id ]( ctx, xOffset + event.x1 * scale, yOffset + event.y1 * scale, xOffset + event.x2 * scale, yOffset + event.y2 * scale, event.color ); + }; + + function eraseCircle( id, event, timestamp ) { + var ctx = drawingCanvas[ id ].context; + var scale = drawingCanvas[ id ].scale; + var xOffset = drawingCanvas[ id ].xOffset; + var yOffset = drawingCanvas[ id ].yOffset; + + eraseWithSponge( ctx, xOffset + event.x * scale, yOffset + event.y * scale ); + }; + + function startErasing( x, y ) { + drawing = false; + erasing = true; + drawingCanvas[ mode ].sponge.style.visibility = 'visible'; + erasePoint( x, y ); + } + + function erasePoint( x, y ) { + var ctx = drawingCanvas[ mode ].context; + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + // move sponge image + drawingCanvas[ mode ].sponge.style.left = ( x * scale + xOffset - eraser.radius ) + 'px'; + drawingCanvas[ mode ].sponge.style.top = ( y * scale + yOffset - 2 * eraser.radius ) + 'px'; + + recordEvent( { + type: 'erase', + x, + y + } ); + + if ( + x * scale + xOffset > 0 && + y * scale + yOffset > 0 && + x * scale + xOffset < drawingCanvas[ mode ].width && + y * scale + yOffset < drawingCanvas[ mode ].height + ) { + eraseWithSponge( ctx, x * scale + xOffset, y * scale + yOffset ); + } + } + + function stopErasing() { + erasing = false; + // hide sponge + drawingCanvas[ mode ].sponge.style.visibility = 'hidden'; + } + + function startDrawing( x, y ) { + drawing = true; + + var ctx = drawingCanvas[ mode ].context; + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + lastX = x * scale + xOffset; + lastY = y * scale + yOffset; + } + + function drawSegment( fromX, fromY, toX, toY, colorIdx ) { + var ctx = drawingCanvas[ mode ].context; + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + recordEvent( { + type: 'draw', + color: colorIdx, + x1: fromX, + y1: fromY, + x2: toX, + y2: toY + } ); + + if ( + fromX * scale + xOffset > 0 && + fromY * scale + yOffset > 0 && + fromX * scale + xOffset < drawingCanvas[ mode ].width && + fromY * scale + yOffset < drawingCanvas[ mode ].height && + toX * scale + xOffset > 0 && + toY * scale + yOffset > 0 && + toX * scale + xOffset < drawingCanvas[ mode ].width && + toY * scale + yOffset < drawingCanvas[ mode ].height + ) { + draw[ mode ]( ctx, fromX * scale + xOffset, fromY * scale + yOffset, toX * scale + xOffset, toY * scale + yOffset, colorIdx ); + } + } + + function stopDrawing() { + drawing = false; + } + + +/***************************************************************** + ** User interface + ******************************************************************/ + + function setupCanvasEvents( canvas ) { +// TODO: check all touchevents + canvas.addEventListener( 'touchstart', function ( evt ) { + evt.preventDefault(); +//console.log("Touch start"); + if ( !readOnly && evt.target.getAttribute( 'data-chalkboard' ) == mode ) { + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + var touch = evt.touches[ 0 ]; + mouseX = touch.pageX; + mouseY = touch.pageY; + startDrawing( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + touchTimeout = setTimeout( startErasing, 500, ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + } + }, passiveSupported ? { + passive: false + } : false ); + + canvas.addEventListener( 'touchmove', function ( evt ) { + evt.preventDefault(); +//console.log("Touch move"); + clearTimeout( touchTimeout ); + touchTimeout = null; + if ( drawing || erasing ) { + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + var touch = evt.touches[ 0 ]; + mouseX = touch.pageX; + mouseY = touch.pageY; + if ( mouseY < drawingCanvas[ mode ].height && mouseX < drawingCanvas[ mode ].width ) { + // move sponge + if ( event.type == 'erase' ) { + drawingCanvas[ mode ].sponge.style.left = ( mouseX - eraser.radius ) + 'px'; + drawingCanvas[ mode ].sponge.style.top = ( mouseY - eraser.radius ) + 'px'; + } + } + + if ( drawing ) { + drawSegment( ( lastX - xOffset ) / scale, ( lastY - yOffset ) / scale, ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale, color[ mode ] ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'draw', + timestamp: Date.now() - slideStart, + mode, + board, + fromX: ( lastX - xOffset ) / scale, + fromY: ( lastY - yOffset ) / scale, + toX: ( mouseX - xOffset ) / scale, + toY: ( mouseY - yOffset ) / scale, + color: color[ mode ] + }; + document.dispatchEvent( message ); + + lastX = mouseX; + lastY = mouseY; + } else { + erasePoint( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'erase', + timestamp: Date.now() - slideStart, + mode, + board, + x: ( mouseX - xOffset ) / scale, + y: ( mouseY - yOffset ) / scale + }; + document.dispatchEvent( message ); + } + + } + }, false ); + + + canvas.addEventListener( 'touchend', function ( evt ) { + evt.preventDefault(); + clearTimeout( touchTimeout ); + touchTimeout = null; + // hide sponge image + drawingCanvas[ mode ].sponge.style.visibility = 'hidden'; + stopDrawing(); + }, false ); + + canvas.addEventListener( 'mousedown', function ( evt ) { + evt.preventDefault(); + if ( !readOnly && evt.target.getAttribute( 'data-chalkboard' ) == mode ) { +//console.log( "mousedown: " + evt.button ); + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + mouseX = evt.pageX; + mouseY = evt.pageY; + + if ( evt.button == 2 || evt.button == 1 ) { + startErasing( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'erase', + timestamp: Date.now() - slideStart, + mode, + board, + x: ( mouseX - xOffset ) / scale, + y: ( mouseY - yOffset ) / scale + }; + document.dispatchEvent( message ); + } else { + startDrawing( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + } + } + } ); + + canvas.addEventListener( 'mousemove', function ( evt ) { + evt.preventDefault(); +//console.log("Mouse move"); + if ( drawing || erasing ) { + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + mouseX = evt.pageX; + mouseY = evt.pageY; + + if ( drawing ) { + drawSegment( ( lastX - xOffset ) / scale, ( lastY - yOffset ) / scale, ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale, color[ mode ] ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'draw', + timestamp: Date.now() - slideStart, + mode, + board, + fromX: ( lastX - xOffset ) / scale, + fromY: ( lastY - yOffset ) / scale, + toX: ( mouseX - xOffset ) / scale, + toY: ( mouseY - yOffset ) / scale, + color: color[ mode ] + }; + document.dispatchEvent( message ); + + lastX = mouseX; + lastY = mouseY; + } else { + erasePoint( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'erase', + timestamp: Date.now() - slideStart, + mode, + board, + x: ( mouseX - xOffset ) / scale, + y: ( mouseY - yOffset ) / scale + }; + document.dispatchEvent( message ); + } + + } + } ); + + + canvas.addEventListener( 'mouseup', function ( evt ) { + evt.preventDefault(); + drawingCanvas[ mode ].canvas.style.cursor = pens[ mode ][ color[ mode ] ].cursor; + if ( drawing || erasing ) { + stopDrawing(); + stopErasing(); + } + } ); + } + + function resize() { +//console.log("resize"); + // Resize the canvas and draw everything again + var timestamp = Date.now() - slideStart; + if ( !playback ) { + timestamp = getSlideDuration(); + } + +//console.log( drawingCanvas[0].scale + "/" + drawingCanvas[0].xOffset + "/" +drawingCanvas[0].yOffset ); + for ( var id = 0; id < 2; id++ ) { + drawingCanvas[ id ].width = window.innerWidth; + drawingCanvas[ id ].height = window.innerHeight; + drawingCanvas[ id ].canvas.width = drawingCanvas[ id ].width; + drawingCanvas[ id ].canvas.height = drawingCanvas[ id ].height; + drawingCanvas[ id ].context.canvas.width = drawingCanvas[ id ].width; + drawingCanvas[ id ].context.canvas.height = drawingCanvas[ id ].height; + + drawingCanvas[ id ].scale = Math.min( drawingCanvas[ id ].width / storage[ id ].width, drawingCanvas[ id ].height / storage[ id ].height ); + drawingCanvas[ id ].xOffset = ( drawingCanvas[ id ].width - storage[ id ].width * drawingCanvas[ id ].scale ) / 2; + drawingCanvas[ id ].yOffset = ( drawingCanvas[ id ].height - storage[ id ].height * drawingCanvas[ id ].scale ) / 2; +//console.log( drawingCanvas[id].scale + "/" + drawingCanvas[id].xOffset + "/" +drawingCanvas[id].yOffset ); + } +//console.log( window.innerWidth + "/" + window.innerHeight); + startPlayback( timestamp, mode, true ); + } + + Reveal.addEventListener( 'pdf-ready', function ( evt ) { +// console.log( "Create printouts when ready" ); + whenLoaded( createPrintout ); + }); + + Reveal.addEventListener( 'ready', function ( evt ) { +//console.log('ready'); + if ( !printMode ) { + window.addEventListener( 'resize', resize ); + + slideStart = Date.now() - getSlideDuration(); + slideIndices = Reveal.getIndices(); + if ( !playback ) { + startPlayback( getSlideDuration(), 0 ); + } + if ( Reveal.isAutoSliding() ) { + var event = new CustomEvent( 'startplayback' ); + event.timestamp = 0; + document.dispatchEvent( event ); + } + updateStorage(); + whenReady( addPageNumbers ); + } + } ); + Reveal.addEventListener( 'slidechanged', function ( evt ) { +// clearTimeout( slidechangeTimeout ); +//console.log('slidechanged'); + if ( !printMode ) { + slideStart = Date.now() - getSlideDuration(); + slideIndices = Reveal.getIndices(); + closeChalkboard(); + board = 0; + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( !playback ) { + slidechangeTimeout = setTimeout( startPlayback, transition, getSlideDuration(), 0 ); + } + if ( Reveal.isAutoSliding() ) { + var event = new CustomEvent( 'startplayback' ); + event.timestamp = 0; + document.dispatchEvent( event ); + } + } + } ); + Reveal.addEventListener( 'fragmentshown', function ( evt ) { +// clearTimeout( slidechangeTimeout ); +//console.log('fragmentshown'); + if ( !printMode ) { + slideStart = Date.now() - getSlideDuration(); + slideIndices = Reveal.getIndices(); + closeChalkboard(); + board = 0; + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( Reveal.isAutoSliding() ) { + var event = new CustomEvent( 'startplayback' ); + event.timestamp = 0; + document.dispatchEvent( event ); + } else if ( !playback ) { + startPlayback( getSlideDuration(), 0 ); +// closeChalkboard(); + } + } + } ); + Reveal.addEventListener( 'fragmenthidden', function ( evt ) { +// clearTimeout( slidechangeTimeout ); +//console.log('fragmenthidden'); + if ( !printMode ) { + slideStart = Date.now() - getSlideDuration(); + slideIndices = Reveal.getIndices(); + closeChalkboard(); + board = 0; + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( Reveal.isAutoSliding() ) { + document.dispatchEvent( new CustomEvent( 'stopplayback' ) ); + } else if ( !playback ) { + startPlayback( getSlideDuration() ); + closeChalkboard(); + } + } + } ); + + Reveal.addEventListener( 'autoslideresumed', function ( evt ) { +//console.log('autoslideresumed'); + var event = new CustomEvent( 'startplayback' ); + event.timestamp = 0; + document.dispatchEvent( event ); + } ); + Reveal.addEventListener( 'autoslidepaused', function ( evt ) { +//console.log('autoslidepaused'); + document.dispatchEvent( new CustomEvent( 'stopplayback' ) ); + + // advance to end of slide +// closeChalkboard(); + startPlayback( getSlideDuration(), 0 ); + } ); + + function toggleNotesCanvas() { + if ( !readOnly ) { + if ( mode == 1 ) { + toggleChalkboard(); + notescanvas.style.background = background[ 0 ]; //'rgba(255,0,0,0.5)'; + notescanvas.style.pointerEvents = 'auto'; + } + else { + if ( notescanvas.style.pointerEvents != 'none' ) { + // hide notes canvas + if ( colorButtons ) { + notescanvas.querySelector( '.palette' ).style.visibility = 'hidden'; + } + notescanvas.style.background = 'rgba(0,0,0,0)'; + notescanvas.style.pointerEvents = 'none'; + } + else { + // show notes canvas + if ( colorButtons ) { + notescanvas.querySelector( '.palette' ).style.visibility = 'visible'; + } + notescanvas.style.background = background[ 0 ]; //'rgba(255,0,0,0.5)'; + notescanvas.style.pointerEvents = 'auto'; + + var idx = 0; + if ( color[ mode ] ) { + idx = color[ mode ]; + } + + setColor( idx, true ); + } + } + } + }; + + function toggleChalkboard() { +//console.log("toggleChalkboard " + mode); + if ( mode == 1 ) { + if ( !readOnly ) { + recordEvent( { type: 'close' } ); + } + closeChalkboard(); + + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'closeChalkboard', + timestamp: Date.now() - slideStart, + mode: 0, + board + }; + document.dispatchEvent( message ); + + + } else { + showChalkboard(); + if ( !readOnly ) { + recordEvent( { type: 'open' } ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'showChalkboard', + timestamp: Date.now() - slideStart, + mode: 1, + board + }; + document.dispatchEvent( message ); + + var idx = 0; + + if ( rememberColor[ mode ] ) { + idx = color[ mode ]; + } + + setColor( idx, true ); + } + } + }; + + function clearSlide() { + recordEvent( { type: 'clear' } ); + clearCanvas( mode ); + } + + function clear() { + if ( !readOnly ) { + clearSlide(); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'clear', + timestamp: Date.now() - slideStart, + mode, + board + }; + document.dispatchEvent( message ); + } + }; + + function colorIndex( idx ) { + if ( !readOnly ) { + setColor( idx, true ); + } + } + + function colorNext() { + if ( !readOnly ) { + let idx = cycleColorNext(); + setColor( idx, true ); + } + } + + function colorPrev() { + if ( !readOnly ) { + let idx = cycleColorPrev(); + setColor( idx, true ); + } + } + + function resetSlideDrawings() { + slideStart = Date.now(); + closeChalkboard(); + + clearCanvas( 0 ); + clearCanvas( 1 ); + + mode = 1; + var slideData = getSlideData(); + slideData.duration = 0; + slideData.events = []; + mode = 0; + var slideData = getSlideData(); + slideData.duration = 0; + slideData.events = []; + + updateStorage(); + } + + function resetSlide( force ) { + var ok = force || confirm( "Please confirm to delete chalkboard drawings on this slide!" ); + if ( ok ) { +//console.log("resetSlide "); + stopPlayback(); + resetSlideDrawings(); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'resetSlide', + timestamp: Date.now() - slideStart, + mode, + board + }; + document.dispatchEvent( message ); + } + }; + + function resetStorage( force ) { + var ok = force || confirm( "Please confirm to delete all chalkboard drawings!" ); + if ( ok ) { + stopPlayback(); + slideStart = Date.now(); + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( mode == 1 ) { + closeChalkboard(); + } + + storage = [ { + width: Reveal.getConfig().width, + height: Reveal.getConfig().height, + data: [] + }, + { + width: Reveal.getConfig().width, + height: Reveal.getConfig().height, + data: [] + } + ]; + + if ( config.storage ) { + sessionStorage.setItem( config.storage, null ) + } + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'init', + timestamp: Date.now() - slideStart, + storage, + mode, + board + }; + document.dispatchEvent( message ); + } + }; + + this.toggleNotesCanvas = toggleNotesCanvas; + this.toggleChalkboard = toggleChalkboard; + this.colorIndex = colorIndex; + this.colorNext = colorNext; + this.colorPrev = colorPrev; + this.clear = clear; + this.reset = resetSlide; + this.resetAll = resetStorage; + this.download = downloadData; + this.updateStorage = updateStorage; + this.getData = getData; + this.configure = configure; + + + for ( var key in keyBindings ) { + if ( keyBindings[ key ] ) { + Reveal.addKeyBinding( keyBindings[ key ], RevealChalkboard[ key ] ); + } + }; + + return this; +}; diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/plugin.yml b/2311/site_libs/revealjs/plugin/reveal-chalkboard/plugin.yml new file mode 100644 index 00000000..b0568c26 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/plugin.yml @@ -0,0 +1,7 @@ +name: RevealChalkboard +script: plugin.js +stylesheet: ["font-awesome/css/all.css", "style.css"] +self-contained: false +config: + chalkboard: + buttons: true diff --git a/2311/site_libs/revealjs/plugin/reveal-chalkboard/style.css b/2311/site_libs/revealjs/plugin/reveal-chalkboard/style.css new file mode 100644 index 00000000..08765e73 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/reveal-chalkboard/style.css @@ -0,0 +1,44 @@ +div.palette, div.boardhandle { + position: absolute; +/* + height: 260px; + margin: -130px 0 0 0px; +*/ + top: 50%; + transform: translateY(-50%); + font-size: 24px; + border-radius: 10px; + border-top: 4px solid #222; + border-right: 4px solid #222; + border-bottom: 4px solid #222; + background: black; + transition: transform 0.3s; +} + +div.palette { + left: -10px; + padding-left:10px; +} + +div.boardhandle { + right: -10px; + padding-right:10px; +} + +div.palette > ul, +div.boardhandle > ul { + list-style-type: none; + margin: 0; + padding: 0; +} + +div.palette > ul > li, +div.boardhandle > ul > li { + margin: 10px; +} + +@media print { + div.palette, div.boardhandle, .chalkboard-button { + display: none!important; + } +} diff --git a/2311/site_libs/revealjs/plugin/reveal-menu/menu.css b/2311/site_libs/revealjs/plugin/reveal-menu/menu.css new file mode 100644 index 00000000..5a300fdf --- /dev/null +++ b/2311/site_libs/revealjs/plugin/reveal-menu/menu.css @@ -0,0 +1,346 @@ +.slide-menu-wrapper { + font-family: 'Source Sans Pro', Helvetica, sans-serif; +} + +.slide-menu-wrapper .slide-menu { + background-color: #333; + z-index: 200; + position: fixed; + top: 0; + width: 300px; + height: 100%; + /*overflow-y: scroll;*/ + transition: transform 0.3s; + font-size: 16px; + font-weight: normal; +} + +.slide-menu-wrapper .slide-menu.slide-menu--wide { + width: 500px; +} + +.slide-menu-wrapper .slide-menu.slide-menu--third { + width: 33%; +} + +.slide-menu-wrapper .slide-menu.slide-menu--half { + width: 50%; +} + +.slide-menu-wrapper .slide-menu.slide-menu--full { + width: 95%; +} + +/* + * Slides menu + */ + +.slide-menu-wrapper .slide-menu-items { + margin: 0; + padding: 0; + width: 100%; + border-bottom: solid 1px #555; +} + +.slide-menu-wrapper .slide-menu-item, +.slide-menu-wrapper .slide-menu-item-vertical { + display: block; + text-align: left; + padding: 10px 18px; + color: #aaa; + cursor: pointer; +} + +.slide-menu-wrapper .slide-menu-item-vertical { + padding-left: 30px; +} + +.slide-menu-wrapper .slide-menu--wide .slide-menu-item-vertical, +.slide-menu-wrapper .slide-menu--third .slide-menu-item-vertical, +.slide-menu-wrapper .slide-menu--half .slide-menu-item-vertical, +.slide-menu-wrapper .slide-menu--full .slide-menu-item-vertical, +.slide-menu-wrapper .slide-menu--custom .slide-menu-item-vertical { + padding-left: 50px; +} + +.slide-menu-wrapper .slide-menu-item { + border-top: solid 1px #555; +} + +.slide-menu-wrapper .active-menu-panel li.selected { + background-color: #222; + color: white; +} + +.slide-menu-wrapper .active-menu-panel li.active { + color: #eee; +} + +.slide-menu-wrapper .slide-menu-item.no-title .slide-menu-item-title, +.slide-menu-wrapper .slide-menu-item-vertical.no-title .slide-menu-item-title { + font-style: italic; +} + +.slide-menu-wrapper .slide-menu-item-number { + color: #999; + padding-right: 6px; +} + +.slide-menu-wrapper .slide-menu-item i.far, +.slide-menu-wrapper .slide-menu-item i.fas, +.slide-menu-wrapper .slide-menu-item-vertical i.far, +.slide-menu-wrapper .slide-menu-item-vertical i.fas, +.slide-menu-wrapper .slide-menu-item svg.svg-inline--fa, +.slide-menu-wrapper .slide-menu-item-vertical svg.svg-inline--fa { + padding-right: 12px; + display: none; +} + +.slide-menu-wrapper .slide-menu-item.past i.fas.past, +.slide-menu-wrapper .slide-menu-item-vertical.past i.fas.past, +.slide-menu-wrapper .slide-menu-item.active i.fas.active, +.slide-menu-wrapper .slide-menu-item-vertical.active i.fas.active, +.slide-menu-wrapper .slide-menu-item.future i.far.future, +.slide-menu-wrapper .slide-menu-item-vertical.future i.far.future, +.slide-menu-wrapper .slide-menu-item.past svg.svg-inline--fa.past, +.slide-menu-wrapper .slide-menu-item-vertical.past svg.svg-inline--fa.past, +.slide-menu-wrapper .slide-menu-item.active svg.svg-inline--fa.active, +.slide-menu-wrapper .slide-menu-item-vertical.active svg.svg-inline--fa.active, +.slide-menu-wrapper .slide-menu-item.future svg.svg-inline--fa.future, +.slide-menu-wrapper .slide-menu-item-vertical.future svg.svg-inline--fa.future { + display: inline-block; +} + +.slide-menu-wrapper .slide-menu-item.past i.fas.past, +.slide-menu-wrapper .slide-menu-item-vertical.past i.fas.past, +.slide-menu-wrapper .slide-menu-item.future i.far.future, +.slide-menu-wrapper .slide-menu-item-vertical.future i.far.future, +.slide-menu-wrapper .slide-menu-item.past svg.svg-inline--fa.past, +.slide-menu-wrapper .slide-menu-item-vertical.past svg.svg-inline--fa.past, +.slide-menu-wrapper .slide-menu-item.future svg.svg-inline--fa.future, +.slide-menu-wrapper .slide-menu-item-vertical.future svg.svg-inline--fa.future { + opacity: 0.4; +} + +.slide-menu-wrapper .slide-menu-item.active i.fas.active, +.slide-menu-wrapper .slide-menu-item-vertical.active i.fas.active, +.slide-menu-wrapper .slide-menu-item.active svg.svg-inline--fa.active, +.slide-menu-wrapper .slide-menu-item-vertical.active svg.svg-inline--fa.active { + opacity: 0.8; +} + +.slide-menu-wrapper .slide-menu--left { + left: 0; + -webkit-transform: translateX(-100%); + -ms-transform: translateX(-100%); + transform: translateX(-100%); +} + +.slide-menu-wrapper .slide-menu--left.active { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); +} + +.slide-menu-wrapper .slide-menu--right { + right: 0; + -webkit-transform: translateX(100%); + -ms-transform: translateX(100%); + transform: translateX(100%); +} + +.slide-menu-wrapper .slide-menu--right.active { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); +} + +.slide-menu-wrapper { + transition: transform 0.3s; +} + +/* + * Toolbar + */ +.slide-menu-wrapper .slide-menu-toolbar { + height: 60px; + width: 100%; + font-size: 12px; + display: table; + table-layout: fixed; /* ensures equal width */ + margin: 0; + padding: 0; + border-bottom: solid 2px #666; +} + +.slide-menu-wrapper .slide-menu-toolbar > li { + display: table-cell; + line-height: 150%; + text-align: center; + vertical-align: middle; + cursor: pointer; + color: #aaa; + border-radius: 3px; +} + +.slide-menu-wrapper .slide-menu-toolbar > li.toolbar-panel-button i, +.slide-menu-wrapper + .slide-menu-toolbar + > li.toolbar-panel-button + svg.svg-inline--fa { + font-size: 1.7em; +} + +.slide-menu-wrapper .slide-menu-toolbar > li.active-toolbar-button { + color: white; + text-shadow: 0 1px black; + text-decoration: underline; +} + +.slide-menu-toolbar > li.toolbar-panel-button:hover { + color: white; +} + +.slide-menu-toolbar + > li.toolbar-panel-button:hover + span.slide-menu-toolbar-label, +.slide-menu-wrapper + .slide-menu-toolbar + > li.active-toolbar-button + span.slide-menu-toolbar-label { + visibility: visible; +} + +/* + * Panels + */ +.slide-menu-wrapper .slide-menu-panel { + position: absolute; + width: 100%; + visibility: hidden; + height: calc(100% - 60px); + overflow-x: hidden; + overflow-y: auto; + color: #aaa; +} + +.slide-menu-wrapper .slide-menu-panel.active-menu-panel { + visibility: visible; +} + +.slide-menu-wrapper .slide-menu-panel h1, +.slide-menu-wrapper .slide-menu-panel h2, +.slide-menu-wrapper .slide-menu-panel h3, +.slide-menu-wrapper .slide-menu-panel h4, +.slide-menu-wrapper .slide-menu-panel h5, +.slide-menu-wrapper .slide-menu-panel h6 { + margin: 20px 0 10px 0; + color: #fff; + line-height: 1.2; + letter-spacing: normal; + text-shadow: none; +} + +.slide-menu-wrapper .slide-menu-panel h1 { + font-size: 1.6em; +} +.slide-menu-wrapper .slide-menu-panel h2 { + font-size: 1.4em; +} +.slide-menu-wrapper .slide-menu-panel h3 { + font-size: 1.3em; +} +.slide-menu-wrapper .slide-menu-panel h4 { + font-size: 1.1em; +} +.slide-menu-wrapper .slide-menu-panel h5 { + font-size: 1em; +} +.slide-menu-wrapper .slide-menu-panel h6 { + font-size: 0.9em; +} + +.slide-menu-wrapper .slide-menu-panel p { + margin: 10px 0 5px 0; +} + +.slide-menu-wrapper .slide-menu-panel a { + color: #ccc; + text-decoration: underline; +} + +.slide-menu-wrapper .slide-menu-panel a:hover { + color: white; +} + +.slide-menu-wrapper .slide-menu-item a { + text-decoration: none; +} + +.slide-menu-wrapper .slide-menu-custom-panel { + width: calc(100% - 20px); + padding-left: 10px; + padding-right: 10px; +} + +.slide-menu-wrapper .slide-menu-custom-panel .slide-menu-items { + width: calc(100% + 20px); + margin-left: -10px; + margin-right: 10px; +} + +/* + * Theme and Transitions buttons + */ + +.slide-menu-wrapper div[data-panel='Themes'] li, +.slide-menu-wrapper div[data-panel='Transitions'] li { + display: block; + text-align: left; + cursor: pointer; + color: #848484; +} + +/* + * Menu controls + */ +.reveal .slide-menu-button { + position: fixed; + left: 30px; + bottom: 30px; + z-index: 30; + font-size: 24px; +} + +/* + * Menu overlay + */ + +.slide-menu-wrapper .slide-menu-overlay { + position: fixed; + z-index: 199; + top: 0; + left: 0; + overflow: hidden; + width: 0; + height: 0; + background-color: #000; + opacity: 0; + transition: opacity 0.3s, width 0s 0.3s, height 0s 0.3s; +} + +.slide-menu-wrapper .slide-menu-overlay.active { + width: 100%; + height: 100%; + opacity: 0.7; + transition: opacity 0.3s; +} + +/* + * Hide menu for pdf printing + */ +body.print-pdf .slide-menu-wrapper .slide-menu, +body.print-pdf .reveal .slide-menu-button, +body.print-pdf .slide-menu-wrapper .slide-menu-overlay { + display: none; +} diff --git a/2311/site_libs/revealjs/plugin/reveal-menu/menu.js b/2311/site_libs/revealjs/plugin/reveal-menu/menu.js new file mode 100644 index 00000000..5369df33 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/reveal-menu/menu.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).RevealMenu=t()}(this,(function(){"use strict";var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function t(e,t,n){return e(n={path:t,exports:{},require:function(e,t){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==t&&n.path)}},n.exports),n.exports}var n=function(e){return e&&e.Math==Math&&e},r=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof e&&e)||Function("return this")(),i=function(e){try{return!!e()}catch(e){return!0}},a=!i((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),o={}.propertyIsEnumerable,s=Object.getOwnPropertyDescriptor,l={f:s&&!o.call({1:2},1)?function(e){var t=s(this,e);return!!t&&t.enumerable}:o},c=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}},u={}.toString,f=function(e){return u.call(e).slice(8,-1)},d="".split,p=i((function(){return!Object("z").propertyIsEnumerable(0)}))?function(e){return"String"==f(e)?d.call(e,""):Object(e)}:Object,h=function(e){if(null==e)throw TypeError("Can't call method on "+e);return e},m=function(e){return p(h(e))},v=function(e){return"object"==typeof e?null!==e:"function"==typeof e},g=function(e,t){if(!v(e))return e;var n,r;if(t&&"function"==typeof(n=e.toString)&&!v(r=n.call(e)))return r;if("function"==typeof(n=e.valueOf)&&!v(r=n.call(e)))return r;if(!t&&"function"==typeof(n=e.toString)&&!v(r=n.call(e)))return r;throw TypeError("Can't convert object to primitive value")},y={}.hasOwnProperty,b=function(e,t){return y.call(e,t)},S=r.document,E=v(S)&&v(S.createElement),x=!a&&!i((function(){return 7!=Object.defineProperty((e="div",E?S.createElement(e):{}),"a",{get:function(){return 7}}).a;var e})),w=Object.getOwnPropertyDescriptor,L={f:a?w:function(e,t){if(e=m(e),t=g(t,!0),x)try{return w(e,t)}catch(e){}if(b(e,t))return c(!l.f.call(e,t),e[t])}},T=function(e){if(!v(e))throw TypeError(String(e)+" is not an object");return e},C=Object.defineProperty,O={f:a?C:function(e,t,n){if(T(e),t=g(t,!0),T(n),x)try{return C(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(e[t]=n.value),e}},A=a?function(e,t,n){return O.f(e,t,c(1,n))}:function(e,t,n){return e[t]=n,e},k=function(e,t){try{A(r,e,t)}catch(n){r[e]=t}return t},I=r["__core-js_shared__"]||k("__core-js_shared__",{}),P=Function.toString;"function"!=typeof I.inspectSource&&(I.inspectSource=function(e){return P.call(e)});var M,R,j,N,_=I.inspectSource,F=r.WeakMap,W="function"==typeof F&&/native code/.test(_(F)),H=t((function(e){(e.exports=function(e,t){return I[e]||(I[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.6.5",mode:"global",copyright:"© 2020 Denis Pushkarev (zloirock.ru)"})})),U=0,$=Math.random(),D=function(e){return"Symbol("+String(void 0===e?"":e)+")_"+(++U+$).toString(36)},q=H("keys"),B={},G=r.WeakMap;if(W){var V=new G,K=V.get,z=V.has,X=V.set;M=function(e,t){return X.call(V,e,t),t},R=function(e){return K.call(V,e)||{}},j=function(e){return z.call(V,e)}}else{var Y=q[N="state"]||(q[N]=D(N));B[Y]=!0,M=function(e,t){return A(e,Y,t),t},R=function(e){return b(e,Y)?e[Y]:{}},j=function(e){return b(e,Y)}}var J={set:M,get:R,has:j,enforce:function(e){return j(e)?R(e):M(e,{})},getterFor:function(e){return function(t){var n;if(!v(t)||(n=R(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}},Z=t((function(e){var t=J.get,n=J.enforce,i=String(String).split("String");(e.exports=function(e,t,a,o){var s=!!o&&!!o.unsafe,l=!!o&&!!o.enumerable,c=!!o&&!!o.noTargetGet;"function"==typeof a&&("string"!=typeof t||b(a,"name")||A(a,"name",t),n(a).source=i.join("string"==typeof t?t:"")),e!==r?(s?!c&&e[t]&&(l=!0):delete e[t],l?e[t]=a:A(e,t,a)):l?e[t]=a:k(t,a)})(Function.prototype,"toString",(function(){return"function"==typeof this&&t(this).source||_(this)}))})),Q=r,ee=function(e){return"function"==typeof e?e:void 0},te=function(e,t){return arguments.length<2?ee(Q[e])||ee(r[e]):Q[e]&&Q[e][t]||r[e]&&r[e][t]},ne=Math.ceil,re=Math.floor,ie=function(e){return isNaN(e=+e)?0:(e>0?re:ne)(e)},ae=Math.min,oe=function(e){return e>0?ae(ie(e),9007199254740991):0},se=Math.max,le=Math.min,ce=function(e,t){var n=ie(e);return n<0?se(n+t,0):le(n,t)},ue=function(e){return function(t,n,r){var i,a=m(t),o=oe(a.length),s=ce(r,o);if(e&&n!=n){for(;o>s;)if((i=a[s++])!=i)return!0}else for(;o>s;s++)if((e||s in a)&&a[s]===n)return e||s||0;return!e&&-1}},fe={includes:ue(!0),indexOf:ue(!1)},de=fe.indexOf,pe=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"].concat("length","prototype"),he={f:Object.getOwnPropertyNames||function(e){return function(e,t){var n,r=m(e),i=0,a=[];for(n in r)!b(B,n)&&b(r,n)&&a.push(n);for(;t.length>i;)b(r,n=t[i++])&&(~de(a,n)||a.push(n));return a}(e,pe)}},me={f:Object.getOwnPropertySymbols},ve=te("Reflect","ownKeys")||function(e){var t=he.f(T(e)),n=me.f;return n?t.concat(n(e)):t},ge=function(e,t){for(var n=ve(t),r=O.f,i=L.f,a=0;ay;y++)if((o||y in m)&&(d=v(f=m[y],y,h),e))if(t)S[y]=d;else if(d)switch(e){case 3:return!0;case 5:return f;case 6:return y;case 2:We.call(S,f)}else if(i)return!1;return a?-1:r||i?i:S}},Ue={forEach:He(0),map:He(1),filter:He(2),some:He(3),every:He(4),find:He(5),findIndex:He(6)},$e=function(e,t){var n=[][e];return!!n&&i((function(){n.call(null,t||function(){throw 1},1)}))},De=Object.defineProperty,qe={},Be=function(e){throw e},Ge=function(e,t){if(b(qe,e))return qe[e];t||(t={});var n=[][e],r=!!b(t,"ACCESSORS")&&t.ACCESSORS,o=b(t,0)?t[0]:Be,s=b(t,1)?t[1]:void 0;return qe[e]=!!n&&!i((function(){if(r&&!a)return!0;var e={length:-1};r?De(e,1,{enumerable:!0,get:Be}):e[1]=1,n.call(e,o,s)}))},Ve=Ue.every,Ke=$e("every"),ze=Ge("every");Ce({target:"Array",proto:!0,forced:!Ke||!ze},{every:function(e){return Ve(this,e,arguments.length>1?arguments[1]:void 0)}});var Xe,Ye,Je=te("navigator","userAgent")||"",Ze=r.process,Qe=Ze&&Ze.versions,et=Qe&&Qe.v8;et?Ye=(Xe=et.split("."))[0]+Xe[1]:Je&&(!(Xe=Je.match(/Edge\/(\d+)/))||Xe[1]>=74)&&(Xe=Je.match(/Chrome\/(\d+)/))&&(Ye=Xe[1]);var tt=Ye&&+Ye,nt=Ne("species"),rt=function(e){return tt>=51||!i((function(){var t=[];return(t.constructor={})[nt]=function(){return{foo:1}},1!==t[e](Boolean).foo}))},it=Ue.filter,at=rt("filter"),ot=Ge("filter");Ce({target:"Array",proto:!0,forced:!at||!ot},{filter:function(e){return it(this,e,arguments.length>1?arguments[1]:void 0)}});var st=Ue.forEach,lt=$e("forEach"),ct=Ge("forEach"),ut=lt&&ct?[].forEach:function(e){return st(this,e,arguments.length>1?arguments[1]:void 0)};Ce({target:"Array",proto:!0,forced:[].forEach!=ut},{forEach:ut});var ft=fe.indexOf,dt=[].indexOf,pt=!!dt&&1/[1].indexOf(1,-0)<0,ht=$e("indexOf"),mt=Ge("indexOf",{ACCESSORS:!0,1:0});Ce({target:"Array",proto:!0,forced:pt||!ht||!mt},{indexOf:function(e){return pt?dt.apply(this,arguments)||0:ft(this,e,arguments.length>1?arguments[1]:void 0)}}),Ce({target:"Array",stat:!0},{isArray:ke});var vt=[].join,gt=p!=Object,yt=$e("join",",");Ce({target:"Array",proto:!0,forced:gt||!yt},{join:function(e){return vt.call(m(this),void 0===e?",":e)}});var bt=Math.min,St=[].lastIndexOf,Et=!!St&&1/[1].lastIndexOf(1,-0)<0,xt=$e("lastIndexOf"),wt=Ge("indexOf",{ACCESSORS:!0,1:0}),Lt=Et||!xt||!wt?function(e){if(Et)return St.apply(this,arguments)||0;var t=m(this),n=oe(t.length),r=n-1;for(arguments.length>1&&(r=bt(r,ie(arguments[1]))),r<0&&(r=n+r);r>=0;r--)if(r in t&&t[r]===e)return r||0;return-1}:St;Ce({target:"Array",proto:!0,forced:Lt!==[].lastIndexOf},{lastIndexOf:Lt});var Tt=Ue.map,Ct=rt("map"),Ot=Ge("map");Ce({target:"Array",proto:!0,forced:!Ct||!Ot},{map:function(e){return Tt(this,e,arguments.length>1?arguments[1]:void 0)}});var At=function(e,t,n){var r=g(t);r in e?O.f(e,r,c(0,n)):e[r]=n},kt=rt("slice"),It=Ge("slice",{ACCESSORS:!0,0:0,1:2}),Pt=Ne("species"),Mt=[].slice,Rt=Math.max;Ce({target:"Array",proto:!0,forced:!kt||!It},{slice:function(e,t){var n,r,i,a=m(this),o=oe(a.length),s=ce(e,o),l=ce(void 0===t?o:t,o);if(ke(a)&&("function"!=typeof(n=a.constructor)||n!==Array&&!ke(n.prototype)?v(n)&&null===(n=n[Pt])&&(n=void 0):n=void 0,n===Array||void 0===n))return Mt.call(a,s,l);for(r=new(void 0===n?Array:n)(Rt(l-s,0)),i=0;s>>0||(Qt.test(n)?16:10))}:Zt;Ce({global:!0,forced:parseInt!=en},{parseInt:en});var tn=function(){var e=T(this),t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.dotAll&&(t+="s"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t};function nn(e,t){return RegExp(e,t)}var rn,an,on={UNSUPPORTED_Y:i((function(){var e=nn("a","y");return e.lastIndex=2,null!=e.exec("abcd")})),BROKEN_CARET:i((function(){var e=nn("^r","gy");return e.lastIndex=2,null!=e.exec("str")}))},sn=RegExp.prototype.exec,ln=String.prototype.replace,cn=sn,un=(rn=/a/,an=/b*/g,sn.call(rn,"a"),sn.call(an,"a"),0!==rn.lastIndex||0!==an.lastIndex),fn=on.UNSUPPORTED_Y||on.BROKEN_CARET,dn=void 0!==/()??/.exec("")[1];(un||dn||fn)&&(cn=function(e){var t,n,r,i,a=this,o=fn&&a.sticky,s=tn.call(a),l=a.source,c=0,u=e;return o&&(-1===(s=s.replace("y","")).indexOf("g")&&(s+="g"),u=String(e).slice(a.lastIndex),a.lastIndex>0&&(!a.multiline||a.multiline&&"\n"!==e[a.lastIndex-1])&&(l="(?: "+l+")",u=" "+u,c++),n=new RegExp("^(?:"+l+")",s)),dn&&(n=new RegExp("^"+l+"$(?!\\s)",s)),un&&(t=a.lastIndex),r=sn.call(o?n:a,u),o?r?(r.input=r.input.slice(c),r[0]=r[0].slice(c),r.index=a.lastIndex,a.lastIndex+=r[0].length):a.lastIndex=0:un&&r&&(a.lastIndex=a.global?r.index+r[0].length:t),dn&&r&&r.length>1&&ln.call(r[0],n,(function(){for(i=1;i1?arguments[1]:void 0,r=oe(t.length),i=void 0===n?r:xn(oe(n),r),a=String(e);return En?En.call(t,a,i):t.slice(i-a.length,i)===a}});var Ln=Ne("species"),Tn=!i((function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")})),Cn="$0"==="a".replace(/./,"$0"),On=Ne("replace"),An=!!/./[On]&&""===/./[On]("a","$0"),kn=!i((function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]})),In=function(e,t,n,r){var a=Ne(e),o=!i((function(){var t={};return t[a]=function(){return 7},7!=""[e](t)})),s=o&&!i((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[Ln]=function(){return n},n.flags="",n[a]=/./[a]),n.exec=function(){return t=!0,null},n[a](""),!t}));if(!o||!s||"replace"===e&&(!Tn||!Cn||An)||"split"===e&&!kn){var l=/./[a],c=n(a,""[e],(function(e,t,n,r,i){return t.exec===pn?o&&!i?{done:!0,value:l.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),{REPLACE_KEEPS_$0:Cn,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:An}),u=c[0],f=c[1];Z(String.prototype,e,u),Z(RegExp.prototype,a,2==t?function(e,t){return f.call(e,this,t)}:function(e){return f.call(e,this)})}r&&A(RegExp.prototype[a],"sham",!0)},Pn=function(e){return function(t,n){var r,i,a=String(h(t)),o=ie(n),s=a.length;return o<0||o>=s?e?"":void 0:(r=a.charCodeAt(o))<55296||r>56319||o+1===s||(i=a.charCodeAt(o+1))<56320||i>57343?e?a.charAt(o):r:e?a.slice(o,o+2):i-56320+(r-55296<<10)+65536}},Mn={codeAt:Pn(!1),charAt:Pn(!0)}.charAt,Rn=function(e,t,n){return t+(n?Mn(e,t).length:1)},jn=function(e,t){var n=e.exec;if("function"==typeof n){var r=n.call(e,t);if("object"!=typeof r)throw TypeError("RegExp exec method returned something other than an Object or null");return r}if("RegExp"!==f(e))throw TypeError("RegExp#exec called on incompatible receiver");return pn.call(e,t)},Nn=Math.max,_n=Math.min,Fn=Math.floor,Wn=/\$([$&'`]|\d\d?|<[^>]*>)/g,Hn=/\$([$&'`]|\d\d?)/g;In("replace",2,(function(e,t,n,r){var i=r.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,a=r.REPLACE_KEEPS_$0,o=i?"$":"$0";return[function(n,r){var i=h(this),a=null==n?void 0:n[e];return void 0!==a?a.call(n,i,r):t.call(String(i),n,r)},function(e,r){if(!i&&a||"string"==typeof r&&-1===r.indexOf(o)){var l=n(t,e,this,r);if(l.done)return l.value}var c=T(e),u=String(this),f="function"==typeof r;f||(r=String(r));var d=c.global;if(d){var p=c.unicode;c.lastIndex=0}for(var h=[];;){var m=jn(c,u);if(null===m)break;if(h.push(m),!d)break;""===String(m[0])&&(c.lastIndex=Rn(u,oe(c.lastIndex),p))}for(var v,g="",y=0,b=0;b=y&&(g+=u.slice(y,E)+O,y=E+S.length)}return g+u.slice(y)}];function s(e,n,r,i,a,o){var s=r+e.length,l=i.length,c=Hn;return void 0!==a&&(a=Ae(a),c=Wn),t.call(o,c,(function(t,o){var c;switch(o.charAt(0)){case"$":return"$";case"&":return e;case"`":return n.slice(0,r);case"'":return n.slice(s);case"<":c=a[o.slice(1,-1)];break;default:var u=+o;if(0===u)return t;if(u>l){var f=Fn(u/10);return 0===f?t:f<=l?void 0===i[f-1]?o.charAt(1):i[f-1]+o.charAt(1):t}c=i[u-1]}return void 0===c?"":c}))}}));var Un=Object.is||function(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t};In("search",1,(function(e,t,n){return[function(t){var n=h(this),r=null==t?void 0:t[e];return void 0!==r?r.call(t,n):new RegExp(t)[e](String(n))},function(e){var r=n(t,e,this);if(r.done)return r.value;var i=T(e),a=String(this),o=i.lastIndex;Un(o,0)||(i.lastIndex=0);var s=jn(i,a);return Un(i.lastIndex,o)||(i.lastIndex=o),null===s?-1:s.index}]}));var $n=Ne("species"),Dn=[].push,qn=Math.min,Bn=!i((function(){return!RegExp(4294967295,"y")}));In("split",2,(function(e,t,n){var r;return r="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(e,n){var r=String(h(this)),i=void 0===n?4294967295:n>>>0;if(0===i)return[];if(void 0===e)return[r];if(!vn(e))return t.call(r,e,i);for(var a,o,s,l=[],c=(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":""),u=0,f=new RegExp(e.source,c+"g");(a=pn.call(f,r))&&!((o=f.lastIndex)>u&&(l.push(r.slice(u,a.index)),a.length>1&&a.index=i));)f.lastIndex===a.index&&f.lastIndex++;return u===r.length?!s&&f.test("")||l.push(""):l.push(r.slice(u)),l.length>i?l.slice(0,i):l}:"0".split(void 0,0).length?function(e,n){return void 0===e&&0===n?[]:t.call(this,e,n)}:t,[function(t,n){var i=h(this),a=null==t?void 0:t[e];return void 0!==a?a.call(t,i,n):r.call(String(i),t,n)},function(e,i){var a=n(r,e,this,i,r!==t);if(a.done)return a.value;var o=T(e),s=String(this),l=function(e,t){var n,r=T(e).constructor;return void 0===r||null==(n=T(r)[$n])?t:Oe(n)}(o,RegExp),c=o.unicode,u=(o.ignoreCase?"i":"")+(o.multiline?"m":"")+(o.unicode?"u":"")+(Bn?"y":"g"),f=new l(Bn?o:"^(?:"+o.source+")",u),d=void 0===i?4294967295:i>>>0;if(0===d)return[];if(0===s.length)return null===jn(f,s)?[s]:[];for(var p=0,h=0,m=[];h1?arguments[1]:void 0,t.length)),r=String(e);return Vn?Vn.call(t,r,n):t.slice(n,n+r.length)===r}});var Xn,Yn=Kt.trim;Ce({target:"String",proto:!0,forced:(Xn="trim",i((function(){return!!Dt[Xn]()||"​…᠎"!="​…᠎"[Xn]()||Dt[Xn].name!==Xn})))},{trim:function(){return Yn(this)}});for(var Jn in{CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}){var Zn=r[Jn],Qn=Zn&&Zn.prototype;if(Qn&&Qn.forEach!==ut)try{A(Qn,"forEach",ut)}catch(e){Qn.forEach=ut}}var er=[].slice,tr=function(e){return function(t,n){var r=arguments.length>2,i=r?er.call(arguments,2):void 0;return e(r?function(){("function"==typeof t?t:Function(t)).apply(this,i)}:t,n)}};Ce({global:!0,bind:!0,forced:/MSIE .\./.test(Je)},{setTimeout:tr(r.setTimeout),setInterval:tr(r.setInterval)});return String.prototype.startsWith||(String.prototype.startsWith=function(e,t){return this.substr(t||0,e.length)===e}),String.prototype.endsWith||(String.prototype.endsWith=function(e,t){return(void 0===t||t>this.length)&&(t=this.length),this.substring(t-e.length,t)===e}),function(){var e,t,n,r,i=(e=/(msie) ([\w.]+)/.exec(window.navigator.userAgent.toLowerCase()))&&"msie"===e[1]?parseFloat(e[2]):null,a=!1;function o(e){(r=e.menu||{}).path=r.path||function(){var e;if(document.querySelector('script[src$="menu.js"]')){var t=document.querySelector('script[src$="menu.js"]');t&&(e=t.src.slice(0,-7))}else e=("undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("menu.js",document.baseURI).href).slice(0,("undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("menu.js",document.baseURI).href).lastIndexOf("/")+1);return e}()||"plugin/menu/",r.path.endsWith("/")||(r.path+="/"),void 0===r.side&&(r.side="left"),void 0===r.numbers&&(r.numbers=!1),"string"!=typeof r.titleSelector&&(r.titleSelector="h1, h2, h3, h4, h5"),void 0===r.hideMissingTitles&&(r.hideMissingTitles=!1),void 0===r.useTextContentForMissingTitles&&(r.useTextContentForMissingTitles=!1),void 0===r.markers&&(r.markers=!0),"string"!=typeof r.themesPath&&(r.themesPath="dist/theme/"),r.themesPath.endsWith("/")||(r.themesPath+="/"),O("link#theme")||(r.themes=!1),!0===r.themes?r.themes=[{name:"Black",theme:r.themesPath+"black.css"},{name:"White",theme:r.themesPath+"white.css"},{name:"League",theme:r.themesPath+"league.css"},{name:"Sky",theme:r.themesPath+"sky.css"},{name:"Beige",theme:r.themesPath+"beige.css"},{name:"Simple",theme:r.themesPath+"simple.css"},{name:"Serif",theme:r.themesPath+"serif.css"},{name:"Blood",theme:r.themesPath+"blood.css"},{name:"Night",theme:r.themesPath+"night.css"},{name:"Moon",theme:r.themesPath+"moon.css"},{name:"Solarized",theme:r.themesPath+"solarized.css"}]:Array.isArray(r.themes)||(r.themes=!1),void 0===r.transitions&&(r.transitions=!1),!0===r.transitions?r.transitions=["None","Fade","Slide","Convex","Concave","Zoom"]:!1===r.transitions||Array.isArray(r.transitions)&&r.transitions.every((function(e){return"string"==typeof e}))||(console.error("reveal.js-menu error: transitions config value must be 'true' or an array of strings, eg ['None', 'Fade', 'Slide')"),r.transitions=!1),i&&i<=9&&(r.transitions=!1),void 0===r.openButton&&(r.openButton=!0),void 0===r.openSlideNumber&&(r.openSlideNumber=!1),void 0===r.keyboard&&(r.keyboard=!0),void 0===r.sticky&&(r.sticky=!1),void 0===r.autoOpen&&(r.autoOpen=!0),void 0===r.delayInit&&(r.delayInit=!1),void 0===r.openOnInit&&(r.openOnInit=!1)}var s=!0;function l(){s=!1}function c(){O("nav.slide-menu").addEventListener("mousemove",(function e(t){O("nav.slide-menu").removeEventListener("mousemove",e),s=!0}))}function u(e){var t=function(e){for(var t=0,n=0;e&&!isNaN(e.offsetLeft)&&!isNaN(e.offsetTop);)t+=e.offsetLeft-e.scrollLeft,n+=e.offsetTop-e.scrollTop,e=e.offsetParent;return{top:n,left:t}}(e).top-e.offsetParent.offsetTop;if(t<0)return-t;var n=e.offsetParent.offsetHeight-(e.offsetTop-e.offsetParent.scrollTop+e.offsetHeight);return n<0?n:0}function f(e){var t=u(e);t&&(l(),e.scrollIntoView(t>0),c())}function d(e){l(),e.offsetParent.scrollTop=e.offsetTop,c()}function p(e){l(),e.offsetParent.scrollTop=e.offsetTop-e.offsetParent.offsetHeight+e.offsetHeight,c()}function h(e){e.classList.add("selected"),f(e),r.sticky&&r.autoOpen&&E(e)}function m(e){if(b())switch(e.stopImmediatePropagation(),e.keyCode){case 72:case 37:!function(){var e=parseInt(O(".active-toolbar-button").getAttribute("data-button"))-1;e<0&&(e=T-1);S(null,O('.toolbar-panel-button[data-button="'+e+'"]').getAttribute("data-panel"))}();break;case 76:case 39:l=(parseInt(O(".active-toolbar-button").getAttribute("data-button"))+1)%T,S(null,O('.toolbar-panel-button[data-button="'+l+'"]').getAttribute("data-panel"));break;case 75:case 38:if(s=O(".active-menu-panel .slide-menu-items li.selected")||O(".active-menu-panel .slide-menu-items li.active"))A(".active-menu-panel .slide-menu-items li").forEach((function(e){e.classList.remove("selected")})),h(O('.active-menu-panel .slide-menu-items li[data-item="'+(parseInt(s.getAttribute("data-item"))-1)+'"]')||s);else(o=O(".active-menu-panel .slide-menu-items li.slide-menu-item"))&&h(o);break;case 74:case 40:if(s=O(".active-menu-panel .slide-menu-items li.selected")||O(".active-menu-panel .slide-menu-items li.active"))A(".active-menu-panel .slide-menu-items li").forEach((function(e){e.classList.remove("selected")})),h(O('.active-menu-panel .slide-menu-items li[data-item="'+(parseInt(s.getAttribute("data-item"))+1)+'"]')||s);else(o=O(".active-menu-panel .slide-menu-items li.slide-menu-item"))&&h(o);break;case 33:case 85:var t=A(".active-menu-panel .slide-menu-items li").filter((function(e){return u(e)>0})),n=A(".active-menu-panel .slide-menu-items li").filter((function(e){return 0==u(e)})),r=t.length>0&&Math.abs(u(t[t.length-1]))0&&(p(r),r=(n=A(".active-menu-panel .slide-menu-items li").filter((function(e){return 0==u(e)})))[0]==r?t[t.length-1]:n[0]),A(".active-menu-panel .slide-menu-items li").forEach((function(e){e.classList.remove("selected")})),h(r),d(r));break;case 34:case 68:n=A(".active-menu-panel .slide-menu-items li").filter((function(e){return 0==u(e)}));var i=A(".active-menu-panel .slide-menu-items li").filter((function(e){return u(e)<0})),a=i.length>0&&Math.abs(u(i[0]))0&&(d(a),a=(n=A(".active-menu-panel .slide-menu-items li").filter((function(e){return 0==u(e)})))[n.length-1]==a?i[0]:n[n.length-1]),A(".active-menu-panel .slide-menu-items li").forEach((function(e){e.classList.remove("selected")})),h(a),p(a));break;case 36:A(".active-menu-panel .slide-menu-items li").forEach((function(e){e.classList.remove("selected")})),(o=O(".active-menu-panel .slide-menu-items li:first-of-type"))&&(o.classList.add("selected"),f(o));break;case 35:var o;A(".active-menu-panel .slide-menu-items li").forEach((function(e){e.classList.remove("selected")})),(o=O(".active-menu-panel .slide-menu-items:last-of-type li:last-of-type"))&&(o.classList.add("selected"),f(o));break;case 32:case 13:var s;(s=O(".active-menu-panel .slide-menu-items li.selected"))&&E(s,!0);break;case 27:g(null,!0)}var l}function v(e){(e&&e.preventDefault(),b())||(O("body").classList.add("slide-menu-active"),O(".reveal").classList.add("has-"+r.effect+"-"+r.side),O(".slide-menu").classList.add("active"),O(".slide-menu-overlay").classList.add("active"),r.themes&&(A('div[data-panel="Themes"] li').forEach((function(e){e.classList.remove("active")})),A('li[data-theme="'+O("link#theme").getAttribute("href")+'"]').forEach((function(e){e.classList.add("active")}))),r.transitions&&(A('div[data-panel="Transitions"] li').forEach((function(e){e.classList.remove("active")})),A('li[data-transition="'+n.transition+'"]').forEach((function(e){e.classList.add("active")}))),A(".slide-menu-panel li.active").forEach((function(e){e.classList.add("selected"),f(e)})))}function g(e,t){e&&e.preventDefault(),r.sticky&&!t||(O("body").classList.remove("slide-menu-active"),O(".reveal").classList.remove("has-"+r.effect+"-"+r.side),O(".slide-menu").classList.remove("active"),O(".slide-menu-overlay").classList.remove("active"),A(".slide-menu-panel li.selected").forEach((function(e){e.classList.remove("selected")})))}function y(e){b()?g(e,!0):v(e)}function b(){return O("body").classList.contains("slide-menu-active")}function S(e,t){v(e);var n=t;"string"!=typeof t&&(n=e.currentTarget.getAttribute("data-panel")),O(".slide-menu-toolbar > li.active-toolbar-button").classList.remove("active-toolbar-button"),O('li[data-panel="'+n+'"]').classList.add("active-toolbar-button"),O(".slide-menu-panel.active-menu-panel").classList.remove("active-menu-panel"),O('div[data-panel="'+n+'"]').classList.add("active-menu-panel")}function E(e,n){var i=parseInt(e.getAttribute("data-slide-h")),a=parseInt(e.getAttribute("data-slide-v")),o=e.getAttribute("data-theme"),s=e.getAttribute("data-highlight-theme"),l=e.getAttribute("data-transition");isNaN(i)||isNaN(a)||t.slide(i,a),o&&I("theme",o),s&&I("highlight-theme",s),l&&t.configure({transition:l});var c=O("a",e);c&&(n||!r.sticky||r.autoOpen&&c.href.startsWith("#")||c.href.startsWith(window.location.origin+window.location.pathname+"#"))&&c.click(),g()}function x(e){"A"!==e.target.nodeName&&e.preventDefault(),E(e.currentTarget)}function w(){var e=t.getState();A("li.slide-menu-item, li.slide-menu-item-vertical").forEach((function(t){t.classList.remove("past"),t.classList.remove("active"),t.classList.remove("future");var n=parseInt(t.getAttribute("data-slide-h")),r=parseInt(t.getAttribute("data-slide-v"));n",s.appendChild(k("br"),O("i",s)),s.appendChild(k("span",{class:"slide-menu-toolbar-label"},e),O("i",s)),s.onclick=i,d.appendChild(s),s},i=function(e,i,a,o,s){function l(e,t){if(""===e)return null;var n=t?O(e,i):O(e);return n?n.textContent:null}var c=i.getAttribute("data-menu-title")||l(".menu-title",i)||l(r.titleSelector,i);if(!c&&r.useTextContentForMissingTitles&&(c=i.textContent.trim())&&(c=c.split("\n").map((function(e){return e.trim()})).join(" ").trim().replace(/^(.{16}[^\s]*).*/,"$1").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")+"..."),!c){if(r.hideMissingTitles)return"";e+=" no-title",c="Slide "+(a+1)}var u=k("li",{class:e,"data-item":a,"data-slide-h":o,"data-slide-v":void 0===s?0:s});if(r.markers&&(u.appendChild(k("i",{class:"fas fa-check-circle fa-fw past"})),u.appendChild(k("i",{class:"fas fa-arrow-alt-circle-right fa-fw active"})),u.appendChild(k("i",{class:"far fa-circle fa-fw future"}))),r.numbers){var f=[],d="h.v";switch("string"==typeof r.numbers?d=r.numbers:"string"==typeof n.slideNumber&&(d=n.slideNumber),d){case"c":f.push(a+1);break;case"c/t":f.push(a+1,"/",t.getTotalSlides());break;case"h/v":f.push(o+1),"number"!=typeof s||isNaN(s)||f.push("/",s+1);break;default:f.push(o+1),"number"!=typeof s||isNaN(s)||f.push(".",s+1)}u.appendChild(k("span",{class:"slide-menu-item-number"},f.join("")+". "))}return u.appendChild(k("span",{class:"slide-menu-item-title"},c)),u},o=function(e){s&&(A(".active-menu-panel .slide-menu-items li.selected").forEach((function(e){e.classList.remove("selected")})),e.currentTarget.classList.add("selected"))},l=O(".reveal").parentElement,c=k("div",{class:"slide-menu-wrapper"});l.appendChild(c);var u=k("nav",{class:"slide-menu slide-menu--"+r.side});"string"==typeof r.width&&(-1!=["normal","wide","third","half","full"].indexOf(r.width)?u.classList.add("slide-menu--"+r.width):(u.classList.add("slide-menu--custom"),u.style.width=r.width)),c.appendChild(u),L();var f=k("div",{class:"slide-menu-overlay"});c.appendChild(f),f.onclick=function(){g(null,!0)};var d=k("ol",{class:"slide-menu-toolbar"});O(".slide-menu").appendChild(d),e("Slides","Slides","fa-images","fas",S,!0),r.custom&&r.custom.forEach((function(t,n,r){e(t.title,"Custom"+n,t.icon,null,S)})),r.themes&&e("Themes","Themes","fa-adjust","fas",S),r.transitions&&e("Transitions","Transitions","fa-sticky-note","fas",S);var p=k("li",{id:"close",class:"toolbar-panel-button"});if(p.appendChild(k("i",{class:"fas fa-times"})),p.appendChild(k("br")),p.appendChild(k("span",{class:"slide-menu-toolbar-label"},"Close")),p.onclick=function(){g(null,!0)},d.appendChild(p),function e(){if(document.querySelector("section[data-markdown]:not([data-markdown-parsed])"))setTimeout(e,100);else{var t=k("div",{"data-panel":"Slides",class:"slide-menu-panel active-menu-panel"});t.appendChild(k("ul",{class:"slide-menu-items"})),u.appendChild(t);var n=O('.slide-menu-panel[data-panel="Slides"] > .slide-menu-items'),r=0;A(".slides > section").forEach((function(e,t){var a=A("section",e);if(a.length>0)a.forEach((function(e,a){var o=i(0===a?"slide-menu-item":"slide-menu-item-vertical",e,r,t,a);o&&n.appendChild(o),r++}));else{var o=i("slide-menu-item",e,r,t);o&&n.appendChild(o),r++}})),A(".slide-menu-item, .slide-menu-item-vertical").forEach((function(e){e.onclick=x})),w()}}(),t.addEventListener("slidechanged",w),r.custom){var h=function(){this.status>=200&&this.status<300?(this.panel.innerHTML=this.responseText,C(this.panel)):I(this)},E=function(){I(this)},C=function(e){A("ul.slide-menu-items li.slide-menu-item",e).forEach((function(e,t){e.setAttribute("data-item",t+1),e.onclick=x,e.addEventListener("mouseenter",o)}))},I=function(e){var t="

    ERROR: The attempt to fetch "+e.responseURL+" failed with HTTP status "+e.status+" ("+e.statusText+").

    Remember that you need to serve the presentation HTML from a HTTP server.

    ";e.panel.innerHTML=t};r.custom.forEach((function(e,t,n){var r=k("div",{"data-panel":"Custom"+t,class:"slide-menu-panel slide-menu-custom-panel"});e.content?(r.innerHTML=e.content,C(r)):e.src&&function(e,t){var n=new XMLHttpRequest;n.panel=e,n.arguments=Array.prototype.slice.call(arguments,2),n.onload=h,n.onerror=E,n.open("get",t,!0),n.send(null)}(r,e.src),u.appendChild(r)}))}if(r.themes){var P=k("div",{class:"slide-menu-panel","data-panel":"Themes"});u.appendChild(P);var M=k("ul",{class:"slide-menu-items"});P.appendChild(M),r.themes.forEach((function(e,t){var n={class:"slide-menu-item","data-item":""+(t+1)};e.theme&&(n["data-theme"]=e.theme),e.highlightTheme&&(n["data-highlight-theme"]=e.highlightTheme);var r=k("li",n,e.name);M.appendChild(r),r.onclick=x}))}if(r.transitions){P=k("div",{class:"slide-menu-panel","data-panel":"Transitions"});u.appendChild(P);M=k("ul",{class:"slide-menu-items"});P.appendChild(M),r.transitions.forEach((function(e,t){var n=k("li",{class:"slide-menu-item","data-transition":e.toLowerCase(),"data-item":""+(t+1)},e);M.appendChild(n),n.onclick=x}))}if(r.openButton){var R=k("div",{class:"slide-menu-button"}),j=k("a",{href:"#"});j.appendChild(k("i",{class:"fas fa-bars"})),R.appendChild(j),O(".reveal").appendChild(R),R.onclick=v}if(r.openSlideNumber)O("div.slide-number").onclick=v;A(".slide-menu-panel .slide-menu-items li").forEach((function(e){e.addEventListener("mouseenter",o)}))}if(r.keyboard){if(document.addEventListener("keydown",m,!1),window.addEventListener("message",(function(e){var t;try{t=JSON.parse(e.data)}catch(e){}t&&"triggerKey"===t.method&&m({keyCode:t.args[0],stopImmediatePropagation:function(){}})})),n.keyboardCondition&&"function"==typeof n.keyboardCondition){var N=n.keyboardCondition;n.keyboardCondition=function(e){return N(e)&&(!b()||77==e.keyCode)}}else n.keyboardCondition=function(e){return!b()||77==e.keyCode};t.addKeyBinding({keyCode:77,key:"M",description:"Toggle menu"},y)}r.openOnInit&&v(),a=!0}function O(e,t){return t||(t=document),t.querySelector(e)}function A(e,t){return t||(t=document),Array.prototype.slice.call(t.querySelectorAll(e))}function k(e,t,n){var r=document.createElement(e);return t&&Object.getOwnPropertyNames(t).forEach((function(e){r.setAttribute(e,t[e])})),n&&(r.innerHTML=n),r}function I(e,t){var n=O("link#"+e),r=n.parentElement,i=n.nextElementSibling;n.remove();var a=n.cloneNode();a.setAttribute("href",t),a.onload=function(){L()},r.insertBefore(a,i)}function P(e,t,n){n.call()}function M(){var e,a,o,s=!i||i>=9;t.isSpeakerNotes()&&window.location.search.endsWith("controls=false")&&(s=!1),s&&(r.delayInit||C(),e="menu-ready",(o=document.createEvent("HTMLEvents",1,2)).initEvent(e,!0,!0),function(e,t){for(var n in t)e[n]=t[n]}(o,a),document.querySelector(".reveal").dispatchEvent(o),n.postMessageEvents&&window.parent!==window.self&&window.parent.postMessage(JSON.stringify({namespace:"reveal",eventName:e,state:t.getState()}),"*"))}return{id:"menu",init:function(e){o(n=(t=e).getConfig()),P(r.path+"menu.css","stylesheet",(function(){void 0===r.loadIcons||r.loadIcons?P(r.path+"font-awesome/css/all.css","stylesheet",M):M()}))},toggle:y,openMenu:v,closeMenu:g,openPanel:S,isOpen:b,initialiseMenu:C,isMenuInitialised:function(){return a}}}})); diff --git a/2311/site_libs/revealjs/plugin/reveal-menu/plugin.yml b/2311/site_libs/revealjs/plugin/reveal-menu/plugin.yml new file mode 100644 index 00000000..3f4b90aa --- /dev/null +++ b/2311/site_libs/revealjs/plugin/reveal-menu/plugin.yml @@ -0,0 +1,9 @@ +name: RevealMenu +script: [menu.js, quarto-menu.js] +stylesheet: [menu.css, quarto-menu.css] +config: + menu: + side: "left" + useTextContentForMissingTitles: true + markers: false + loadIcons: false diff --git a/2311/site_libs/revealjs/plugin/reveal-menu/quarto-menu.css b/2311/site_libs/revealjs/plugin/reveal-menu/quarto-menu.css new file mode 100644 index 00000000..eec145c0 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/reveal-menu/quarto-menu.css @@ -0,0 +1,68 @@ +.slide-menu-wrapper .slide-tool-item { + display: block; + text-align: left; + padding: 10px 18px; + color: #aaa; + cursor: pointer; + border-top: solid 1px #555; +} + +.slide-menu-wrapper .slide-tool-item a { + text-decoration: none; +} + +.slide-menu-wrapper .slide-tool-item kbd { + font-family: monospace; + margin-right: 10px; + padding: 3px 8px; + color: inherit; + border: 1px solid; + border-radius: 5px; + border-color: #555; +} + +.slide-menu-wrapper .slide-menu-toolbar > li.active-toolbar-button { + text-decoration: none; +} + +.reveal .slide-menu-button { + left: 8px; + bottom: 8px; +} + +.reveal .slide-menu-button .fas::before, +.reveal .slide-chalkboard-buttons .fas::before, +.slide-menu-wrapper .slide-menu-toolbar .fas::before { + display: inline-block; + height: 2.2rem; + width: 2.2rem; + content: ""; + vertical-align: -0.125em; + background-repeat: no-repeat; + background-size: 2.2rem 2.2rem; +} + +.reveal .slide-chalkboard-buttons .fas::before { + height: 1.45rem; + width: 1.45rem; + background-size: 1.45rem 1.45rem; + vertical-align: 0.1em; +} + +.slide-menu-wrapper .slide-menu-toolbar .fas::before { + height: 1.8rem; + width: 1.8rem; + background-size: 1.8rem 1.8rem; +} + +.slide-menu-wrapper .slide-menu-toolbar .fa-images::before { + background-image: url('data:image/svg+xml,'); +} + +.slide-menu-wrapper .slide-menu-toolbar .fa-gear::before { + background-image: url('data:image/svg+xml,'); +} + +.slide-menu-wrapper .slide-menu-toolbar .fa-times::before { + background-image: url('data:image/svg+xml,'); +} diff --git a/2311/site_libs/revealjs/plugin/reveal-menu/quarto-menu.js b/2311/site_libs/revealjs/plugin/reveal-menu/quarto-menu.js new file mode 100644 index 00000000..96740536 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/reveal-menu/quarto-menu.js @@ -0,0 +1,43 @@ +window.revealMenuToolHandler = function (handler) { + return function (event) { + event.preventDefault(); + handler(); + Reveal.getPlugin("menu").closeMenu(); + }; +}; + +window.RevealMenuToolHandlers = { + fullscreen: revealMenuToolHandler(function () { + const element = document.documentElement; + const requestMethod = + element.requestFullscreen || + element.webkitRequestFullscreen || + element.webkitRequestFullScreen || + element.mozRequestFullScreen || + element.msRequestFullscreen; + if (requestMethod) { + requestMethod.apply(element); + } + }), + speakerMode: revealMenuToolHandler(function () { + Reveal.getPlugin("notes").open(); + }), + keyboardHelp: revealMenuToolHandler(function () { + Reveal.toggleHelp(true); + }), + overview: revealMenuToolHandler(function () { + Reveal.toggleOverview(true); + }), + toggleChalkboard: revealMenuToolHandler(function () { + RevealChalkboard.toggleChalkboard(); + }), + toggleNotesCanvas: revealMenuToolHandler(function () { + RevealChalkboard.toggleNotesCanvas(); + }), + downloadDrawings: revealMenuToolHandler(function () { + RevealChalkboard.download(); + }), + togglePdfExport: revealMenuToolHandler(function () { + PdfExport.togglePdfExport(); + }), +}; diff --git a/2311/site_libs/revealjs/plugin/search/plugin.js b/2311/site_libs/revealjs/plugin/search/plugin.js new file mode 100644 index 00000000..5d09ce6a --- /dev/null +++ b/2311/site_libs/revealjs/plugin/search/plugin.js @@ -0,0 +1,243 @@ +/*! + * Handles finding a text string anywhere in the slides and showing the next occurrence to the user + * by navigatating to that slide and highlighting it. + * + * @author Jon Snyder , February 2013 + */ + +const Plugin = () => { + + // The reveal.js instance this plugin is attached to + let deck; + + let searchElement; + let searchButton; + let searchInput; + + let matchedSlides; + let currentMatchedIndex; + let searchboxDirty; + let hilitor; + + function render() { + + searchElement = document.createElement( 'div' ); + searchElement.classList.add( 'searchbox' ); + searchElement.style.position = 'absolute'; + searchElement.style.top = '10px'; + searchElement.style.right = '10px'; + searchElement.style.zIndex = 10; + + //embedded base64 search icon Designed by Sketchdock - http://www.sketchdock.com/: + searchElement.innerHTML = ` +
    `; + + searchInput = searchElement.querySelector( '.searchinput' ); + searchInput.style.width = '240px'; + searchInput.style.fontSize = '14px'; + searchInput.style.padding = '4px 6px'; + searchInput.style.color = '#000'; + searchInput.style.background = '#fff'; + searchInput.style.borderRadius = '2px'; + searchInput.style.border = '0'; + searchInput.style.outline = '0'; + searchInput.style.boxShadow = '0 2px 18px rgba(0, 0, 0, 0.2)'; + searchInput.style['-webkit-appearance'] = 'none'; + + deck.getRevealElement().appendChild( searchElement ); + + // searchButton.addEventListener( 'click', function(event) { + // doSearch(); + // }, false ); + + searchInput.addEventListener( 'keyup', function( event ) { + switch (event.keyCode) { + case 13: + event.preventDefault(); + doSearch(); + searchboxDirty = false; + break; + default: + searchboxDirty = true; + } + }, false ); + + closeSearch(); + + } + + function openSearch() { + if( !searchElement ) render(); + + searchElement.style.display = 'inline'; + searchInput.focus(); + searchInput.select(); + } + + function closeSearch() { + if( !searchElement ) render(); + + searchElement.style.display = 'none'; + if(hilitor) hilitor.remove(); + } + + function toggleSearch() { + if( !searchElement ) render(); + + if (searchElement.style.display !== 'inline') { + openSearch(); + } + else { + closeSearch(); + } + } + + function doSearch() { + //if there's been a change in the search term, perform a new search: + if (searchboxDirty) { + var searchstring = searchInput.value; + + if (searchstring === '') { + if(hilitor) hilitor.remove(); + matchedSlides = null; + } + else { + //find the keyword amongst the slides + hilitor = new Hilitor("slidecontent"); + matchedSlides = hilitor.apply(searchstring); + currentMatchedIndex = 0; + } + } + + if (matchedSlides) { + //navigate to the next slide that has the keyword, wrapping to the first if necessary + if (matchedSlides.length && (matchedSlides.length <= currentMatchedIndex)) { + currentMatchedIndex = 0; + } + if (matchedSlides.length > currentMatchedIndex) { + deck.slide(matchedSlides[currentMatchedIndex].h, matchedSlides[currentMatchedIndex].v); + currentMatchedIndex++; + } + } + } + + // Original JavaScript code by Chirp Internet: www.chirp.com.au + // Please acknowledge use of this code by including this header. + // 2/2013 jon: modified regex to display any match, not restricted to word boundaries. + function Hilitor(id, tag) { + + var targetNode = document.getElementById(id) || document.body; + var hiliteTag = tag || "EM"; + var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$"); + var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"]; + var wordColor = []; + var colorIdx = 0; + var matchRegex = ""; + var matchingSlides = []; + + this.setRegex = function(input) + { + input = input.replace(/^[^\w]+|[^\w]+$/g, "").replace(/[^\w'-]+/g, "|"); + matchRegex = new RegExp("(" + input + ")","i"); + } + + this.getRegex = function() + { + return matchRegex.toString().replace(/^\/\\b\(|\)\\b\/i$/g, "").replace(/\|/g, " "); + } + + // recursively apply word highlighting + this.hiliteWords = function(node) + { + if(node == undefined || !node) return; + if(!matchRegex) return; + if(skipTags.test(node.nodeName)) return; + + if(node.hasChildNodes()) { + for(var i=0; i < node.childNodes.length; i++) + this.hiliteWords(node.childNodes[i]); + } + if(node.nodeType == 3) { // NODE_TEXT + var nv, regs; + if((nv = node.nodeValue) && (regs = matchRegex.exec(nv))) { + //find the slide's section element and save it in our list of matching slides + var secnode = node; + while (secnode != null && secnode.nodeName != 'SECTION') { + secnode = secnode.parentNode; + } + + var slideIndex = deck.getIndices(secnode); + var slidelen = matchingSlides.length; + var alreadyAdded = false; + for (var i=0; i < slidelen; i++) { + if ( (matchingSlides[i].h === slideIndex.h) && (matchingSlides[i].v === slideIndex.v) ) { + alreadyAdded = true; + } + } + if (! alreadyAdded) { + matchingSlides.push(slideIndex); + } + + if(!wordColor[regs[0].toLowerCase()]) { + wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length]; + } + + var match = document.createElement(hiliteTag); + match.appendChild(document.createTextNode(regs[0])); + match.style.backgroundColor = wordColor[regs[0].toLowerCase()]; + match.style.fontStyle = "inherit"; + match.style.color = "#000"; + + var after = node.splitText(regs.index); + after.nodeValue = after.nodeValue.substring(regs[0].length); + node.parentNode.insertBefore(match, after); + } + } + }; + + // remove highlighting + this.remove = function() + { + var arr = document.getElementsByTagName(hiliteTag); + var el; + while(arr.length && (el = arr[0])) { + el.parentNode.replaceChild(el.firstChild, el); + } + }; + + // start highlighting at target node + this.apply = function(input) + { + if(input == undefined || !input) return; + this.remove(); + this.setRegex(input); + this.hiliteWords(targetNode); + return matchingSlides; + }; + + } + + return { + + id: 'search', + + init: reveal => { + + deck = reveal; + deck.registerKeyboardShortcut( 'CTRL + Shift + F', 'Search' ); + + document.addEventListener( 'keydown', function( event ) { + if( event.key == "F" && (event.ctrlKey || event.metaKey) ) { //Control+Shift+f + event.preventDefault(); + toggleSearch(); + } + }, false ); + + }, + + open: openSearch + + } +}; + +export default Plugin; \ No newline at end of file diff --git a/2311/site_libs/revealjs/plugin/search/search.esm.js b/2311/site_libs/revealjs/plugin/search/search.esm.js new file mode 100644 index 00000000..b401a707 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/search/search.esm.js @@ -0,0 +1,7 @@ +var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},t=function(e){try{return!!e()}catch(e){return!0}},n=!t((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),r=function(e){return e&&e.Math==Math&&e},o=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof e&&e)||function(){return this}()||Function("return this")(),i=t,c=/#|\.prototype\./,a=function(e,t){var n=l[u(e)];return n==s||n!=f&&("function"==typeof t?i(t):!!t)},u=a.normalize=function(e){return String(e).replace(c,".").toLowerCase()},l=a.data={},f=a.NATIVE="N",s=a.POLYFILL="P",p=a,g=function(e){return"object"==typeof e?null!==e:"function"==typeof e},d=g,h=function(e){if(!d(e))throw TypeError(String(e)+" is not an object");return e},y=g,v=h,x=function(e){if(!y(e)&&null!==e)throw TypeError("Can't set "+String(e)+" as a prototype");return e},b=Object.setPrototypeOf||("__proto__"in{}?function(){var e,t=!1,n={};try{(e=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set).call(n,[]),t=n instanceof Array}catch(e){}return function(n,r){return v(n),x(r),t?e.call(n,r):n.__proto__=r,n}}():void 0),E=g,m=b,S={},w=g,O=o.document,R=w(O)&&w(O.createElement),T=function(e){return R?O.createElement(e):{}},_=!n&&!t((function(){return 7!=Object.defineProperty(T("div"),"a",{get:function(){return 7}}).a})),j=g,P=function(e,t){if(!j(e))return e;var n,r;if(t&&"function"==typeof(n=e.toString)&&!j(r=n.call(e)))return r;if("function"==typeof(n=e.valueOf)&&!j(r=n.call(e)))return r;if(!t&&"function"==typeof(n=e.toString)&&!j(r=n.call(e)))return r;throw TypeError("Can't convert object to primitive value")},I=n,C=_,N=h,A=P,k=Object.defineProperty;S.f=I?k:function(e,t,n){if(N(e),t=A(t,!0),N(n),C)try{return k(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(e[t]=n.value),e};var $={},L=function(e){if(null==e)throw TypeError("Can't call method on "+e);return e},M=L,U=function(e){return Object(M(e))},D=U,F={}.hasOwnProperty,z=function(e,t){return F.call(D(e),t)},K={}.toString,B=function(e){return K.call(e).slice(8,-1)},W=B,G="".split,V=t((function(){return!Object("z").propertyIsEnumerable(0)}))?function(e){return"String"==W(e)?G.call(e,""):Object(e)}:Object,Y=L,q=function(e){return V(Y(e))},X=Math.ceil,H=Math.floor,J=function(e){return isNaN(e=+e)?0:(e>0?H:X)(e)},Q=J,Z=Math.min,ee=function(e){return e>0?Z(Q(e),9007199254740991):0},te=J,ne=Math.max,re=Math.min,oe=q,ie=ee,ce=function(e,t){var n=te(e);return n<0?ne(n+t,0):re(n,t)},ae=function(e){return function(t,n,r){var o,i=oe(t),c=ie(i.length),a=ce(r,c);if(e&&n!=n){for(;c>a;)if((o=i[a++])!=o)return!0}else for(;c>a;a++)if((e||a in i)&&i[a]===n)return e||a||0;return!e&&-1}},ue={includes:ae(!0),indexOf:ae(!1)},le={},fe=z,se=q,pe=ue.indexOf,ge=le,de=function(e,t){var n,r=se(e),o=0,i=[];for(n in r)!fe(ge,n)&&fe(r,n)&&i.push(n);for(;t.length>o;)fe(r,n=t[o++])&&(~pe(i,n)||i.push(n));return i},he=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"].concat("length","prototype");$.f=Object.getOwnPropertyNames||function(e){return de(e,he)};var ye={exports:{}},ve=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}},xe=S,be=ve,Ee=n?function(e,t,n){return xe.f(e,t,be(1,n))}:function(e,t,n){return e[t]=n,e},me=o,Se=Ee,we=function(e,t){try{Se(me,e,t)}catch(n){me[e]=t}return t},Oe=we,Re=o["__core-js_shared__"]||Oe("__core-js_shared__",{}),Te=Re;(ye.exports=function(e,t){return Te[e]||(Te[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.12.1",mode:"global",copyright:"© 2021 Denis Pushkarev (zloirock.ru)"});var _e,je,Pe=0,Ie=Math.random(),Ce=function(e){return"Symbol("+String(void 0===e?"":e)+")_"+(++Pe+Ie).toString(36)},Ne=o,Ae=o,ke=function(e){return"function"==typeof e?e:void 0},$e=function(e,t){return arguments.length<2?ke(Ne[e])||ke(Ae[e]):Ne[e]&&Ne[e][t]||Ae[e]&&Ae[e][t]},Le=$e("navigator","userAgent")||"",Me=o.process,Ue=Me&&Me.versions,De=Ue&&Ue.v8;De?je=(_e=De.split("."))[0]<4?1:_e[0]+_e[1]:Le&&(!(_e=Le.match(/Edge\/(\d+)/))||_e[1]>=74)&&(_e=Le.match(/Chrome\/(\d+)/))&&(je=_e[1]);var Fe=je&&+je,ze=t,Ke=!!Object.getOwnPropertySymbols&&!ze((function(){return!String(Symbol())||!Symbol.sham&&Fe&&Fe<41})),Be=Ke&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,We=o,Ge=ye.exports,Ve=z,Ye=Ce,qe=Ke,Xe=Be,He=Ge("wks"),Je=We.Symbol,Qe=Xe?Je:Je&&Je.withoutSetter||Ye,Ze=function(e){return Ve(He,e)&&(qe||"string"==typeof He[e])||(qe&&Ve(Je,e)?He[e]=Je[e]:He[e]=Qe("Symbol."+e)),He[e]},et=g,tt=B,nt=Ze("match"),rt=h,ot=function(){var e=rt(this),t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.dotAll&&(t+="s"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t},it={},ct=t;function at(e,t){return RegExp(e,t)}it.UNSUPPORTED_Y=ct((function(){var e=at("a","y");return e.lastIndex=2,null!=e.exec("abcd")})),it.BROKEN_CARET=ct((function(){var e=at("^r","gy");return e.lastIndex=2,null!=e.exec("str")}));var ut={exports:{}},lt=Re,ft=Function.toString;"function"!=typeof lt.inspectSource&&(lt.inspectSource=function(e){return ft.call(e)});var st,pt,gt,dt=lt.inspectSource,ht=dt,yt=o.WeakMap,vt="function"==typeof yt&&/native code/.test(ht(yt)),xt=ye.exports,bt=Ce,Et=xt("keys"),mt=vt,St=g,wt=Ee,Ot=z,Rt=Re,Tt=function(e){return Et[e]||(Et[e]=bt(e))},_t=le,jt=o.WeakMap;if(mt||Rt.state){var Pt=Rt.state||(Rt.state=new jt),It=Pt.get,Ct=Pt.has,Nt=Pt.set;st=function(e,t){if(Ct.call(Pt,e))throw new TypeError("Object already initialized");return t.facade=e,Nt.call(Pt,e,t),t},pt=function(e){return It.call(Pt,e)||{}},gt=function(e){return Ct.call(Pt,e)}}else{var At=Tt("state");_t[At]=!0,st=function(e,t){if(Ot(e,At))throw new TypeError("Object already initialized");return t.facade=e,wt(e,At,t),t},pt=function(e){return Ot(e,At)?e[At]:{}},gt=function(e){return Ot(e,At)}}var kt={set:st,get:pt,has:gt,enforce:function(e){return gt(e)?pt(e):st(e,{})},getterFor:function(e){return function(t){var n;if(!St(t)||(n=pt(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}},$t=o,Lt=Ee,Mt=z,Ut=we,Dt=dt,Ft=kt.get,zt=kt.enforce,Kt=String(String).split("String");(ut.exports=function(e,t,n,r){var o,i=!!r&&!!r.unsafe,c=!!r&&!!r.enumerable,a=!!r&&!!r.noTargetGet;"function"==typeof n&&("string"!=typeof t||Mt(n,"name")||Lt(n,"name",t),(o=zt(n)).source||(o.source=Kt.join("string"==typeof t?t:""))),e!==$t?(i?!a&&e[t]&&(c=!0):delete e[t],c?e[t]=n:Lt(e,t,n)):c?e[t]=n:Ut(t,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&Ft(this).source||Dt(this)}));var Bt=$e,Wt=S,Gt=n,Vt=Ze("species"),Yt=n,qt=o,Xt=p,Ht=function(e,t,n){var r,o;return m&&"function"==typeof(r=t.constructor)&&r!==n&&E(o=r.prototype)&&o!==n.prototype&&m(e,o),e},Jt=S.f,Qt=$.f,Zt=function(e){var t;return et(e)&&(void 0!==(t=e[nt])?!!t:"RegExp"==tt(e))},en=ot,tn=it,nn=ut.exports,rn=t,on=kt.enforce,cn=function(e){var t=Bt(e),n=Wt.f;Gt&&t&&!t[Vt]&&n(t,Vt,{configurable:!0,get:function(){return this}})},an=Ze("match"),un=qt.RegExp,ln=un.prototype,fn=/a/g,sn=/a/g,pn=new un(fn)!==fn,gn=tn.UNSUPPORTED_Y;if(Yt&&Xt("RegExp",!pn||gn||rn((function(){return sn[an]=!1,un(fn)!=fn||un(sn)==sn||"/a/i"!=un(fn,"i")})))){for(var dn=function(e,t){var n,r=this instanceof dn,o=Zt(e),i=void 0===t;if(!r&&o&&e.constructor===dn&&i)return e;pn?o&&!i&&(e=e.source):e instanceof dn&&(i&&(t=en.call(e)),e=e.source),gn&&(n=!!t&&t.indexOf("y")>-1)&&(t=t.replace(/y/g,""));var c=Ht(pn?new un(e,t):un(e,t),r?this:ln,dn);gn&&n&&(on(c).sticky=!0);return c},hn=function(e){e in dn||Jt(dn,e,{configurable:!0,get:function(){return un[e]},set:function(t){un[e]=t}})},yn=Qt(un),vn=0;yn.length>vn;)hn(yn[vn++]);ln.constructor=dn,dn.prototype=ln,nn(qt,"RegExp",dn)}cn("RegExp");var xn={},bn={},En={}.propertyIsEnumerable,mn=Object.getOwnPropertyDescriptor,Sn=mn&&!En.call({1:2},1);bn.f=Sn?function(e){var t=mn(this,e);return!!t&&t.enumerable}:En;var wn=n,On=bn,Rn=ve,Tn=q,_n=P,jn=z,Pn=_,In=Object.getOwnPropertyDescriptor;xn.f=wn?In:function(e,t){if(e=Tn(e),t=_n(t,!0),Pn)try{return In(e,t)}catch(e){}if(jn(e,t))return Rn(!On.f.call(e,t),e[t])};var Cn={};Cn.f=Object.getOwnPropertySymbols;var Nn=$,An=Cn,kn=h,$n=$e("Reflect","ownKeys")||function(e){var t=Nn.f(kn(e)),n=An.f;return n?t.concat(n(e)):t},Ln=z,Mn=$n,Un=xn,Dn=S,Fn=o,zn=xn.f,Kn=Ee,Bn=ut.exports,Wn=we,Gn=function(e,t){for(var n=Mn(t),r=Dn.f,o=Un.f,i=0;i0&&(!i.multiline||i.multiline&&"\n"!==e[i.lastIndex-1])&&(u="(?: "+u+")",f=" "+f,l++),n=new RegExp("^(?:"+u+")",a)),tr&&(n=new RegExp("^"+u+"$(?!\\s)",a)),Zn&&(t=i.lastIndex),r=Hn.call(c?n:i,f),c?r?(r.input=r.input.slice(l),r[0]=r[0].slice(l),r.index=i.lastIndex,i.lastIndex+=r[0].length):i.lastIndex=0:Zn&&r&&(i.lastIndex=i.global?r.index+r[0].length:t),tr&&r&&r.length>1&&Jn.call(r[0],n,(function(){for(o=1;o")})),br="$0"==="a".replace(/./,"$0"),Er=dr("replace"),mr=!!/./[Er]&&""===/./[Er]("a","$0"),Sr=!gr((function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]})),wr=J,Or=L,Rr=function(e){return function(t,n){var r,o,i=String(Or(t)),c=wr(n),a=i.length;return c<0||c>=a?e?"":void 0:(r=i.charCodeAt(c))<55296||r>56319||c+1===a||(o=i.charCodeAt(c+1))<56320||o>57343?e?i.charAt(c):r:e?i.slice(c,c+2):o-56320+(r-55296<<10)+65536}},Tr={codeAt:Rr(!1),charAt:Rr(!0)}.charAt,_r=U,jr=Math.floor,Pr="".replace,Ir=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,Cr=/\$([$&'`]|\d{1,2})/g,Nr=B,Ar=nr,kr=function(e,t,n,r){var o=dr(e),i=!gr((function(){var t={};return t[o]=function(){return 7},7!=""[e](t)})),c=i&&!gr((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[yr]=function(){return n},n.flags="",n[o]=/./[o]),n.exec=function(){return t=!0,null},n[o](""),!t}));if(!i||!c||"replace"===e&&(!xr||!br||mr)||"split"===e&&!Sr){var a=/./[o],u=n(o,""[e],(function(e,t,n,r,o){var c=t.exec;return c===pr||c===vr.exec?i&&!o?{done:!0,value:a.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),{REPLACE_KEEPS_$0:br,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:mr}),l=u[0],f=u[1];sr(String.prototype,e,l),sr(vr,o,2==t?function(e,t){return f.call(e,this,t)}:function(e){return f.call(e,this)})}r&&hr(vr[o],"sham",!0)},$r=h,Lr=ee,Mr=J,Ur=L,Dr=function(e,t,n){return t+(n?Tr(e,t).length:1)},Fr=function(e,t,n,r,o,i){var c=n+e.length,a=r.length,u=Cr;return void 0!==o&&(o=_r(o),u=Ir),Pr.call(i,u,(function(i,u){var l;switch(u.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,n);case"'":return t.slice(c);case"<":l=o[u.slice(1,-1)];break;default:var f=+u;if(0===f)return i;if(f>a){var s=jr(f/10);return 0===s?i:s<=a?void 0===r[s-1]?u.charAt(1):r[s-1]+u.charAt(1):i}l=r[f-1]}return void 0===l?"":l}))},zr=function(e,t){var n=e.exec;if("function"==typeof n){var r=n.call(e,t);if("object"!=typeof r)throw TypeError("RegExp exec method returned something other than an Object or null");return r}if("RegExp"!==Nr(e))throw TypeError("RegExp#exec called on incompatible receiver");return Ar.call(e,t)},Kr=Math.max,Br=Math.min;kr("replace",2,(function(e,t,n,r){var o=r.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,i=r.REPLACE_KEEPS_$0,c=o?"$":"$0";return[function(n,r){var o=Ur(this),i=null==n?void 0:n[e];return void 0!==i?i.call(n,o,r):t.call(String(o),n,r)},function(e,r){if(!o&&i||"string"==typeof r&&-1===r.indexOf(c)){var a=n(t,e,this,r);if(a.done)return a.value}var u=$r(e),l=String(this),f="function"==typeof r;f||(r=String(r));var s=u.global;if(s){var p=u.unicode;u.lastIndex=0}for(var g=[];;){var d=zr(u,l);if(null===d)break;if(g.push(d),!s)break;""===String(d[0])&&(u.lastIndex=Dr(l,Lr(u.lastIndex),p))}for(var h,y="",v=0,x=0;x=v&&(y+=l.slice(v,E)+R,v=E+b.length)}return y+l.slice(v)}]}));var Wr={};Wr[Ze("toStringTag")]="z";var Gr="[object z]"===String(Wr),Vr=Gr,Yr=B,qr=Ze("toStringTag"),Xr="Arguments"==Yr(function(){return arguments}()),Hr=Vr?Yr:function(e){var t,n,r;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),qr))?n:Xr?Yr(t):"Object"==(r=Yr(t))&&"function"==typeof t.callee?"Arguments":r},Jr=Gr?{}.toString:function(){return"[object "+Hr(this)+"]"},Qr=Gr,Zr=ut.exports,eo=Jr;Qr||Zr(Object.prototype,"toString",eo,{unsafe:!0}) +/*! + * Handles finding a text string anywhere in the slides and showing the next occurrence to the user + * by navigatating to that slide and highlighting it. + * + * @author Jon Snyder , February 2013 + */;export default function(){var e,t,n,r,o,i,c;function a(){(t=document.createElement("div")).classList.add("searchbox"),t.style.position="absolute",t.style.top="10px",t.style.right="10px",t.style.zIndex=10,t.innerHTML='\n\t\t',(n=t.querySelector(".searchinput")).style.width="240px",n.style.fontSize="14px",n.style.padding="4px 6px",n.style.color="#000",n.style.background="#fff",n.style.borderRadius="2px",n.style.border="0",n.style.outline="0",n.style.boxShadow="0 2px 18px rgba(0, 0, 0, 0.2)",n.style["-webkit-appearance"]="none",e.getRevealElement().appendChild(t),n.addEventListener("keyup",(function(t){switch(t.keyCode){case 13:t.preventDefault(),function(){if(i){var t=n.value;""===t?(c&&c.remove(),r=null):(c=new f("slidecontent"),r=c.apply(t),o=0)}r&&(r.length&&r.length<=o&&(o=0),r.length>o&&(e.slide(r[o].h,r[o].v),o++))}(),i=!1;break;default:i=!0}}),!1),l()}function u(){t||a(),t.style.display="inline",n.focus(),n.select()}function l(){t||a(),t.style.display="none",c&&c.remove()}function f(t,n){var r=document.getElementById(t)||document.body,o=n||"EM",i=new RegExp("^(?:"+o+"|SCRIPT|FORM)$"),c=["#ff6","#a0ffff","#9f9","#f99","#f6f"],a=[],u=0,l="",f=[];this.setRegex=function(e){e=e.replace(/^[^\w]+|[^\w]+$/g,"").replace(/[^\w'-]+/g,"|"),l=new RegExp("("+e+")","i")},this.getRegex=function(){return l.toString().replace(/^\/\\b\(|\)\\b\/i$/g,"").replace(/\|/g," ")},this.hiliteWords=function(t){if(null!=t&&t&&l&&!i.test(t.nodeName)){if(t.hasChildNodes())for(var n=0;n0?H:X)(e)},Q=J,Z=Math.min,ee=function(e){return e>0?Z(Q(e),9007199254740991):0},te=J,ne=Math.max,re=Math.min,oe=q,ie=ee,ce=function(e,t){var n=te(e);return n<0?ne(n+t,0):re(n,t)},ae=function(e){return function(t,n,r){var o,i=oe(t),c=ie(i.length),a=ce(r,c);if(e&&n!=n){for(;c>a;)if((o=i[a++])!=o)return!0}else for(;c>a;a++)if((e||a in i)&&i[a]===n)return e||a||0;return!e&&-1}},ue={includes:ae(!0),indexOf:ae(!1)},le={},fe=z,se=q,pe=ue.indexOf,de=le,ge=function(e,t){var n,r=se(e),o=0,i=[];for(n in r)!fe(de,n)&&fe(r,n)&&i.push(n);for(;t.length>o;)fe(r,n=t[o++])&&(~pe(i,n)||i.push(n));return i},he=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"].concat("length","prototype");$.f=Object.getOwnPropertyNames||function(e){return ge(e,he)};var ye={exports:{}},ve=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}},xe=S,be=ve,me=n?function(e,t,n){return xe.f(e,t,be(1,n))}:function(e,t,n){return e[t]=n,e},Ee=o,Se=me,we=function(e,t){try{Se(Ee,e,t)}catch(n){Ee[e]=t}return t},Oe=we,Re="__core-js_shared__",Te=o[Re]||Oe(Re,{}),_e=Te;(ye.exports=function(e,t){return _e[e]||(_e[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.12.1",mode:"global",copyright:"© 2021 Denis Pushkarev (zloirock.ru)"});var je,Pe,Ie=0,Ce=Math.random(),Ne=function(e){return"Symbol("+String(void 0===e?"":e)+")_"+(++Ie+Ce).toString(36)},Ae=o,ke=o,$e=function(e){return"function"==typeof e?e:void 0},Le=function(e,t){return arguments.length<2?$e(Ae[e])||$e(ke[e]):Ae[e]&&Ae[e][t]||ke[e]&&ke[e][t]},Me=Le("navigator","userAgent")||"",Ue=o.process,De=Ue&&Ue.versions,Fe=De&&De.v8;Fe?Pe=(je=Fe.split("."))[0]<4?1:je[0]+je[1]:Me&&(!(je=Me.match(/Edge\/(\d+)/))||je[1]>=74)&&(je=Me.match(/Chrome\/(\d+)/))&&(Pe=je[1]);var ze=Pe&&+Pe,Ke=t,Be=!!Object.getOwnPropertySymbols&&!Ke((function(){return!String(Symbol())||!Symbol.sham&&ze&&ze<41})),We=Be&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,Ge=o,Ve=ye.exports,Ye=z,qe=Ne,Xe=Be,He=We,Je=Ve("wks"),Qe=Ge.Symbol,Ze=He?Qe:Qe&&Qe.withoutSetter||qe,et=function(e){return Ye(Je,e)&&(Xe||"string"==typeof Je[e])||(Xe&&Ye(Qe,e)?Je[e]=Qe[e]:Je[e]=Ze("Symbol."+e)),Je[e]},tt=d,nt=B,rt=et("match"),ot=h,it=function(){var e=ot(this),t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.dotAll&&(t+="s"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t},ct={},at=t;function ut(e,t){return RegExp(e,t)}ct.UNSUPPORTED_Y=at((function(){var e=ut("a","y");return e.lastIndex=2,null!=e.exec("abcd")})),ct.BROKEN_CARET=at((function(){var e=ut("^r","gy");return e.lastIndex=2,null!=e.exec("str")}));var lt={exports:{}},ft=Te,st=Function.toString;"function"!=typeof ft.inspectSource&&(ft.inspectSource=function(e){return st.call(e)});var pt,dt,gt,ht=ft.inspectSource,yt=ht,vt=o.WeakMap,xt="function"==typeof vt&&/native code/.test(yt(vt)),bt=ye.exports,mt=Ne,Et=bt("keys"),St=xt,wt=d,Ot=me,Rt=z,Tt=Te,_t=function(e){return Et[e]||(Et[e]=mt(e))},jt=le,Pt="Object already initialized",It=o.WeakMap;if(St||Tt.state){var Ct=Tt.state||(Tt.state=new It),Nt=Ct.get,At=Ct.has,kt=Ct.set;pt=function(e,t){if(At.call(Ct,e))throw new TypeError(Pt);return t.facade=e,kt.call(Ct,e,t),t},dt=function(e){return Nt.call(Ct,e)||{}},gt=function(e){return At.call(Ct,e)}}else{var $t=_t("state");jt[$t]=!0,pt=function(e,t){if(Rt(e,$t))throw new TypeError(Pt);return t.facade=e,Ot(e,$t,t),t},dt=function(e){return Rt(e,$t)?e[$t]:{}},gt=function(e){return Rt(e,$t)}}var Lt={set:pt,get:dt,has:gt,enforce:function(e){return gt(e)?dt(e):pt(e,{})},getterFor:function(e){return function(t){var n;if(!wt(t)||(n=dt(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}},Mt=o,Ut=me,Dt=z,Ft=we,zt=ht,Kt=Lt.get,Bt=Lt.enforce,Wt=String(String).split("String");(lt.exports=function(e,t,n,r){var o,i=!!r&&!!r.unsafe,c=!!r&&!!r.enumerable,a=!!r&&!!r.noTargetGet;"function"==typeof n&&("string"!=typeof t||Dt(n,"name")||Ut(n,"name",t),(o=Bt(n)).source||(o.source=Wt.join("string"==typeof t?t:""))),e!==Mt?(i?!a&&e[t]&&(c=!0):delete e[t],c?e[t]=n:Ut(e,t,n)):c?e[t]=n:Ft(t,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&Kt(this).source||zt(this)}));var Gt=Le,Vt=S,Yt=n,qt=et("species"),Xt=n,Ht=o,Jt=p,Qt=function(e,t,n){var r,o;return E&&"function"==typeof(r=t.constructor)&&r!==n&&m(o=r.prototype)&&o!==n.prototype&&E(e,o),e},Zt=S.f,en=$.f,tn=function(e){var t;return tt(e)&&(void 0!==(t=e[rt])?!!t:"RegExp"==nt(e))},nn=it,rn=ct,on=lt.exports,cn=t,an=Lt.enforce,un=function(e){var t=Gt(e),n=Vt.f;Yt&&t&&!t[qt]&&n(t,qt,{configurable:!0,get:function(){return this}})},ln=et("match"),fn=Ht.RegExp,sn=fn.prototype,pn=/a/g,dn=/a/g,gn=new fn(pn)!==pn,hn=rn.UNSUPPORTED_Y;if(Xt&&Jt("RegExp",!gn||hn||cn((function(){return dn[ln]=!1,fn(pn)!=pn||fn(dn)==dn||"/a/i"!=fn(pn,"i")})))){for(var yn=function(e,t){var n,r=this instanceof yn,o=tn(e),i=void 0===t;if(!r&&o&&e.constructor===yn&&i)return e;gn?o&&!i&&(e=e.source):e instanceof yn&&(i&&(t=nn.call(e)),e=e.source),hn&&(n=!!t&&t.indexOf("y")>-1)&&(t=t.replace(/y/g,""));var c=Qt(gn?new fn(e,t):fn(e,t),r?this:sn,yn);hn&&n&&(an(c).sticky=!0);return c},vn=function(e){e in yn||Zt(yn,e,{configurable:!0,get:function(){return fn[e]},set:function(t){fn[e]=t}})},xn=en(fn),bn=0;xn.length>bn;)vn(xn[bn++]);sn.constructor=yn,yn.prototype=sn,on(Ht,"RegExp",yn)}un("RegExp");var mn={},En={},Sn={}.propertyIsEnumerable,wn=Object.getOwnPropertyDescriptor,On=wn&&!Sn.call({1:2},1);En.f=On?function(e){var t=wn(this,e);return!!t&&t.enumerable}:Sn;var Rn=n,Tn=En,_n=ve,jn=q,Pn=P,In=z,Cn=_,Nn=Object.getOwnPropertyDescriptor;mn.f=Rn?Nn:function(e,t){if(e=jn(e),t=Pn(t,!0),Cn)try{return Nn(e,t)}catch(e){}if(In(e,t))return _n(!Tn.f.call(e,t),e[t])};var An={};An.f=Object.getOwnPropertySymbols;var kn=$,$n=An,Ln=h,Mn=Le("Reflect","ownKeys")||function(e){var t=kn.f(Ln(e)),n=$n.f;return n?t.concat(n(e)):t},Un=z,Dn=Mn,Fn=mn,zn=S,Kn=o,Bn=mn.f,Wn=me,Gn=lt.exports,Vn=we,Yn=function(e,t){for(var n=Dn(t),r=zn.f,o=Fn.f,i=0;i0&&(!i.multiline||i.multiline&&"\n"!==e[i.lastIndex-1])&&(u="(?: "+u+")",f=" "+f,l++),n=new RegExp("^(?:"+u+")",a)),rr&&(n=new RegExp("^"+u+"$(?!\\s)",a)),tr&&(t=i.lastIndex),r=Qn.call(c?n:i,f),c?r?(r.input=r.input.slice(l),r[0]=r[0].slice(l),r.index=i.lastIndex,i.lastIndex+=r[0].length):i.lastIndex=0:tr&&r&&(i.lastIndex=i.global?r.index+r[0].length:t),rr&&r&&r.length>1&&Zn.call(r[0],n,(function(){for(o=1;o")})),Sr="$0"==="a".replace(/./,"$0"),wr=vr("replace"),Or=!!/./[wr]&&""===/./[wr]("a","$0"),Rr=!yr((function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]})),Tr=J,_r=L,jr=function(e){return function(t,n){var r,o,i=String(_r(t)),c=Tr(n),a=i.length;return c<0||c>=a?e?"":void 0:(r=i.charCodeAt(c))<55296||r>56319||c+1===a||(o=i.charCodeAt(c+1))<56320||o>57343?e?i.charAt(c):r:e?i.slice(c,c+2):o-56320+(r-55296<<10)+65536}},Pr={codeAt:jr(!1),charAt:jr(!0)}.charAt,Ir=U,Cr=Math.floor,Nr="".replace,Ar=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,kr=/\$([$&'`]|\d{1,2})/g,$r=B,Lr=or,Mr=function(e,t,n,r){var o=vr(e),i=!yr((function(){var t={};return t[o]=function(){return 7},7!=""[e](t)})),c=i&&!yr((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[br]=function(){return n},n.flags="",n[o]=/./[o]),n.exec=function(){return t=!0,null},n[o](""),!t}));if(!i||!c||"replace"===e&&(!Er||!Sr||Or)||"split"===e&&!Rr){var a=/./[o],u=n(o,""[e],(function(e,t,n,r,o){var c=t.exec;return c===hr||c===mr.exec?i&&!o?{done:!0,value:a.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),{REPLACE_KEEPS_$0:Sr,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:Or}),l=u[0],f=u[1];gr(String.prototype,e,l),gr(mr,o,2==t?function(e,t){return f.call(e,this,t)}:function(e){return f.call(e,this)})}r&&xr(mr[o],"sham",!0)},Ur=h,Dr=ee,Fr=J,zr=L,Kr=function(e,t,n){return t+(n?Pr(e,t).length:1)},Br=function(e,t,n,r,o,i){var c=n+e.length,a=r.length,u=kr;return void 0!==o&&(o=Ir(o),u=Ar),Nr.call(i,u,(function(i,u){var l;switch(u.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,n);case"'":return t.slice(c);case"<":l=o[u.slice(1,-1)];break;default:var f=+u;if(0===f)return i;if(f>a){var s=Cr(f/10);return 0===s?i:s<=a?void 0===r[s-1]?u.charAt(1):r[s-1]+u.charAt(1):i}l=r[f-1]}return void 0===l?"":l}))},Wr=function(e,t){var n=e.exec;if("function"==typeof n){var r=n.call(e,t);if("object"!=typeof r)throw TypeError("RegExp exec method returned something other than an Object or null");return r}if("RegExp"!==$r(e))throw TypeError("RegExp#exec called on incompatible receiver");return Lr.call(e,t)},Gr=Math.max,Vr=Math.min;Mr("replace",2,(function(e,t,n,r){var o=r.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,i=r.REPLACE_KEEPS_$0,c=o?"$":"$0";return[function(n,r){var o=zr(this),i=null==n?void 0:n[e];return void 0!==i?i.call(n,o,r):t.call(String(o),n,r)},function(e,r){if(!o&&i||"string"==typeof r&&-1===r.indexOf(c)){var a=n(t,e,this,r);if(a.done)return a.value}var u=Ur(e),l=String(this),f="function"==typeof r;f||(r=String(r));var s=u.global;if(s){var p=u.unicode;u.lastIndex=0}for(var d=[];;){var g=Wr(u,l);if(null===g)break;if(d.push(g),!s)break;""===String(g[0])&&(u.lastIndex=Kr(l,Dr(u.lastIndex),p))}for(var h,y="",v=0,x=0;x=v&&(y+=l.slice(v,m)+R,v=m+b.length)}return y+l.slice(v)}]}));var Yr={};Yr[et("toStringTag")]="z";var qr="[object z]"===String(Yr),Xr=qr,Hr=B,Jr=et("toStringTag"),Qr="Arguments"==Hr(function(){return arguments}()),Zr=Xr?Hr:function(e){var t,n,r;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),Jr))?n:Qr?Hr(t):"Object"==(r=Hr(t))&&"function"==typeof t.callee?"Arguments":r},eo=qr?{}.toString:function(){return"[object "+Zr(this)+"]"},to=qr,no=lt.exports,ro=eo;to||no(Object.prototype,"toString",ro,{unsafe:!0}) +/*! + * Handles finding a text string anywhere in the slides and showing the next occurrence to the user + * by navigatating to that slide and highlighting it. + * + * @author Jon Snyder , February 2013 + */;return function(){var e,t,n,r,o,i,c;function a(){(t=document.createElement("div")).classList.add("searchbox"),t.style.position="absolute",t.style.top="10px",t.style.right="10px",t.style.zIndex=10,t.innerHTML='\n\t\t',(n=t.querySelector(".searchinput")).style.width="240px",n.style.fontSize="14px",n.style.padding="4px 6px",n.style.color="#000",n.style.background="#fff",n.style.borderRadius="2px",n.style.border="0",n.style.outline="0",n.style.boxShadow="0 2px 18px rgba(0, 0, 0, 0.2)",n.style["-webkit-appearance"]="none",e.getRevealElement().appendChild(t),n.addEventListener("keyup",(function(t){switch(t.keyCode){case 13:t.preventDefault(),function(){if(i){var t=n.value;""===t?(c&&c.remove(),r=null):(c=new f("slidecontent"),r=c.apply(t),o=0)}r&&(r.length&&r.length<=o&&(o=0),r.length>o&&(e.slide(r[o].h,r[o].v),o++))}(),i=!1;break;default:i=!0}}),!1),l()}function u(){t||a(),t.style.display="inline",n.focus(),n.select()}function l(){t||a(),t.style.display="none",c&&c.remove()}function f(t,n){var r=document.getElementById(t)||document.body,o=n||"EM",i=new RegExp("^(?:"+o+"|SCRIPT|FORM)$"),c=["#ff6","#a0ffff","#9f9","#f99","#f6f"],a=[],u=0,l="",f=[];this.setRegex=function(e){e=e.replace(/^[^\w]+|[^\w]+$/g,"").replace(/[^\w'-]+/g,"|"),l=new RegExp("("+e+")","i")},this.getRegex=function(){return l.toString().replace(/^\/\\b\(|\)\\b\/i$/g,"").replace(/\|/g," ")},this.hiliteWords=function(t){if(null!=t&&t&&l&&!i.test(t.nodeName)){if(t.hasChildNodes())for(var n=0;n { + + zoom.reset(); + + } + +}; + +export default () => Plugin; + +/*! + * zoom.js 0.3 (modified for use with reveal.js) + * http://lab.hakim.se/zoom-js + * MIT licensed + * + * Copyright (C) 2011-2014 Hakim El Hattab, http://hakim.se + */ +var zoom = (function(){ + + // The current zoom level (scale) + var level = 1; + + // The current mouse position, used for panning + var mouseX = 0, + mouseY = 0; + + // Timeout before pan is activated + var panEngageTimeout = -1, + panUpdateInterval = -1; + + // Check for transform support so that we can fallback otherwise + var supportsTransforms = 'transform' in document.body.style; + + if( supportsTransforms ) { + // The easing that will be applied when we zoom in/out + document.body.style.transition = 'transform 0.8s ease'; + } + + // Zoom out if the user hits escape + document.addEventListener( 'keyup', function( event ) { + if( level !== 1 && event.keyCode === 27 ) { + zoom.out(); + } + } ); + + // Monitor mouse movement for panning + document.addEventListener( 'mousemove', function( event ) { + if( level !== 1 ) { + mouseX = event.clientX; + mouseY = event.clientY; + } + } ); + + /** + * Applies the CSS required to zoom in, prefers the use of CSS3 + * transforms but falls back on zoom for IE. + * + * @param {Object} rect + * @param {Number} scale + */ + function magnify( rect, scale ) { + + var scrollOffset = getScrollOffset(); + + // Ensure a width/height is set + rect.width = rect.width || 1; + rect.height = rect.height || 1; + + // Center the rect within the zoomed viewport + rect.x -= ( window.innerWidth - ( rect.width * scale ) ) / 2; + rect.y -= ( window.innerHeight - ( rect.height * scale ) ) / 2; + + if( supportsTransforms ) { + // Reset + if( scale === 1 ) { + document.body.style.transform = ''; + } + // Scale + else { + var origin = scrollOffset.x +'px '+ scrollOffset.y +'px', + transform = 'translate('+ -rect.x +'px,'+ -rect.y +'px) scale('+ scale +')'; + + document.body.style.transformOrigin = origin; + document.body.style.transform = transform; + } + } + else { + // Reset + if( scale === 1 ) { + document.body.style.position = ''; + document.body.style.left = ''; + document.body.style.top = ''; + document.body.style.width = ''; + document.body.style.height = ''; + document.body.style.zoom = ''; + } + // Scale + else { + document.body.style.position = 'relative'; + document.body.style.left = ( - ( scrollOffset.x + rect.x ) / scale ) + 'px'; + document.body.style.top = ( - ( scrollOffset.y + rect.y ) / scale ) + 'px'; + document.body.style.width = ( scale * 100 ) + '%'; + document.body.style.height = ( scale * 100 ) + '%'; + document.body.style.zoom = scale; + } + } + + level = scale; + + if( document.documentElement.classList ) { + if( level !== 1 ) { + document.documentElement.classList.add( 'zoomed' ); + } + else { + document.documentElement.classList.remove( 'zoomed' ); + } + } + } + + /** + * Pan the document when the mosue cursor approaches the edges + * of the window. + */ + function pan() { + var range = 0.12, + rangeX = window.innerWidth * range, + rangeY = window.innerHeight * range, + scrollOffset = getScrollOffset(); + + // Up + if( mouseY < rangeY ) { + window.scroll( scrollOffset.x, scrollOffset.y - ( 1 - ( mouseY / rangeY ) ) * ( 14 / level ) ); + } + // Down + else if( mouseY > window.innerHeight - rangeY ) { + window.scroll( scrollOffset.x, scrollOffset.y + ( 1 - ( window.innerHeight - mouseY ) / rangeY ) * ( 14 / level ) ); + } + + // Left + if( mouseX < rangeX ) { + window.scroll( scrollOffset.x - ( 1 - ( mouseX / rangeX ) ) * ( 14 / level ), scrollOffset.y ); + } + // Right + else if( mouseX > window.innerWidth - rangeX ) { + window.scroll( scrollOffset.x + ( 1 - ( window.innerWidth - mouseX ) / rangeX ) * ( 14 / level ), scrollOffset.y ); + } + } + + function getScrollOffset() { + return { + x: window.scrollX !== undefined ? window.scrollX : window.pageXOffset, + y: window.scrollY !== undefined ? window.scrollY : window.pageYOffset + } + } + + return { + /** + * Zooms in on either a rectangle or HTML element. + * + * @param {Object} options + * - element: HTML element to zoom in on + * OR + * - x/y: coordinates in non-transformed space to zoom in on + * - width/height: the portion of the screen to zoom in on + * - scale: can be used instead of width/height to explicitly set scale + */ + to: function( options ) { + + // Due to an implementation limitation we can't zoom in + // to another element without zooming out first + if( level !== 1 ) { + zoom.out(); + } + else { + options.x = options.x || 0; + options.y = options.y || 0; + + // If an element is set, that takes precedence + if( !!options.element ) { + // Space around the zoomed in element to leave on screen + var padding = 20; + var bounds = options.element.getBoundingClientRect(); + + options.x = bounds.left - padding; + options.y = bounds.top - padding; + options.width = bounds.width + ( padding * 2 ); + options.height = bounds.height + ( padding * 2 ); + } + + // If width/height values are set, calculate scale from those values + if( options.width !== undefined && options.height !== undefined ) { + options.scale = Math.max( Math.min( window.innerWidth / options.width, window.innerHeight / options.height ), 1 ); + } + + if( options.scale > 1 ) { + options.x *= options.scale; + options.y *= options.scale; + + magnify( options, options.scale ); + + if( options.pan !== false ) { + + // Wait with engaging panning as it may conflict with the + // zoom transition + panEngageTimeout = setTimeout( function() { + panUpdateInterval = setInterval( pan, 1000 / 60 ); + }, 800 ); + + } + } + } + }, + + /** + * Resets the document zoom state to its default. + */ + out: function() { + clearTimeout( panEngageTimeout ); + clearInterval( panUpdateInterval ); + + magnify( { x: 0, y: 0 }, 1 ); + + level = 1; + }, + + // Alias + magnify: function( options ) { this.to( options ) }, + reset: function() { this.out() }, + + zoomLevel: function() { + return level; + } + } + +})(); diff --git a/2311/site_libs/revealjs/plugin/zoom/zoom.esm.js b/2311/site_libs/revealjs/plugin/zoom/zoom.esm.js new file mode 100644 index 00000000..c0e8d7b6 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/zoom/zoom.esm.js @@ -0,0 +1,4 @@ +/*! + * reveal.js Zoom plugin + */ +var e={id:"zoom",init:function(e){e.getRevealElement().addEventListener("mousedown",(function(n){var o=/Linux/.test(window.navigator.platform)?"ctrl":"alt",i=(e.getConfig().zoomKey?e.getConfig().zoomKey:o)+"Key",d=e.getConfig().zoomLevel?e.getConfig().zoomLevel:2;n[i]&&!e.isOverview()&&(n.preventDefault(),t.to({x:n.clientX,y:n.clientY,scale:d,pan:!1}))}))},destroy:function(){t.reset()}},t=function(){var e=1,n=0,o=0,i=-1,d=-1,l="transform"in document.body.style;function s(t,n){var o=r();if(t.width=t.width||1,t.height=t.height||1,t.x-=(window.innerWidth-t.width*n)/2,t.y-=(window.innerHeight-t.height*n)/2,l)if(1===n)document.body.style.transform="";else{var i=o.x+"px "+o.y+"px",d="translate("+-t.x+"px,"+-t.y+"px) scale("+n+")";document.body.style.transformOrigin=i,document.body.style.transform=d}else 1===n?(document.body.style.position="",document.body.style.left="",document.body.style.top="",document.body.style.width="",document.body.style.height="",document.body.style.zoom=""):(document.body.style.position="relative",document.body.style.left=-(o.x+t.x)/n+"px",document.body.style.top=-(o.y+t.y)/n+"px",document.body.style.width=100*n+"%",document.body.style.height=100*n+"%",document.body.style.zoom=n);e=n,document.documentElement.classList&&(1!==e?document.documentElement.classList.add("zoomed"):document.documentElement.classList.remove("zoomed"))}function c(){var t=.12*window.innerWidth,i=.12*window.innerHeight,d=r();owindow.innerHeight-i&&window.scroll(d.x,d.y+(1-(window.innerHeight-o)/i)*(14/e)),nwindow.innerWidth-t&&window.scroll(d.x+(1-(window.innerWidth-n)/t)*(14/e),d.y)}function r(){return{x:void 0!==window.scrollX?window.scrollX:window.pageXOffset,y:void 0!==window.scrollY?window.scrollY:window.pageYOffset}}return l&&(document.body.style.transition="transform 0.8s ease"),document.addEventListener("keyup",(function(n){1!==e&&27===n.keyCode&&t.out()})),document.addEventListener("mousemove",(function(t){1!==e&&(n=t.clientX,o=t.clientY)})),{to:function(n){if(1!==e)t.out();else{if(n.x=n.x||0,n.y=n.y||0,n.element){var o=n.element.getBoundingClientRect();n.x=o.left-20,n.y=o.top-20,n.width=o.width+40,n.height=o.height+40}void 0!==n.width&&void 0!==n.height&&(n.scale=Math.max(Math.min(window.innerWidth/n.width,window.innerHeight/n.height),1)),n.scale>1&&(n.x*=n.scale,n.y*=n.scale,s(n,n.scale),!1!==n.pan&&(i=setTimeout((function(){d=setInterval(c,1e3/60)}),800)))}},out:function(){clearTimeout(i),clearInterval(d),s({x:0,y:0},1),e=1},magnify:function(e){this.to(e)},reset:function(){this.out()},zoomLevel:function(){return e}}}();export default function(){return e} diff --git a/2311/site_libs/revealjs/plugin/zoom/zoom.js b/2311/site_libs/revealjs/plugin/zoom/zoom.js new file mode 100644 index 00000000..b52804d6 --- /dev/null +++ b/2311/site_libs/revealjs/plugin/zoom/zoom.js @@ -0,0 +1,4 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).RevealZoom=t()}(this,(function(){"use strict"; +/*! + * reveal.js Zoom plugin + */var e={id:"zoom",init:function(e){e.getRevealElement().addEventListener("mousedown",(function(o){var n=/Linux/.test(window.navigator.platform)?"ctrl":"alt",i=(e.getConfig().zoomKey?e.getConfig().zoomKey:n)+"Key",d=e.getConfig().zoomLevel?e.getConfig().zoomLevel:2;o[i]&&!e.isOverview()&&(o.preventDefault(),t.to({x:o.clientX,y:o.clientY,scale:d,pan:!1}))}))},destroy:function(){t.reset()}},t=function(){var e=1,o=0,n=0,i=-1,d=-1,l="transform"in document.body.style;function s(t,o){var n=r();if(t.width=t.width||1,t.height=t.height||1,t.x-=(window.innerWidth-t.width*o)/2,t.y-=(window.innerHeight-t.height*o)/2,l)if(1===o)document.body.style.transform="";else{var i=n.x+"px "+n.y+"px",d="translate("+-t.x+"px,"+-t.y+"px) scale("+o+")";document.body.style.transformOrigin=i,document.body.style.transform=d}else 1===o?(document.body.style.position="",document.body.style.left="",document.body.style.top="",document.body.style.width="",document.body.style.height="",document.body.style.zoom=""):(document.body.style.position="relative",document.body.style.left=-(n.x+t.x)/o+"px",document.body.style.top=-(n.y+t.y)/o+"px",document.body.style.width=100*o+"%",document.body.style.height=100*o+"%",document.body.style.zoom=o);e=o,document.documentElement.classList&&(1!==e?document.documentElement.classList.add("zoomed"):document.documentElement.classList.remove("zoomed"))}function c(){var t=.12*window.innerWidth,i=.12*window.innerHeight,d=r();nwindow.innerHeight-i&&window.scroll(d.x,d.y+(1-(window.innerHeight-n)/i)*(14/e)),owindow.innerWidth-t&&window.scroll(d.x+(1-(window.innerWidth-o)/t)*(14/e),d.y)}function r(){return{x:void 0!==window.scrollX?window.scrollX:window.pageXOffset,y:void 0!==window.scrollY?window.scrollY:window.pageYOffset}}return l&&(document.body.style.transition="transform 0.8s ease"),document.addEventListener("keyup",(function(o){1!==e&&27===o.keyCode&&t.out()})),document.addEventListener("mousemove",(function(t){1!==e&&(o=t.clientX,n=t.clientY)})),{to:function(o){if(1!==e)t.out();else{if(o.x=o.x||0,o.y=o.y||0,o.element){var n=o.element.getBoundingClientRect();o.x=n.left-20,o.y=n.top-20,o.width=n.width+40,o.height=n.height+40}void 0!==o.width&&void 0!==o.height&&(o.scale=Math.max(Math.min(window.innerWidth/o.width,window.innerHeight/o.height),1)),o.scale>1&&(o.x*=o.scale,o.y*=o.scale,s(o,o.scale),!1!==o.pan&&(i=setTimeout((function(){d=setInterval(c,1e3/60)}),800)))}},out:function(){clearTimeout(i),clearInterval(d),s({x:0,y:0},1),e=1},magnify:function(e){this.to(e)},reset:function(){this.out()},zoomLevel:function(){return e}}}();return function(){return e}})); diff --git a/2311/site_libs/rstudio_leaflet-1.3.1/images/1px.png b/2311/site_libs/rstudio_leaflet-1.3.1/images/1px.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/2311/site_libs/rstudio_leaflet-1.3.1/images/1px.png differ diff --git a/2311/site_libs/rstudio_leaflet-1.3.1/rstudio_leaflet.css b/2311/site_libs/rstudio_leaflet-1.3.1/rstudio_leaflet.css new file mode 100644 index 00000000..c10d2f11 --- /dev/null +++ b/2311/site_libs/rstudio_leaflet-1.3.1/rstudio_leaflet.css @@ -0,0 +1,41 @@ +.leaflet-tooltip.leaflet-tooltip-text-only, +.leaflet-tooltip.leaflet-tooltip-text-only:before, +.leaflet-tooltip.leaflet-tooltip-text-only:after { + background: none; + border: none; + box-shadow: none; +} + +.leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-left { + margin-left: 5px; +} + +.leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-right { + margin-left: -5px; +} + +.leaflet-tooltip:after { + border-right: 6px solid transparent; + /* right: -16px; */ +} + +.leaflet-popup-pane .leaflet-popup-tip-container { + /* when the tooltip container is clicked, it is closed */ + pointer-events: all; + /* tooltips should display the "hand" icon, just like .leaflet-interactive*/ + cursor: pointer; +} + +/* have the widget be displayed in the right 'layer' */ +.leaflet-map-pane { + z-index: auto; +} + +/* Add missing rule from leaflet for img. +This complete existing leaflet.css. +Fix for https://github.com/rstudio/rmarkdown/issues/1949 */ +.leaflet-container .leaflet-right-pane img, +.leaflet-container .leaflet-left-pane img { + max-width: none !important; + max-height: none !important; +} diff --git a/2311/topics/linux/assets/bash_cheat_sheet_1.pdf b/2311/topics/linux/assets/bash_cheat_sheet_1.pdf new file mode 100644 index 00000000..5d852303 Binary files /dev/null and b/2311/topics/linux/assets/bash_cheat_sheet_1.pdf differ diff --git a/2311/topics/linux/assets/bash_cheat_sheet_2.pdf b/2311/topics/linux/assets/bash_cheat_sheet_2.pdf new file mode 100644 index 00000000..6c7d2aa3 Binary files /dev/null and b/2311/topics/linux/assets/bash_cheat_sheet_2.pdf differ diff --git a/2311/topics/linux/assets/bash_cheat_sheet_3.pdf b/2311/topics/linux/assets/bash_cheat_sheet_3.pdf new file mode 100644 index 00000000..e188c8d7 Binary files /dev/null and b/2311/topics/linux/assets/bash_cheat_sheet_3.pdf differ diff --git a/2311/topics/linux/assets/files.tar.gz b/2311/topics/linux/assets/files.tar.gz new file mode 100644 index 00000000..f34eb8ff Binary files /dev/null and b/2311/topics/linux/assets/files.tar.gz differ diff --git a/2311/topics/linux/assets/linux_advanced.tar.gz b/2311/topics/linux/assets/linux_advanced.tar.gz new file mode 100644 index 00000000..ae703d32 Binary files /dev/null and b/2311/topics/linux/assets/linux_advanced.tar.gz differ diff --git a/2311/topics/linux/assets/linux_cheat_sheet.pdf b/2311/topics/linux/assets/linux_cheat_sheet.pdf new file mode 100644 index 00000000..7c41ad45 Binary files /dev/null and b/2311/topics/linux/assets/linux_cheat_sheet.pdf differ diff --git a/2311/topics/linux/assets/uppmax_cheat_sheet.png b/2311/topics/linux/assets/uppmax_cheat_sheet.png new file mode 100644 index 00000000..8a843849 Binary files /dev/null and b/2311/topics/linux/assets/uppmax_cheat_sheet.png differ diff --git a/2311/topics/linux/lab_linux_advanced.html b/2311/topics/linux/lab_linux_advanced.html new file mode 100644 index 00000000..82c792f7 --- /dev/null +++ b/2311/topics/linux/lab_linux_advanced.html @@ -0,0 +1,948 @@ + + + + + + + + + + +Advanced Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Advanced Linux

    +

    Variables and Loops

    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Martin Dahlö

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    In code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window.

    +
    +
    +
    +

    1 Connect to UPPMAX

    +

    The first step of this lab is to open a ssh connection to UPPMAX. Please refer to Connecting to UPPMAX for instructions. Once connected to UPPMAX, return here and continue reading the instructions below.

    +
    +
    +

    2 Logon to a node

    +

    Usually you would do most of the work in this lab directly on one of the login nodes at UPPMAX, but we have arranged for you to have one core each for better performance. This was covered briefly in the lecture notes.

    +

    Check which node you got when you booked resources this morning (replace username with your UPPMAX username)

    +
    $ squeue -u username
    +

    should look something like this

    +
    dahlo@rackham2 work $ squeue -u dahlo
    +             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
    +           3132376      core       sh    dahlo  R       0:04      1 r292
    +dahlo@rackham2 work $
    +

    where r292 is the name of the node I got (yours will probably be different). Note the numbers in the Time column. They show for how long the job has been running. When it reaches the time limit you requested (7 hours in this case) the session will shut down, and you will lose all unsaved data. Connect to this node from within UPPMAX.

    +
    $ ssh -Y r292
    +

    If the list is empty you can run the allocation command again and it should be in the list:

    +
    +
    cat(paste0("salloc -A ",upid," -t 03:30:00 -p core -n 1 --no-shell &"))
    +
    +
    salloc -A naiss2023-22-862 -t 03:30:00 -p core -n 1 --no-shell &
    +
    +
    +

    There is a UPPMAX specific tool called jobinfo that supplies the same kind of information as squeue that you can use as well ($ jobinfo -u username).

    +
    +
    +

    3 First things first

    +

    Let’s make sure nano has syntax highlighting enabled. What that will do is to paint the boring code in pretty colors, making it much easier to read it. See the difference for yourself by first looking at this file before you enable it:

    +
    $ nano /sw/uppmax/bin/projplot
    +

    Close down nano when you have seen how boing it looks without colors by pressing ctrl+x. Now, let’s enable syntax highlighting. To do this, we will simply tell nano to include the syntax highlighting instructions from a bunch of files that are already installed at uppmax. Run this command to do just that:

    +
    $ find /usr/share/nano/ -iname "*.nanorc" -exec echo include {} \; >> ~/.nanorc
    +

    This command will put one line per language instructions (~30 of them, located in /usr/share/nano), into the nano autostart file (~/.nanorc) and put the word ‘include’ infront of each file name. That will make nano include the instructions from each of those files whenever it starts. Now have a look at the same file as before and enjoy the colors:

    +
    $ nano /sw/uppmax/bin/projplot
    +

    Then close nano and continue with the lab.

    +
    +
    +

    4 Copy files for lab

    +

    Now, you will need some files. To avoid all the course participants editing the same file all at once, undoing each other’s edits, each participant will get their own copy of the needed files. The files are located in the folder /sw/courses/ngsintro/linux/linux_advanced/.

    +

    If you for some reason have problems copying the files, or if you are not on UPPMAX when running this lab, you can download these files here. You can unpack the file using the command tar -xzvf linux_advanced.tar.gz once you have downloaded it. After unpacking, continue the lab from step 4.

    +

    Next, copy the lab files from this folder. -r means recursively, which means all the files including sub-folders of the source folder. Without it, only files directly in the source folder would be copied, NOT sub-folders and files in sub-folders.

    +

    Remember to use tab-complete to avoid typos and too much writing.

    +
    +
    +
    cp -r <source> <destination>
    +cp -r /sw/courses/ngsintro/linux/linux_advanced /proj/naiss2023-22-862/nobackup/username
    +
    +
    +

    Have a look in /proj/naiss2023-22-862/nobackup/username/linux_advanced.

    +
    +
    +
    cd /proj/naiss2023-22-862/nobackup/username/linux_advanced
    +
    +
    +
    $ ll
    +

    If you see files, the copying was successful.

    +
    +
    +

    5 Using variables

    +

    Variables are like small notes you write stuff on. If you want to save the value of something to be able to use it later, variables is the way to go. Let’s try assigning values to some variables and see how we use them.

    +
    $ a=5
    +

    Now the values 5 is stored in the variable named a. To use the variable we have to put a $ sign in front of it so that bash knows we are referring to the variable a and not just typing the letter a. To see the result of using the variable, we can use the program echo, which prints whatever you give it to the terminal.

    +
    $ echo print this text to the terminal
    +$ echo "you can use quotes if you want to"
    +

    As you see, all the words you give it are printed just the way they are. Try putting the variable somewhere in the text.

    +
    $ echo Most international flights leave from terminal $a at Arlanda airport
    +

    Bash will see that you have a variable there and will replace the variable name with the value the variable have before sending the text to echo. If you change the value of a and run the exact command again you will see that it changes.

    +
    $ a="five"
    +$ echo Most international flights leave from terminal $a at Arlanda airport
    +

    So without changing anything in the echo statement, we can make it output different things, all depending on the value of the variable a. This is one of the main points of using variables, that you don’t have to change the code or script but you can still make it behave differently depending on the values of the variables.

    +

    You can also do mathematics with variables, but we have to tell bash that we want to do calculations first. We do this by wrapping the calculations inside a dollar sign (telling bash it’s a variable) and double parentheses, i.e. $((5+5)).

    +
    $ a=4
    +$ echo $a squared is $(($a*$a))
    +

    Write a echo command that will print out the volume of a rectangular cuboid, with the side lengths specified by variables named x, y, and z. To see that it works correctly, the volume of a rectangular cuboid with sides 5,5,5 is 125, and for 4,5,10 is 200. Give it a couple of tries on your own first. If you get completely stuck you can see a suggested solution below.

    +
    +
    +
    $ x=4
    +$ y=5
    +$ z=10
    +$ echo The volume of the rectangular cuboid with the sides $x,$y,$z is $(($x*$y*$z)).
    +
    +
    +
    +
    +

    6 Exercises

    +

    First off, let’s open another terminal to UPPMAX so that you have 2 of them open. Scripting is a lot easier if you have one terminal on the command line ready to run commands and test things, and another one with a text editor where you write the actual code. That way you will never have to close down the text editor when you want to run the script you are writing on, and then open it up again when you want to continue editing the code.

    +

    So open a new terminal window, connect it to UPPMAX and then connect it to the node you have booked. Make sure both terminals are in the /proj/naiss2023-22-862/nobackup/username/linux_advanced directory, and start editing a new file with gedit or nano where you write your script. Name the file whatever you want, but in the examples I will refer to it as loop_01.sh. Write your loops to this file (or create a new file for each new example) and test run it in the other terminal.

    +

    NOTE: If you get error messages like (gedit:27463): dconf-WARNING **: 10:59:00.575: failed to commit changes to dconf: Failed to execute child process “dbus-launch” (No such file or directory), and if you can’t change any preferences, you can try starting gedit through the graphical menu in ThinLic instead. If you are using the Xfce desktop environment you should have a start-menu-like button at the top-left of the screen named Applications, or if you right-click somewhere on the desktop you should find it in the context menu that pops up. In the Applications menu, look in the category Accessories and you should find a program called Text editor which will start gedit *(hopefully without the errors).

    +

    The most simple loops are the ones that loop over a predefined list. You saw examples of this in the lecture slides, for example:

    +
    for i in "Print these words" one by one;
    +do
    +    echo $i
    +done
    +

    which will print the value of $i in each iteration of the loop. Write this loop in the file you are editing with gedit/nano, save the file, and then run it in the other terminal you have open.

    +
    $ bash loop_01.sh
    +

    As you see, the words inside the quotation marks are treated as a single unit, unlike the words after. You can also iterate over numbers, so erase the previous loop you wrote and try this instead:

    +
    for number in 1 2 3;
    +do
    +    echo $number
    +done
    +

    If everything worked correctly you should have gotten the numbers 1 2 3 printed to the screen. As you might guess, this way of writing the list of numbers to iterate over will not be usable once you have more than 10 or so numbers you want to loop over. Fortunately, the creators of bash (and most other computer languages) saw this problem coming a mile away and did something about it. To quickly create a list of numbers in bash, you can use something called a sequence expression to create the list for you.

    +
    for whatevernameyouwant in {12..72};  
    +do  
    +    echo $whatevernameyouwant  
    +done  
    +
    +

    6.1 Exercise 1

    +

    Let’s say it’s New Year’s Eve and you want to impress your friends with a computerized countdown of the last 10 seconds of the year (don’t we all?).

    +
    +
    +
    + +
    +
    +Tip +
    +
    +
    +

    Start off with getting a loop to count down from 10 to 0 first. Notice how fast the computer counts? That won’t do if it’s seconds we want to be counting down. Try looking the man page for the sleep command (man sleep) and figure out how to use it. The point of using sleep is to tell the computer to wait for 1 second after printing the number, instead of rushing to the next iteration in the loop directly. Try to implement this on your own.

    +
    +
    +
    +
    +
    # declare the values the loop will loop over
    +for secondsToGo in {10..0};
    +do
    +    # print out the current number
    +    echo $secondsToGo
    +
    +    # sleep for 1 second
    +    sleep 1
    +
    +done
    +
    +# Declare the start of a new year in a festive manner
    +echo Happy New Year everyone!!
    +
    +
    +
    +
    +

    6.2 Exercise 2

    +

    Let’s try to do something similar to the example in the lecture slides, to run the same commands on multiple files. In the Introduction to UPPMAX, we learned how to use samtools to convert BAM files to SAM files so that humans can read them. In real life you will never do this, instead you will most likely always do it the other way around. SAM files take up ~4x more space on the hard drive compared to the same file in BAM format, so as soon as you see a SAM file you should convert it to a BAM file instead to conserve hard drive space. If you have many SAM files that needs converting you don’t want to sit there and type all the commands by hand like a pleb.

    +

    Write a script that converts all the SAM files in a specified directory to BAM files. Incidentally, you can find 50 SAM files in need of conversion in the folder called sam in the folder you copied to your folder earlier in this lab (/proj/naiss2023-22-862/nobackup/username/linux_advanced/sam). Bonus points if you make the program take the specified directory as an argument, and another bonus point if you get the program to name the resulting BAM file to the same name as the SAM file but with a .bam ending instead.

    +
    +
    +
    + +
    +
    +Tip +
    +
    +
    +

    Remember that you have to load the samtools module to be able to run it. The way you get samtools to convert a SAM file to a BAM file is by typing the following command:

    +
    samtools view -bS sample_1.sam > sample_1.bam
    +

    The -b option tells samtools to output BAM format, and the -S option tells samtools that the input is in SAM format.

    +

    Remember, Google is a good place to get help. If you get stuck, google “bash remove file ending” or “bash argument to script” and look for hits from StackOverflow/StackExchange or similar pages. There are always many different way to solve a problem. Try finding one you understand what they do and test if you can get them to work the way you want. If not, look for another solution and try that one instead.

    +
    +
    +

    Basic, without bonus points:

    +
    +
    +
    # load the modules needed for samtools
    +module load bioinfo-tools samtools/1.3
    +
    +# move to the SAM files directory to start with
    +cd sam
    +
    +# use ls to get the list to iterate over
    +for file in *.sam;
    +do
    +    # do the actual converting, just slapping on .bam at the end of the name
    +    samtools view -bS $file > $file.bam
    +done
    +
    +
    +

    Advanced, with bonus points:

    +
    +
    +
    # load the modules needed for samtools
    +module load bioinfo-tools samtools/1.3
    +
    +# move to the SAM files directory to start with.
    +# $1 contains the first argument given to the program
    +cd $1
    +
    +# use ls to get the list to iterate over.
    +for file in *.sam;
    +do
    +
    +    # print a message to the screen so that the user knows what is happening.
    +    # $(basename $file .sam) means that it will take the file name and remove .sam
    +    # at the end of the name.
    +    echo "Converting $file to $(basename $file .sam).bam"
    +
    +    # do the actual converting
    +    samtools view -bS $file > $(basename $file .sam).bam
    +done
    +
    +
    +
    +
    +

    6.3 Exercise 3

    +

    Let’s add a small thing to the exercise we just did. If there already exists a BAM file with the same name as the SAM file it’s not necessary to convert it again. Let’s use an if statement to check if the file already exists before we do the conversion.

    +

    The following if statement will check if a given filename exists, and prints a message depending on if it exists or not.

    +
    FILE=$1
    +
    +if [ -f $FILE ];
    +then
    +   echo "File $FILE exists."
    +else
    +   echo "File $FILE does not exist."
    +fi
    +

    What we want to do is to check if the file doesn’t exists. The way to do that is to invert the answer of the check if the file does exist. To do that in bash, and many other languages, is to use the exclamation mark, !, which in these kinds of logical situations means NOT or the opposite of.

    +
    FILE=$1
    +
    +if [ ! -f $FILE ];
    +then
    +    echo "File $FILE does not exist."
    +fi
    +

    Now, modify the previous exercise to only do the conversion if a file with the intended name of the BAM file doesn’t already exists. i.e; if you have a.sam and want to create a BAM file named a.bam, first check if a.bam already exists and only do the conversion if it does not exist.

    +

    Basic:

    +
    +
    +
    # load the modules needed for samtools
    +module load bioinfo-tools samtools/1.3
    +
    +# move to the SAM files directory to start with.
    +cd sam
    +
    +# use ls to get the list to iterate over.
    +for file in *.sam;
    +do
    +    # check if the intended output file does not already exists
    +    if [ ! -f $file.bam ];
    +    then
    +        # do the actual converting, just slapping on .bam at the end of the name
    +        samtools view -bS $file > $file.bam
    +    fi
    +done
    +
    +
    +

    Advanced:

    +
    +
    +
    # load the modules needed for samtools
    +module load bioinfo-tools samtools/1.3
    +
    +cd $1
    +
    +# use ls to get the list to iterate over.
    +# $1 contains the first argument given to the program
    +for file in *.sam;
    +do
    +
    +    # basename will remove the path information to the file, and will also remove the .sam ending
    +    filename_bam=$(basename $file .sam)
    +
    +    # add the .bam file ending to the filename
    +    filename_bam=$filename_bam.bam
    +
    +    # check if the intended output file does not already exists.
    +    if [ ! -f $filename_bam ];
    +    then
    +
    +        # print a message to the screen so that the user knows what is happening.
    +        echo "Converting $file to $filename_bam"
    +
    +        # do the actual converting
    +        samtools view -bS $file > $filename_bam
    +
    +    else
    +        # inform the user that the conversion is skipped
    +        echo "Skipping conversion of $file as $filename_bam already exist"
    +    fi
    +done
    +
    +
    +
    +
    +

    6.4 Bonus exercise 1

    +

    Maths and programming are usually a very good combination, so many of the examples of programming you’ll see involve some kind of maths. Now we will write a loop that will calculate the factorial of a number. As wikipedia will tell you, “the factorial of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n”, i.e. multiply all the integers, starting from 1, leading up to and including a number with each other.

    +

    The factorial of 5, written 5!, would be 1*2*3*4*5=120. Doing this by hand would start taking its time even after a couple of steps, but since we know how to loop that should not be a problem anymore.

    +

    Write a loop that will calculate the factorial of a given number stored in the variable $n.

    +
    +
    +
    + +
    +
    +Tip +
    +
    +
    +

    A problem that you will encounter is that the sequence expression, {1..10}, from the previous exercise doesn’t handle variables. This is because of the way bash is built. The sequence expressions are handled before handling the variables so when bash tries to generate the sequence, the variable names have not yet been replaced with the values they contain. This leads to bash trying to create a sequence from 1 to $n, which of course doesn’t mean anything.

    +

    To get around this we can use a different way of generating sequences (there are always alternatives). There is a program called seq that does pretty much the same thing as the sequence expression, and since it is a program it will be executed after the variables have been handled. It’s as easy to use as the sequence expressions; instead of writing {1..10} just write $( seq 1 10 ).

    +

    The $() tells bash to run something in a subshell, which pretty much means it will run the command within the paratheses and then take whatever that command printed to the screen and replace the parantheses e xpression:

    +
    echo $(seq 1 5)
    +

    becomes

    +
    echo 1 2 3 4 5
    +
    +
    +
    +
    +
    # set the number you want to calculate the factorial of
    +n=10
    +
    +# you have to initialize a variable before you can start using it.
    +# Leaving this empty would lead to the first iteration of the loop trying
    +# to use a variable that has no value, which would cause it to crash
    +factorial=1
    +
    +# declare the values the loop will loop over (1 to whatever $n is)
    +for i in $( seq 1 $n );
    +do
    +
    +    # set factorial to whatever factorial is at the moment, multiplied with the variable $i
    +    factorial=$(( $factorial * $i ))
    +
    +    # an alternative solution which gives exactly the same result, but makes it a bit more readable maybe
    +    # temporary_sum=$(( $factorial * $i ))
    +    # factorial=$temporary_sum
    +
    +done
    +
    +# print the result
    +echo The factorial of $n is $factorial
    +
    +
    +
    +
    +

    6.5 Bonus exercise 2

    +

    Now, let’s combine everything you’ve learned so far in this course.

    +

    Write a script that runs the pipeline from the Bioinformatics filetypes lab for each fastq file in a specified directory, using the same reference genome as in the file type exercise. Navigate to the Linux 2: File types in Bioinformatics lab on the Contents page.

    +

    If that sounds too easy, make the script submit a slurm job for each sample that will run the pipeline for that sample on a calculation node (1 core, 5 minutes each). And if that is too easy, add that the pipeline will use the local hard drive on the calculation node for all files used in the analysis.

    +

    When the analysis is done, only fastq files and sorted and indexed BAM files should be in your folder.

    +

    Read more about the $SNIC_TMP variable in the disk storage guide on the UPPMAX homepage.

    +

    There is a bunch of fastq files in the directory /proj/naiss2023-22-862/nobackup/username/linux_advanced/fastq/ that is to be used for this exercise.

    +

    Basic solution:

    +
    +
    +
    # make the dummy pipeline available
    +export PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts
    +
    +# index the reference genome
    +reference_indexer -r /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa
    +
    +# go to the input files
    +cd $1
    +
    +# loop over all the fastq files
    +for file in *.fastq;
    +do
    +
    +    # align the reads
    +    align_reads -r /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa -i $file -o $file.sam
    +
    +    # convert the sam file to a bam file
    +    sambam_tool -f bam -i $file.sam -o $file.bam
    +
    +    # sort the bam file
    +    sambam_tool -f sort -i $file.bam -o $file.sorted.bam
    +
    +    # index the bam file
    +    sambam_tool -f index -i $file.sorted.bam
    +
    +done
    +
    +
    +

    Advanced solution:

    +
    +
    +
    # make the dummy pipeline available in this script
    +export PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts
    +
    +# index the reference genome once, only if needed
    +if [ ! -f /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa.idx ];
    +then
    +    reference_indexer -r /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa
    +fi
    +
    +
    +# find out the absolute path to the input files
    +cd $1
    +input_absolute_path=$(pwd)
    +
    +# go back to the previous directory now that the absolute path has been saved
    +cd -
    +
    +
    +
    +# loop over all the fastq files
    +for file in $input_absolute_path/*.fastq;
    +do
    +
    +    # print status report
    +    echo Processing $file
    +
    +    # save the file name without the path information for convenience
    +    file_basename=$(basename $file)
    +
    +    # save the file name without the file ending for convenience
    +    file_prefix=$(basename $file .fastq)
    +
    +    # print a temporary script file that will be submitted to slurm
    +    echo "#!/bin/bash -l
    +
    +    #SBATCH -A naiss2023-22-862
    +    #SBATCH -p core
    +    #SBATCH -n 1
    +    #SBATCH -t 00:05:00
    +    #SBATCH -J $file_basename
    +
    +    # make the dummy pipeline available on the calculation node
    +    echo "Loading modules"
    +    export PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts
    +
    +    # copy the reference genome, index and sample file to the nodes local hard drive.
    +    # You have to escape the dollar sign in SNIC_TMP to keep bash from resolving
    +    # it to its value in the submitter script already.
    +    echo "Copying data to node local hard drive"
    +    cp /proj/naiss2023-22-862/nobackup/username/filetypes/0_ref/ad2.fa* $file $SNIC_TMP/
    +
    +    # go the the nodes local hard drive
    +    echo "Changing directory to node local hard drive"
    +    cd $SNIC_TMP
    +
    +    # align the reads
    +    echo "Aligning the reads"
    +    align_reads -r ad2.fa -i $file_basename -o $file_prefix.sam
    +
    +    # convert the SAM file to a BAM file
    +    echo "Converting sam to bam"
    +    sambam_tool -f bam -i $file_prefix.sam -o $file_prefix.bam
    +
    +    # sort the BAM file
    +    echo "Sorting the bam file"
    +    sambam_tool -f sort -i $file_prefix.bam -o $file_prefix.sorted.bam
    +
    +    # index the BAM file
    +    echo "Indexing the sorted bam file"
    +    sambam_tool -f index -i $file_prefix.sorted.bam
    +
    +    # copy back the files you want to keep
    +    echo "Copying results back to network storage"
    +    cp $file_prefix.sorted.bam $input_absolute_path/
    +    cp $file_prefix.sorted.bam.bai $input_absolute_path/$file_prefix.sorted.bai
    +
    +    echo "Finished"
    +    " > tmp.sbatch
    +
    +    # submit the temporary script file
    +    sbatch tmp.sbatch
    +
    +done
    +
    +# remove the temporary file now that everything has been submitted
    +rm tmp.sbatch
    +
    +
    + + +
    +
    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/linux/lab_linux_filetypes.html b/2311/topics/linux/lab_linux_filetypes.html new file mode 100644 index 00000000..83861e40 --- /dev/null +++ b/2311/topics/linux/lab_linux_filetypes.html @@ -0,0 +1,733 @@ + + + + + + + + + + +Filetypes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Filetypes

    +

    Common filetypes In bioinformatics

    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Martin Dahlö

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    In code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window.

    +
    +
    +
    +

    1 Connect to UPPMAX

    +

    The first step of this lab is to open a ssh connection to UPPMAX. Please refer to Connecting to UPPMAX for instructions. Once connected to UPPMAX, return here and continue reading the instructions below.

    +
    +
    +

    2 Logon to a node

    +

    Usually you would do most of the work in this lab directly on one of the login nodes at UPPMAX, but we have arranged for you to have one core each for better performance. This was covered briefly in the lecture notes.

    +
    +
    +
    salloc -A naiss2023-22-862 -t 07:00:00 -p core -n 1 --no-shell &
    +
    +
    +

    check which node you got (replace username with your UPPMAX username)

    +
    $ squeue -u username
    +

    should look something like this

    +
    dahlo@rackham2 work $ squeue -u dahlo
    +             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
    +           3132376      core       sh    dahlo  R       0:04      1 r292
    +dahlo@rackham2 work $
    +

    where r292 is the name of the node I got (yours will probably be different). Note the numbers in the Time column. They show for how long the job has been running. When it reaches the time limit you requested (7 hours in this case) the session will shut down, and you will lose all unsaved data. Connect to this node from within UPPMAX.

    +
    $ ssh -Y r292
    +

    There is a UPPMAX specific tool called jobinfo that supplies the same kind of information as squeue that you can use as well ($ jobinfo -u username).

    +
    +
    +

    3 Copy lab files

    +

    Now you will need some files. To avoid all the course participants editing the same file all at once, undoing each other’s edits, each participant will get their own copy of the needed files. The files are located in the folder /sw/courses/ngsintro/linux/filetypes

    +

    Next, copy the lab files from this folder. -r means recursively, which means all the files including sub-folders of the source folder. Without it, only files directly in the source folder would be copied, NOT sub-folders and files in sub-folders.

    +

    Remember to use tab-complete to avoid typos and too much writing.

    +
    +
    +
    cp -r <source> <destination>
    +cp -r /sw/courses/ngsintro/linux/filetypes /proj/naiss2023-22-862/nobackup/username/
    +
    +
    +

    Have a look in /proj/naiss2023-22-862/nobackup/username/.

    +
    +
    +
    cd /proj/naiss2023-22-862/nobackup/username/filetypes
    +tree
    +
    +
    +

    This will print a file tree, which gives you a nice overview of the folders where you are standing in. As you can see, you have a couple of files and a couple of empty folders. In the 0_ref folder you have a reference genome in fasta format and annotations for the genome in GTF format. In 0_seq you have a fastq file containing the reads we will align.

    +
    +
    +

    4 Run pipeline

    +

    The best way to see all the different file formats is to run a small pipeline and see which files we encounter along the way. The pipeline is roughly the same steps you’ll do in the variant-calling part of the course, so for now we’ll stick with the dummy pipeline which some of you might have encoutered in the extra material for the UPPMAX exercise.

    +

    The programs in the dummy pipeline does not actually do any analysis but they work the same way as the real deal, although slightly simplified, to get you familiar with how to work with analysis programs. The data is from a sequencing of the adenovirus genome, which is tiny compared to the human genome (36kb vs 3gb).

    +

    The starting point of the pipeline are fresh reads from the sequencing machine in fastq format, and a reference genome in fasta format. The goal of the exercise is to look at our aligned reads in a genome viewer together with the annotations of the adenovirus genome.

    +

    First, let’s go through the steps of the pipeline:

    +
      +
    • Build an index for the reference genome. This will speed up the alignment process. Not possible to do the analysis without it.
    • +
    • Align the reads.
    • +
    • Convert the SAM file to a BAM file. We want to use the space efficiently.
    • +
    • Sort the BAM file. We have to sort it to be able to index it.
    • +
    • Index the BAM file. We have to index it to make it fast to access the data in the file.
    • +
    • View the aligned data together with the annotations.
    • +
    +

    The first thing you usually do is to load the modules for the programs you want to run. During this exercise we’ll only run my dummy scripts that don’t actually do any analysis, so they don’t have a module of their own. What we can do instead is to manually do what module loading usually does: to modify the $PATH variable.

    +

    The $PATH variable specifies directories where the computer should look for programs. For instance, when you type nano, how does the computer know which program to start? You gave it the name nano, but that could refer to any file named nano in the computer, yet it starts the correct one every time. The answer is that it looks in the directories stored in the $PATH variable.

    +

    To see which directories that are available by default, type

    +
    $ echo $PATH
    +

    It should give you something like this, a list of directories, separated by colon signs:

    +
    dahlo@rackham2 work $ echo $PATH
    +/home/dahlo/perl//bin/:/home/dahlo/.pyenv/shims:/home/dahlo/.pyenv/bin:
    +/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:
    +/sbin:/opt/thinlinc/bin:/sw/uppmax/bin:/home/dahlo/usr/bin
    +

    Try loading a module, and then look at the $PATH variable again. You’ll see that there are a few extra directories there now, after the module has been loaded.

    +
    dahlo@rackham2 work $ module load bioinfo-tools samtools/1.10
    +dahlo@rackham2 work $ echo $PATH
    +/sw/apps/bioinfo/samtools/1.10/rackham/bin:/home/dahlo/perl/bin:/home/dahlo/.pyenv/shims:
    +/home/dahlo/.pyenv/bin:/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:
    +/usr/sbin:/sbin:/opt/thinlinc/bin:/sw/uppmax/bin:/home/dahlo/usr/bin
    +

    To pretend that we are loading a module, we will just add a the directory containing my dummy scripts to the $PATH variable, and it will be like we loaded the module for them.

    +
    $ export PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts
    +

    This will set the $PATH variable to whatever it is at the moment, and add a directory at the end of it. Note the lack of a dollar sign in front of the variable name directly after export. You don’t use dollar sign when assigning values to variables, and you always use dollar signs when getting values from variables.

    +
    +

    Important

    +

    The export command affects only the terminal you type it in. If you have 2 terminals open, only the terminal you typed it in will have a modified path. If you close that terminal and open a new one, it will not have the modified path.

    +
    +
    +

    4.1 Build index

    +
      +
    1. Build an index for the reference genome.
    2. +
    3. Align the reads.
    4. +
    5. Convert the SAM file to a BAM file.
    6. +
    7. Sort the BAM file.
    8. +
    9. Index the BAM file.
    10. +
    11. View the aligned data together with the annotations.
    12. +
    +

    All aligners will have to index the reference genome you are aligning your data against. This is only done once per reference genome, and then you reuse that index whenever you need it. All aligners have their own kind of index unfortunately, so you will have to build one index for each aligner you want to use. In this lab, we will use the dummy aligher called align_reads, and we will build a index using it’s indexing progam, called reference_indexer.

    +

    First, have a look in the 0_ref folder

    +
    $ ll 0_ref
    +

    You should see 2 files: the fasta file, the gtf file. Have a look at each of them with less, just to see how they look inside. To do the actual indexing of the genome:

    +

    Run reference_indexer.

    +
    Syntax: reference_indexer -r <name of the fasta file you want to index>
    +
    +
    +
    $ reference_indexer -r 0_ref/ad2.fa
    +
    +
    +

    Since the genome is so small this should only take a second or so. The human genome will probably take a couple of hours. Look in the 0_ref folder again and see if anything has changed.

    +
    $ ll 0_ref
    +

    The new file you see is the index file created by reference_indexer. This index is in the same format as you would get from the real program samtools. Try viewing the index file with less and see how it looks. The samtools type of index contains one row per fasta record in the reference file. In this case, there is only one record for the adenovirus genome, and it’s called ad2 in the fasta file. The human reference genome typically have one record per chromosome, so a index of the human genome would then have 24 rows.

    +

    The numbers after the record name specifies how many bases the record has, how far into the file (in bytes) the record starts, the number of bases on each line in the record, and how many bytes each line takes up in the file. Using this information the program can quickly jump to the start location of each record, without having to read the file from the first row every time.

    +

    Other aligners might use more complex indexing of the file to speed up the alignment process even further, e.g. creating an index over where it can find all possible “words” that you can form with 5 or so bases, making it easier to find possible matching sites for reads. If the read starts with ATGTT you can quickly look in the index and see all places in the geonome that contains this word and start looking if the rest of the read matches the area around the word.

    +

    This greatly decreases the number of places you have to look when looking for a match. These types of indexes usually take a long time to create (5+ hours maybe), but since you only have to do it once per reference genome it’s easily worth it, seeing how the alignment process probably would take 100s of hours without the index, instead of 6-12 hours.

    +

    We are now ready to align our reads.

    +
    +
    +

    4.2 Align reads

    +
      +
    1. Build an index for the reference genome.
    2. +
    3. Align the reads.
    4. +
    5. Convert the SAM file to a BAM file.
    6. +
    7. Sort the BAM file.
    8. +
    9. Index the BAM file.
    10. +
    11. View the aligned data together with the annotations.
    12. +
    +

    Align reads using align_reads, naming the output file ad2.sam, placed in the 1_alignment folder.

    +
    Syntax: align_reads -r <reference genome> -i <fastq file with reads> -o <name of the output file>
    +
    +
    +
    $ align_reads -r 0_ref/ad2.fa -i 0_seq/ad2.fq -o 1_alignment/ad2.sam
    +
    +
    +

    This will create a SAM file in 1_alignment called ad2.sam. Have a look at it with less. If you think the file looks messy, add a -S after less to make it stop wrapping long lines, less -S 1_alignment/ad2.sam and scroll sideways using the arrow keys. As you can see there is one row per aligned read in this file. Each row contains information about the read, like the name of the read, where in the reference genome it aligned, and also a copy of the reads sequence and quality score, among other things.

    +
    +
    +

    4.3 SAM to BAM

    +
      +
    1. Build an index for the reference genome.
    2. +
    3. Align the reads.
    4. +
    5. Convert the SAM file to a BAM file.
    6. +
    7. Sort the BAM file.
    8. +
    9. Index the BAM file.
    10. +
    11. View the aligned data together with the annotations.
    12. +
    +

    The next step is to convert the SAM file to a BAM file. This is more or less just compressing the file, like creating a zip file. To do that we will use the dummy program sambam_tools, telling it we want to convert a file to BAM (-f bam), which file we want to convert (-i), where it should save the resulting BAM file (-o). Save the BAM file in the 2_bam folder and name it ad2.bam.

    +
    Syntax: sambam_tool -f bam -i <sam file> -o <bam>
    +
    +
    +
    $ sambam_tool -f bam -i 1_alignment/ad2.sam -o 2_bam/ad2.bam
    +
    +
    +

    Have a look in the 2_bam folder.

    +
    $ ll 2_bam
    +

    The created BAM file is an exact copy of the SAM file, but stored in a much more efficient format. Aligners usually have an option to output BAM format directly, saving you the trouble to convert it yourself, but not all tools can do this (they really should though). Have a look at the difference in file size, though in this example it’s quite an extreme difference (2.9 MB vs 0.3 MB). The quality score of all reads is the same (BBBBBBBBB..), and files with less differences are easier to compress. Usually the BAM file is about 25% of the size of the SAM file.

    +

    Since the BAM format is a binary format we can’t look at it with less. We would have to use a tool, like samtools which you will probably see later in the week, to first convert the file back to a SAM file before we can read it. In that case we can just look at the SAM file before converting it since they will be the same.

    +
    +
    +

    4.4 Sort & index BAM

    +
      +
    1. Build an index for the reference genome.
    2. +
    3. Align the reads.
    4. +
    5. Convert the SAM file to a BAM file.
    6. +
    7. Sort the BAM file.
    8. +
    9. Index the BAM file.
    10. +
    11. View the aligned data together with the annotations.
    12. +
    +

    A BAM file is taking up much less space than the SAM file, but we can still improve performance. An indexed BAM file is infinitely faster for programs to work with, but before we can index it, we have to sort it since it’s not possible to index an unsorted file in any meaningful way.

    +

    To sort the BAM file we’ll use the sambam_tool again, but specifying a different function, -f sort instead. Tell it to store the sorted BAM file in the 3_sorted folder and name the file ad2.sorted.bam

    +
    Syntax: sambam_tool -f sort -i <unsorted bam file> -o <sorted bam file>
    +
    +
    +
    $ sambam_tool -f sort -i 2_bam/ad2.bam -o 3_sorted/ad2.sorted.bam
    +
    +
    +

    This will sort the ad2.bam file and create a new BAM file which is sorted, called ad2.sorted.bam.

    +

    Now when we have a sorted BAM file, we can index it. Use the command

    +
    Syntax: sambam_tool -f index -i <sorted bam file>
    +
    +
    +
    $ sambam_tool -f index -i 3_sorted/ad2.sorted.bam
    +
    +
    +

    This will create an index named ad2.sorted.bam.bai in the same folder as the ad2.sorted.bam file is located. It’s nicer to have the .bam and .bai named to the same “prefix”, so rename the .bai file to not have the .bam in its name.

    +
    $ mv 3_sorted/ad2.sorted.bam.bai 3_sorted/ad2.sorted.bai
    +
    +
    +

    4.5 View in a genome viewer

    +
      +
    1. Build an index for the reference genome.
    2. +
    3. Align the reads.
    4. +
    5. Convert the SAM file to a BAM file.
    6. +
    7. Sort the BAM file.
    8. +
    9. Index the BAM file.
    10. +
    11. View the aligned data together with the annotations.
    12. +
    +

    Now that we have to data aligned and prepared for easy access, we will view it in a genome viewer together with the annotations for the genome. Have a look at the annotations file with less.

    +
    $ less -S 0_ref/ad2.gtf
    +

    The -S will tell less to not wrap the lines, and instead show one line per line. If the line is longer than the window, you can user the left and right arrow to scroll to the left and right. Many tabular files are much more readable when using the -S option. Try viewing the file without it and see the difference.

    +

    To view the file, we will use the program IGV (Integrated Genome Viewer). Before we can do this, we have to load the module for IGV.

    +

    If you are using a Mac you might have to install the program XQuartz, if you have not already installed that program. By using -Y in your ssh command you enable graphical transfer over ssh, but you will also have to have a program able to receive the graphics in order to display it.

    +
    $ module load bioinfo-tools IGV/2.4.2
    +

    Start it by typing the following command (now we’ll find out if you used -Y in all your ssh connections!):

    +
    $ igv.sh
    +
    +
    +
    + +
    +
    +Tip +
    +
    +
    +

    If you notice that IGV over Xforwarding is excruciatingly slow, you can try to use the web based ThinLinc client instead. Unfortunately this requires you to have set up a two factor authentification (2FA) with UPPMAX, so it’s something you can try on your own. Instructions for setting up the 2FA at UPPMAX. When you are all set up, go to the address https://rackham-gui.uppmax.uu.se and login with your normal UPPMAX username and password together with your 2FA (described at the login screen). This will get you a remote desktop on one of the login nodes, and you can open a terminal and run IGV there instead. Once IGV is started, either using Xforwarding or the remote desktop in your web browser, we are ready to go.

    +
    +
    +

    There are 3 files we have to load in IGV.

    +

    The first is the reference genome. Press the menu button located at “Genomes - Load Genome from File…” and find your reference genome in 0_ref/ad2.fa. If you are having trouble finding your files, note that IGV always starts in your home directory. Use the dropdown menu at the top to navigate to /proj/naiss2023-22-862/nobackup/….

    +

    The second file you have to load is the reads. Press the menu button “File - Load from File…” and select your 3_sorted/ad2.sorted.bam.

    +

    The last file you have to load is the annotation data. Press “File - Load from File…” again and select you annotation file in 0_ref/ad2.gtf.

    +

    This will show you the reference genome, how all the reads are aligned to it, and all the annotation data. Try zooming in on an area and have a look at the reads and annotations. The figures you see in the picture are all derived from the data in the files you have given it.

    +

    At the top of the window you have the overview of the current chromosome you are looking at, which tells you the scale you are zoomed at for the moment. When you zoom in you will see a red rectangle apper which shows you which portion of the chromosome you are looking at. Just below the scale you’ll see the coverage graph, which tells you how many reads cover each position along the reference genome. The colored bands you see here and there are SNPs, i.e. positions where the reads of your sample does not match the reference genome.

    +

    All the reads, the larger area in the middle of the window, are drawn from the data in the BAM file using the chromosome name, the starting position and the ending position of each read. When you zoom in more you will be able to see individual reads and how they are aligned. The annotation in GTF format are all plotted using the data in the GTF file, visible just under all the reads, are shown as blue rectangles.

    +

    The reference genome, a fasta file containing the DNA sequence of the reference genome, is visible at the bottom of the window if you zoom to the smallest level so you can see the bases of the genome.

    +
    +
    +
    +

    5 Create a CRAM file

    +

    The CRAM format is even more efficient than the BAM format. To create a CRAM file we’ll have to use samtools, so we will load the module for it.

    +
    $ module load bioinfo-tools samtools/1.10
    +

    Tell samtools that you want CRAM output (-C) and specify which reference genome it should use to do the CRAM conversion (-T)

    +
    Syntax: samtools view -C -T <reference genome> -o <name of cram file> <bam file to convert>
    +
    +
    +
    $ samtools view -C -T 0_ref/ad2.fa -o 4_cram/ad2.cram 3_sorted/ad2.sorted.bam
    +
    +
    +

    Compare the sizes of the convered BAM file and the newly created CRAM file:

    +
    $ ll -h 3_sorted/ad2.sorted.bam 4_cram/ad2.cram
    +

    This will list both the files, and print the file size in a human readable format (-h). The CRAM file is roughly 1/3 of the size of the BAM file. This is probably because all the reads in the simulated data has the same quality value (BBBBBBBBBB). Fewer types of quality values are easier to compress, hence this amazing compression ratio. Real data will have much more diverse quality scores, and the CRAM file would be pethaps 70-80% of the original BAM file.

    +
    +
    +
    + +
    +
    +Optional +
    +
    +
    +

    If you have been fast to finish this lab and you still have time left (or just can’t get enough of linux stuff), please have a look at the advanced linux tutorial where you can learn the basics in bash programming using variables, loops and control statements.

    +
    +
    + + +
    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/linux/lab_linux_intro.html b/2311/topics/linux/lab_linux_intro.html new file mode 100644 index 00000000..d5cb4842 --- /dev/null +++ b/2311/topics/linux/lab_linux_intro.html @@ -0,0 +1,857 @@ + + + + + + + + + + +Introduction To Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Introduction To Linux

    +

    Command-line interface to the unix file system

    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Martin Dahlö

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    In code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window.

    +
    +
    +
    +

    1 Connect to UPPMAX

    +

    The first step of this lab is to open a ssh connection to UPPMAX. Please refer to Connecting to UPPMAX for instructions. Once connected to UPPMAX, return here and continue reading the instructions below.

    +
    +
    +

    2 Logon to a node

    +

    Usually you would do most of the work in this lab directly on one of the login nodes at UPPMAX, but we have arranged for you to have one core each for better performance. This was covered briefly in the lecture notes.

    +
    +
    +
    salloc -A naiss2023-22-862 -t 07:00:00 -p core -n 1 --no-shell &
    +
    +
    +

    check which node you got (replace username with your UPPMAX username)

    +
    squeue -u username
    +

    should look something like this

    +
    dahlo@rackham2 work $ squeue -u dahlo
    +             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
    +           3132376      core       sh    dahlo  R       0:04      1 r292
    +dahlo@rackham2 work $
    +

    where r292 is the name of the node I got (yours will probably be different). Note the numbers in the Time column. They show for how long the job has been running. When it reaches the time limit you requested (7 hours in this case) the session will shut down, and you will lose all unsaved data. Connect to this node from within UPPMAX.

    +
    $ ssh -Y r292
    +

    There is a UPPMAX specific tool called jobinfo that supplies the same kind of information as squeue that you can use as well ($ jobinfo -u username).

    +
    + +
    +

    4 Copy lab files

    +

    Now you will need some files. To avoid all the course participants editing the same file all at once, undoing each other’s edits, each participant will get their own copy of the needed files.

    +

    The files are located in the folder /sw/courses/ngsintro/linux/linux_tutorial

    +

    or they can be downloaded if you are not on UPPMAX at the moment, files.tar.gz (instruction on how to download further down)

    +

    For structures sake, first create a folder with your username in the nobackup folder, and a folder called linux_tutorial inside that folder, where you can put all your lab files.

    +

    This can be done in 2 ways:

    +
    +
    +
    mkdir /proj/naiss2023-22-862/nobackup/username
    +mkdir /proj/naiss2023-22-862/nobackup/username/linux_tutorial
    +
    +
    +

    or

    +
    +
    +
    mkdir -p /proj/naiss2023-22-862/nobackup/username/linux_tutorial
    +
    +
    +

    The reason for this is that Linux will not like it if you try to create the folder linux_tutorial inside a folder (the one named like your username) that does not exist yet. Then, you have the choice to either first create the one named like your username (the first way), or to tell Linux to create it for you by giving it the -p option (the second way).

    +

    Next, copy the lab files to this folder.

    +
    cp -r <source-folder> <destination-folder>
    +
    +
    +
    cp -r /sw/courses/ngsintro/linux/linux_tutorial/* /proj/naiss2023-22-862/nobackup/username/linux_tutorial
    +
    +
    +

    -r denotes recursively, which means all the files including sub-folders of the source folder. Without it, only files directly in the source folder would be copied, NOT sub-folders and files in sub-folders.

    +

    Remember to tab-complete to avoid typos and too much writing.

    +

    If you are unable to copy the files on UPPMAX, you can download the files from this link instead of copying them. This is done with the command wget (web get). It works kind of the same way as the cp command, but you give it a source URL instead of a source file, and you specify the destination by giving it a prefix, a path that will be appended in front on the file name when it’s downloaded.

    +

    i.e; if you want to download the file http://somewhere.com/my.file and you give it the prefix ~/analysis/, the downloaded file will be saved as ~/analysis/my.file.

    +
    Ex: wget -P <destination prefix> <source URL>
    +
    +
    +

    5 Unpack files

    +

    Go to the folder you just copied and see what is in it.

    +

    Remember to tab-complete to avoid typos and too much writing.

    +
    +
    +
    cd /proj/naiss2023-22-862/nobackup/username/linux_tutorial
    +ll
    +
    +
    +

    tar.gz is a file ending given to compressed files, something you will encounter quite often. Compression decreases the size of the files which is good when downloading, and it can take thousands of files and compress them all into a single compressed file. This is both convenient for the person downloading and speeds up the transfer more than you would think.

    +

    To unpack the files.tar.gz file use the following line while standing in the newly copied linux_tutorial folder.

    +
    $ tar -xzvf files.tar.gz
    +

    The command will always be the same for all tar.gz files you want to unpack. -xzvf means eXtract from a Zipped file, Verbose (prints the name of the file being unpacked), from the specified File (f must always be the last of the letters).

    +

    Look in the folder again and see what we just unpacked:

    +
    [user@milou2 linux_tutorial]$ ls -la
    +total 512
    +drwxrwsr-x 12 user g20XXXXX   2048 Sep 24 13:19 .
    +drwxrwsr-x  6 user g20XXXXX   2048 Sep 24 13:19 ..
    +drwxrwsr-x  2 user g20XXXXX   2048 Sep 19  2012 a_strange_name
    +drwxrwsr-x  2 user g20XXXXX   2048 Sep 19  2012 backed_up_proj_folder
    +drwxrwsr-x  2 user g20XXXXX   2048 Sep 19  2012 external_hdd
    +-rwxrwxr-x  1 user g20XXXXX  17198 Sep 24 13:19 files.tar.gz
    +drwxrwsr-x  2 user g20XXXXX   2048 Sep 19  2012 important_results
    +drwxrwsr-x  2 user g20XXXXX 129024 Sep 19  2012 many_files
    +drwxrwsr-x  2 user g20XXXXX   2048 Sep 19  2012 old_project
    +-rwxrwxr-x  1 user g20XXXXX      0 Sep 24 13:19 other_file.old
    +drwxrwsr-x  2 user g20XXXXX   2048 Sep 19  2012 part_1
    +drwxrwsr-x  2 user g20XXXXX   2048 Sep 19  2012 part_2
    +drwxrwsr-x  2 user g20XXXXX   2048 Jan 28  2012 this_has_a_file
    +drwxrwsr-x  2 user g20XXXXX   2048 Jan 28  2012 this_is_empty
    +-rwxrwxr-x  1 user g20XXXXX      0 Sep 19  2012 useless_file
    +
    +
    +

    6 Copying and moving files

    +

    Let’s move some files. Moving files might be one of the more common things you do, after cd and ls. You might want to organize your files in a better way, or move important result files to the project folder, who knows?

    +

    We will start with moving our important result to a backed-up folder. When months of analysis is done, the last thing you want is to lose your files. Typically this would mean that you move the final results to your project folder.

    +

    In this example, we want to move the result files only, located in the folder important_results, to our fake project folder, called backed_up_proj_folder.

    +

    The syntax for the move command is:

    +
    $ mv <source> <destination>
    +

    First, take a look inside the important_results folder:

    +
    [user@milou2 linux_tutorial]$ ll important_results/
    +total 0
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 dna_data_analysis_result_file_that_is_important-you_should_really_use_tab_completion_for_file_names.bam
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 temp_file-1
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 temp_file-2
    +

    You see that there are some unimportant temporary files that you have no interest in. Just to demonstrate the move command, I will show you how to move one of these temporary files to your backed-up project folder:

    +
    $ mv important_results/temp_file-1 backed_up_proj_folder/
    +

    Now do the same, but move the important DNA data file!

    +

    Look in the backed-up project folder to make sure you moved the file correctly.

    +
    [user@milou2 linux_tutorial]$ ll backed_up_proj_folder/
    +total 0
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 dna_data_analysis_result_file_that_is_important-you_should_really_use_tab_completion_for_file_names.bam
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 last_years_data
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 temp_file-1
    +

    Another use for the move command is to rename things. When you think of it, renaming is just a special case of moving. You move the file to a location and give the file a new name in the process. The location you move the file to can very well be the same folder the file already is in. To give this a try, we will rename the folder a_strange_name to a better name.

    +
    $ mv a_strange_name a_better_name
    +

    Look around to see that the name change worked.

    +
    [user@milou2 linux_tutorial]$ mv a_strange_name a_better_name
    +[user@milou2 linux_tutorial]$ ll
    +total 448
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 a_better_name
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 24 13:40 backed_up_proj_folder
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 external_hdd
    +-rwxrwxr-x 1 user g20XXXXX  17198 Sep 24 13:36 files.tar.gz
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 24 13:40 important_results
    +drwxrwsr-x 2 user g20XXXXX 129024 Sep 19  2012 many_files
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 old_project
    +-rwxrwxr-x 1 user g20XXXXX      0 Sep 24 13:36 other_file.old
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 part_1
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 part_2
    +drwxrwsr-x 2 user g20XXXXX   2048 Jan 28  2012 this_has_a_file
    +drwxrwsr-x 2 user g20XXXXX   2048 Jan 28  2012 this_is_empty
    +-rwxrwxr-x 1 user g20XXXXX      0 Sep 19  2012 useless_file
    +

    Sometimes you don’t want to move things, you want to copy them. Moving a file will remove the original file, whereas copying the file will leave the original untouched. An example when you want to do this could be that you want to give a copy of a file to a friend. Imagine that you have a external hard drive that you want to place the file on. The file you want to give to your friend is data from last years project, which is located in your backed_up_project_folder, backed_up_proj_folder/last_years_data

    +

    As with the move command, the syntax is

    +
    $ cp <source> <destination>
    +$ cp backed_up_proj_folder/last_years_data external_hdd/
    +

    Take a look in the external_hdd to make sure the file got copied.

    +
    [user@milou2 linux_tutorial]$ cp backed_up_proj_folder/last_years_data external_hdd/
    +[user@milou2 linux_tutorial]$ ll external_hdd/
    +total 0
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 24 13:46 last_years_data
    +
    +
    +

    7 Deleting files

    +

    Sometimes you will delete files. Usually this is when you know that the file or files are useless to you, and they only take up space on your hard drive or UPPMAX account.

    +

    To delete a file, we use the ReMove command, rm. Syntax:

    +
    $ rm <file to remove>
    +

    If you want, you can also specify multiple files at once, as many as you want!

    +
    $ rm <file to remove> <file to remove> <file to remove> <file to remove> <file to remove>
    +
    +

    Danger

    +

    There is no trash bin in Linux. If you delete a file, it is gone. So be careful when deleting stuff.

    +
    +

    Try it out by deleting the useless file in the folder you are standing in. First, look around in the folder to see the file.

    +
    [user@milou2 linux_tutorial]$ ll
    +total 448
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 a_better_name
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 24 13:40 backed_up_proj_folder
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 24 13:46 external_hdd
    +-rwxrwxr-x 1 user g20XXXXX  17198 Sep 24 13:36 files.tar.gz
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 24 13:40 important_results
    +drwxrwsr-x 2 user g20XXXXX 129024 Sep 19  2012 many_files
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 old_project
    +-rwxrwxr-x 1 user g20XXXXX      0 Sep 24 13:36 other_file.old
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 part_1
    +drwxrwsr-x 2 user g20XXXXX   2048 Sep 19  2012 part_2
    +drwxrwsr-x 2 user g20XXXXX   2048 Jan 28  2012 this_has_a_file
    +drwxrwsr-x 2 user g20XXXXX   2048 Jan 28  2012 this_is_empty
    +-rwxrwxr-x 1 user g20XXXXX      0 Sep 19  2012 useless_file
    +

    Now remove it.

    +
    $ rm useless_file
    +

    Similarly, folders can be removed too. There is even a special command for removing folders, rmdir. They work similar to rm, except that they can’t remove files. There are two folders, this_is_empty and this_has_a_file, that we now will delete.

    +
    $ rmdir this_is_empty
    +$ rmdir this_has_a_file
    +

    If you look inside this_has_a_file,

    +
    [user@milou2 linux_tutorial]$ ll this_has_a_file
    +total 0
    +-rwxrwxr-x 1 user g20XXXXX 0 Jan 28  2012 file
    +

    you see that there is a file in there! Only directories that are completely empty can be deleted using rmdir. To be able to delete this_has_a_file, either delete the file manually and then remove the folder

    +
    $ rm this_has_a_file/file
    +$ rmdir this_has_a_file
    +

    or delete the directory recursively, which will remove this_has_a_file and everything inside:

    +
    $ rm -r this_has_a_file
    +
    +
    +

    8 Open files

    +

    So what happens if you give your files bad names like file1 or results? You take a break in a project and return to it 4 months later, and all those short names you gave your files doesn’t tell you at all what the files actually contain.

    +

    Of course, this never happens because you ALWAYS name your files so that you definitely know what they contain. But let’s say it did happen. Then the only way out is to look at the contents of the files and try to figure out if it is the file you are looking for.

    +

    Now, we are looking for that really good script we wrote a couple of months ago in that other project. Look in the project’s folder, old_project and find the script.

    +
    [user@milou2 linux_tutorial]$ ll old_project/
    +total 96
    +-rwxrwxr-x 1 user g20XXXXX 39904 Sep 19  2012 a
    +-rwxrwxr-x 1 user g20XXXXX     0 Sep 19  2012 stuff_1
    +-rwxrwxr-x 1 user g20XXXXX  1008 Sep 19  2012 the_best
    +

    Not so easy with those names.. We will have to use less to look at the files and figure out which is which.

    +
    $ less <filename>
    +

    Press q to close it down, use arrows keys to scroll up/down.

    +

    Have a look at the_best, that must be our script, right?

    +
    $ less old_project/the_best
    +

    I guess not. Carrot cakes might be the bomb, but they won’t solve bioinformatic problems. Have a look at the file a instead.

    +

    That’s more like it!

    +

    Now imagine that you had hundreds of files with weird names, and you really needed to find it. Lesson learned: name your files so that you know what they are! And don’t be afraid to create folders to organise files.

    +

    Another thing to think about when opening files in Linux is which program should you open the file in? The programs we covered during the lectures are nano and less. The main difference between these programs in that less can’t edit files, only view them. Another difference is that less doesn’t load the whole file into the RAM memory when opening it.

    +

    So, why care about how the program works? I’ll show you why. This time we will be opening a larger file, located in the course’s project folder. It’s 65 megabytes, so it is a tiny file compared with bio-data. Normal sequencing files can easily be 100-1000 times larger than this.

    +

    First, open the file with nano.

    +
    $ nano <filename>
    +$ nano /sw/courses/ngsintro/linux/linux_additional-files/large_file
    +

    Press Ctrl+X to close it down, use arrows to scroll up/down).

    +

    Is the file loaded yet? Now take that waiting time and multiply it with 100-1000. Now open the file with less. Notice the difference?

    +

    head and tail works the same was as less in this regard. They don’t load the whole file into RAM, they just take what they need.

    +

    To view the first rows of the large file, use head.

    +
    $ head <filename>
    +$ head /sw/courses/ngsintro/linux/linux_additional-files/large_file
    +

    Remember how to view an arbitrary number of first rows in a file?

    +
    $ head -n <number of rows to view> <filename>
    +$ head -n 23 /sw/courses/ngsintro/linux/linux_additional-files/large_file
    +

    The same syntax for viewing the last rows of a file with tail:

    +
    $ tail <filename>
    +$ tail /sw/courses/ngsintro/linux/linux_additional-files/large_file
    +$ tail -n <number of rows to view> <filename>
    +$ tail -n 23 /sw/courses/ngsintro/linux/linux_additional-files/large_file
    +
    +
    +

    9 Wildcards

    +

    Sometimes (most of the time really) you have many files. So many that it would take you a day just to type all their names. This is where wildcards saves the day. The wildcard symbol in Linux is the star sign, * , and it means literally anything. Say that you want to move all the files which has names starting with sample_1_ and the rest of the name doesn’t matter. You want all the files belonging to sample_1. Then you could use the wildcard to represent the rest of the name.

    +

    DO NOT run this command, it’s just an example.

    +
    $ mv  sample_1_*  my_other_folder
    +

    We can try it out on the example files I have prepared. There are two folders called part_1 and part_2. We want to collect all the .txt files from both these folders in one of the folders. Look around in both the folders to see what they contain.

    +
    [user@milou2 linux_tutorial]$ ll part_1/
    +total 0
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 file_1.txt
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 file_2.txt
    +[user@milou2 linux_tutorial]$ ll part_2
    +total 0
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 file_3.txt
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 file_4.txt
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 garbage.tmp
    +-rwxrwxr-x 1 user g20XXXXX 0 Sep 19  2012 incomplete_datasets.dat
    +

    We see that part_1 only contains .txt files, and that part_2 contains some other files as well. The best option seems to be to move all .txt files from part_2 info part_1.

    +
    $ mv part_2/*.txt part_1/
    +

    The wildcard works with most, if not all, Linux commands. We can try using wildcards with ls. Look in the folder many_files. Yes, there are hundreds of .docx files in there. But, there are a couple of .txt files in there as well. Find out how many .docx and .txt files exist.

    +

    Try to figure out the solution on your own. Then check the answer below.

    +
    +
    +
    $ ll many_files/*.docx
    +$ ll many_files/*.txt
    +
    +
    +
    +
    +

    10 Utility commands

    +

    Ok, the last 2 commands for now are top and man.

    +

    top can be useful when you want to look at which programs are being run on the computer, and how hard the computer is working. Type top and have a look.

    +
    $ top
    +

    Press q to exit.

    +
    Tasks: 376 total,   2 running, 290 sleeping,   0 stopped,   0 zombie
    +%Cpu(s):  2.7 us,  1.3 sy,  0.0 ni, 95.3 id,  0.1 wa,  0.0 hi,  0.6 si,  0.0 st
    +KiB Mem : 32590776 total, 16233548 free,  8394804 used,  7962424 buff/cache
    +KiB Swap: 99999744 total, 99999744 free,        0 used. 22658832 avail Mem
    +
    +  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                       
    + 3286 roy       20   0 4557248 522400 170808 R  12.3  1.6  62:49.20 gnome-shell                   
    + 3113 roy       20   0 1282356 385012 290540 S   8.0  1.2  42:00.49 Xorg                          
    +22213 roy       20   0 5474576 544848 101592 S   5.6  1.7 102:55.33 zoom                          
    + 6186 roy       20   0  710140  60504  35836 S   3.0  0.2   0:00.62 terminator                    
    + 4248 roy       20   0 2737604 556212 140580 S   2.7  1.7  54:51.48 QtWebEngineProc               
    + 4632 roy       20   0 4866068 0.993g 281532 S   2.7  3.2  69:18.68 firefox                       
    + 6548 roy       20   0 3703060 509340 189452 S   2.7  1.6  15:26.80 Web Content                   
    + 9338 roy       20   0 4407324 846700 213324 S   2.7  2.6  15:53.71 Web Content                   
    + 4776 roy       20   0 3310524 318364 102700 S   2.0  1.0   8:53.07 WebExtensions                 
    + 6595 roy       20   0 4133152 992224 187540 S   1.3  3.0  18:51.05 Web Content                   
    +  952 root     -51   0       0      0      0 S   1.0  0.0   2:40.89 irq/51-SYNA2393               
    + 7800 roy       20   0 1213744 238536 129392 S   1.0  0.7  11:15.74 atom                          
    +    1 root      20   0  226080   9836   6692 S   0.7  0.0   2:07.87 systemd                       
    + 6690 roy       20   0 3492596 560304 166588 S   0.7  1.7   8:08.77 Web Content                   
    +12895 roy       20   0 3320332 294820 172212 S   0.7  0.9   7:05.93 Web Content                   
    +   10 root      20   0       0      0      0 I   0.3  0.0   2:43.21 rcu_sched                     
    + 1052 root      20   0 2505296  36228  22444 S   0.3  0.1   3:45.16 containerd                    
    + 2631 gdm       20   0 4044492 198480 142328 S   0.3  0.6   1:55.32 gnome-shell
    +

    Each row in top corresponds to one program running on the computer, and the column describe various information about the program. The right-most column shows you which program the row is about.

    +

    There are mainly 2 things that are interesting when looking in top. The column %CPU describes how much cpu is used by each program. If you are doing calculations, which is what bioinformatics is mostly about, the cpu usage should be high. The numbers in the column is how many percent of a core the program is running. If you have a computer with 8 cores, like the UPPMAX computers, you can have 8 programs using 100% of a core each running at the same time without anything slowing down. As soon as you start a 9th program, it will have to share a core with another program and those 2 programs will run at half-speed since a core can only work that fast. In the example above, program gnome-shell is using 12.3% of a core.

    +

    The column %MEM describes how much memory each program uses. The numbers mean how many percent of the total memory a program uses. In the example above, the program firefox is using 3.2% of the total memory.

    +

    The area in the top describes the overall memory usage. Total tells you how much memory the computer has, used tells you how much of the memory is being used at the moment, and free tells you how much memory is free at the moment.

    +

    Total = Used + Free

    +

    A warning sign you can look for in top is when you are running an analysis which seems to take forever to complete, and you see that there is almost no cpu usage on the computer. That means that the computer is not doing any calculation, which could be bad. If you look at the memory usage at the same time, and see that it’s maxed out (used 100% of total), you can more or less abort the analysis.

    +

    When the memory runs out, the computer more or less stops. Since it can’t fit everything into the RAM memory, it will start using the hard drive to store the things it can’t fit in the RAM. Since the hard drive is ~1000 times slower than the RAM, things will be going in slow-motion. The solution could be to either change the settings of the program you are running to decrease the memory usage (if the program has that functionality), or just get a computer with more memory.

    +

    You might wonder how the heck am I supposed to be able to remember all these commands, options and flags? The simple answer is that you won’t. Not all of them at least. You might remember ls, but was it -l or -a you should use to see hidden files? You might wish that there was a manual for these things.

    +

    Good news everyone, there is a manual! To get all the nitty-gritty details about ls, you use the man command.

    +
    $ man <command you want to look at>
    +$ man ls
    +
    LS(1)                            User Commands                            LS(1)
    +
    +NAME
    +       ls - list directory contents
    +
    +SYNOPSIS
    +       ls [OPTION]... [FILE]...
    +
    +DESCRIPTION
    +       List  information  about  the  FILEs (the current directory by default).
    +       Sort entries alphabetically if none of -cftuvSUX nor  --sort  is  speci‐
    +       fied.
    +
    +       Mandatory arguments to long options are mandatory for short options too.
    +
    +       -a, --all
    +              do not ignore entries starting with .
    +
    +       -A, --almost-all
    +              do not list implied . and ..
    +
    +       --author
    +              with -l, print the author of each file
    +
    +       -b, --escape
    +              print C-style escapes for nongraphic characters
    +
    +       --block-size=SIZE
    +              scale  sizes by SIZE before printing them; e.g., '--block-size=M'
    + Manual page ls(1) line 1 (press h for help or q to quit)
    +

    This will open a less window (remember, q to close it down, arrows to scroll) with the manual page about ls. Here you will be able to read everything about ls. You’ll see which flag does what (-a is to show the hidden files, which in linux are files with a name starting with a dot .), which syntax the program has, etc. If you are unsure about how to use a command, look it up using man.

    +

    The man pages can be a bit tricky to understand at first, but you get used to it with time. If it is still unclear, try searching for it on the internet. You are bound to find someone with the exact same question as you, that has already asked on a forum, and gotten a good answer. 5 years ago.

    +
    +
    +
    + +
    +
    +Optional +
    +
    +
    +

    If you still have time left on the lab and you finished early, check out the Linux file permissions lab.

    +
    +
    + + +
    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/linux/lab_linux_permissions.html b/2311/topics/linux/lab_linux_permissions.html new file mode 100644 index 00000000..bfbcf84b --- /dev/null +++ b/2311/topics/linux/lab_linux_permissions.html @@ -0,0 +1,783 @@ + + + + + + + + + + +File permissions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    File permissions

    +

    Ownership and permissions for files and folders

    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Martin Dahlö

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    In code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window.

    +
    +
    +
    +

    1 Ownership & Permissions

    +

    As Linux can be a multi-user environment it is important that files and directories can have different owners and permissions to keep people from editing or executing your files.

    +
    +

    1.1 Owners

    +

    The permissions are defined separately for users, groups and others.

    +

    The user is the username of the person who owns the file. By default the user who creates a file will become its owner. The group is a group of users that co-own the file. They will all have the same permissions to the file. This is useful in any project where a group of people are working together. The others is quite simply everyone else’s permissions.

    +
    +
    +

    1.2 Permissions

    +

    There are four permissions that a file or directory can have. Note the one character designations/flags, r,w,x and -.

    +

    In all cases, if the file or directory has the flag it means that it is enabled.

    +

    Read: r

    +

    File: Whether the file can be opened and read.
    +Directory: Whether the contents of the directory can be listed.

    +

    Write: w

    +

    File: Whether the file can be modified. (Note that for renaming or deleting a file you need additional directory permissions.)
    +Directory: Whether the files in the directory can be renamed or deleted.

    +

    Execute: x

    +

    File: Whether the file can be executed as a program or shell script.
    +Directory: Whether the directory can be entered using cd.

    +

    No permissions: -

    +
    +
    +
    +

    2 Interpreting permissions

    +

    Make an empty directory we can work in and make a file.

    +
    +
    +
    $ cd /proj/naiss2023-22-862/nobackup/username
    +$ mkdir advlinux
    +$ cd advlinux
    +$ touch  filename
    +$ ls -lh
    +total 0
    + -rw-r--r-- 1 S_D staff 0B Sep 21 13:54 filename
    +
    +
    +

    (-lh means long and human readable, displaying more information about the files or directories in a human understandable format)

    +

    This shows us a cryptic line for each file/folder, where the columns are as following:

    +
    -rw-rw-r--   : permissions
    +1            : number of linked hard-links
    +S_D          : owner of the file
    +staff        : to which group this file belongs to
    +0            : file size
    +Sep 21 13:54 : modification/creation date and time
    +filename     : file/directory name
    +

    The first segment, -rw-r--r--, describes the ownerships and permissions of our newly created file. The very first character, in this case -, shows the file’s type. It can be any of these:

    +

    d = directory - = regular file l = symbolic link s = Unix domain socket p = named pipe c = character device file b = block device file

    +

    As expected the file we have just created is a regular file. Ignore the types other than directory, regular and symbolic link as they are outside the scope of this course.

    +

    The next nine characters, in our case rw-r--r--, can be divided into three groups consisting of three characters in order from left to right. In our case rw-, r-- and r--. The first group designates the users permissions, the second the groups permissions and the third the others permissions. As you may have guessed the within group permissions are ordered, the first always designates read permissions, the second write and the third executability.

    +

    This translates our files permissions to say this -rw-r--r--:

    +
    - It is a regular file.
    +- The user has read & write permission, but not execute.
    +- The group has read permission but not write and execute.
    +- Everyone else (other), have read permission but not write and execute.
    +

    As another example, lets create a directory.

    +
    $ mkdir directoryname
    +$ ls -lh
    +total 0
    +drwxr-xr-x  2 S_D  staff    68B Sep 21 14:41 directoryname
    +-rw-r--r--  1 S_D  staff     0B Sep 21 13:54 filename
    +

    As you can see the first character correctly identifies it as d, a directory, and all user groups have x, execute permissions, to enter the directory by default.

    +
    +
    +

    3 Editing Ownership & Permissions

    +

    The command to set file permission is chmod which means CHange MODe. Only the owner can set file permissions.

    +
      +
    1. First you decide which group you want to set permissions for. User, u, group, g, other, o, or all three, a.
    2. +
    3. Next you either add, +, remove, -, or wipe out previous and add new, =, permissions.
    4. +
    5. Then you specify the kind of permission: r,w,x, or -.
    6. +
    +

    Lets revisit our example file and directory to test this.

    +
    $ ls -lh
    +total 0
    +drwxr-xr-x  2 S_D  staff    68B Sep 21 14:41 directoryname
    +-rw-r--r--  1 S_D  staff     0B Sep 21 13:54 filename
    +$ chmod a=x filename
    +$ ls -lh
    +total 0
    +drwxr-xr-x  2 S_D  staff    68B Sep 21 14:41 directoryname
    +---x--x--x  1 S_D  staff     0B Sep 21 13:54 filename
    +

    As you can see this affected all three, a, it wiped the previous permissions, =, and added an executable permission, x, to all three groups.

    +

    Try some others both on the file and directory to get the hang of it.

    +
    $ chmod g+r filename
    +$ chmod u-x filename
    +$ chmod ug=rx filename
    +$ chmod a=- filename
    +$ chmod a+w directoryname
    +

    In no more than two commands, change the file permissions from

    +
    ----------
    +

    to

    +
    -rw-rw--wx
    +

    Notice also that we here gave everyone writing permission to the file, that means that ANYONE can write to the file. Not very safe.

    +
    +
    +
    $ chmod ug+rw filename  
    +$ chmod o=wx filename
    +
    +
    +
    + +
    +

    5 Grep

    +

    Some files can be so large that opening it in a program would be very hard on your computer. It could be a file containing biological data, it could be a log file of a transfer where we want check for any errors. No matter the reason, a handy tool to know is the grep command.

    +

    grep searches for a specific string in one or more files. Case sensitive/insensitive or regular expressions work as well.

    +

    Let’s start, as always, by cleaning our directory.

    +
    $ rm -r *
    +

    Then let’s create a file with some text in it that we can work with. I have supplied some great text below.

    +
    $ nano textfile
    +
    +Cats sleep anywhere, any table, any chair.
    +Top of piano, window-ledge, in the middle, on the edge.
    +Open draw, empty shoe, anybody's lap will do.
    +Fitted in a cardboard box, in the cupboard with your frocks.
    +Anywhere! They don't care! Cats sleep anywhere.
    +

    Now let’s see how the grep command works. The syntax is:

    +
    grep "string" filename/filepattern
    +

    Some examples for you to try and think about:

    +
    $ grep "Cat" textfile
    +$ grep "cat" textfile
    +

    As you can see the last one did not return any results. Add a -i for case insensitive search.

    +
    $ grep -i "cat" textfile
    +

    Now let’s copy the file and check both of them together by matching a pattern for the filenames.

    +
    $ cp textfile textcopy
    +$ grep "Cat" text*
    +

    The * will ensure that any file starting with text and then anything following will be searched. This example would perhaps be more real if we had several text files with different texts and we were looking for a specific string in any of them.

    +

    Copy the file sample_1.sam to your folder using the command below

    +
    $ cp /sw/courses/ngsintro/linux/linux_additional-files/sample_1.sam .
    +

    Use grep to search in the file for a specific string of nucleotides, for example:

    +
    $ grep "TACCACCGAAATCTGTGCAGAGGAGAACGCAGCTCCGCCCTCGCGGTGCTCTCCGGGTCTGTGCTGAGGAG" sample_1.sam
    +

    Try with shorter sequences. When do you start getting lots of hits? This file is only a fraction of a genome, you would have gotten many times more hits doing this to a complete many GB large sam file.

    +

    Use grep to find all lines with chr1 in them. This output is too much to be meaningful. Send it to a file (>) where you have now effectively stored all the chromosome 1 information.

    +
    +
    +

    6 Piping

    +

    A useful tool in linux environment is the use of pipes. What they essentially do is connect the first command to the second command and the second command to the third command etc for as many commands as you want or need.

    +

    This is often used in UPPMAX jobs and other analysis as there are three major benefits. The first is that you do not have to stand in line to get a core or a node twice. The second is that you do not generate intermediary data which will clog your storage, you go from start file to result. The third is that it may actually be faster.

    +

    The pipe command has this syntax

    +
    command 1 | command 2
    +

    The | is the pipe symbol (on mac keyboard alt+7), signifying that whatever output usually comes out of command 1 should instead be directly sent to command 2 and output in the manner that command 2 inputs.

    +

    In a hypothetical situation you have a folder with hundreds of files and you know the file you are looking for is very large but you can’t remember its name.

    +

    Let’s do a ls -l in the /etc directory and pipe the output to be sorted by file size. -n means we are sorting numerically and not alphabetically, -k 5 says look at the fifth column of output, which happens to be the file size of ls command.

    +
    $ ls -l /etc | sort -k 5 -n
    +

    An example use would be to align a file and directly send the now aligned file to be converted into a different format that may be required for another part of the analysis.

    +

    The next step requires us to use a bioinformatics software called samtools. To be able to use this program we first have to load the module for it. We will cover this in the UPPMAX lectures, so if you are a bit too fast for you own good, you will just have to type this command:

    +
    $ module load bioinfo-tools samtools
    +

    Here is an example where we convert the samfile to a bamfile (-Sb literally means the input is Sam and to output in bam) and pipe it to immediately get sorted, not even creating the unsorted bamfile intermediary. Notice that samtools is made to take the single - after samtools sort as the position of the piped data from samtools view.

    +
    $ samtools view -bS sample_1.sam | samtools sort - -o outbam
    +

    This should have generated a file called outbam.bam in your current folder. We will have some more examples of pipes in the next section.

    +
    +
    +

    7 Word Count

    +

    wc for Word Count is a useful command for counting the number of occurrences of a word in a file. This is easiest explained with an example.

    +

    Let’s return to our sample_1.sam.

    +
    $ wc sample_1.sam
    +233288 3666760 58105794 sample_1.sam
    +

    This can be interpreted like this:

    +

    Number of lines = 233288
    +Number of words = 3666760
    +Number of characters = 58105794

    +

    To make this more meaningful, let’s use the pipes and grep command seen previously to see how many lines and how many times the string of nucleotides CATCATCAT exist in this file.

    +
    $ grep "CATCATCAT" sample_1.sam | wc
    +60  957 15074
    +

    To see only the line count you can add -l after wc and to count only characters -m.

    +

    Output only the amount of lines that have chr1 in them from sample_1.sam.

    +
    +
    +
    $ grep "chr1" sample_1.sam | wc -l
    +
    +
    +

    Count the lines containing CATCATCAT in the outbam.bam file.

    +
    +
    +
    $ samtools view outbam.bam | grep "CATCATCAT" | wc -l
    +
    +
    +
    +
    +

    8 Bonus exercise 1

    +

    These are some harder assignments, so don’t worry about it if you didn’t have time to do it.

    +

    Lets look at grep and use some regular expressions http://www.cheatography.com/davechild/cheat-sheets/regular-expressions/

    +

    From file sample_1.sam find all lines that start with @ and put them in a file called at.txt.

    +
    +
    +
    $ grep "^@" sample_1.sam > at.txt
    +
    +
    +

    Find all the lines that end with at least 3 numbers from at.txt. Sometimes, you have to escape {} with \{\})

    +
    +
    +
    $ grep "[0-9]\{3\}$" sample_1.sam
    +
    +
    +
    +
    +

    9 Bonus exercise 2

    +

    [sed](http://www.grymoire.com/Unix/Sed.html) is a handy tool to replace strings in files.

    +

    You have realized that all the chromosomes have been misnamed as chr3 when they should be chr4. Use sed to replace chr3 with chr4 in sample_1.sam and output it to sample_2.sam.

    +

    The solution to this replaces the first instance on each line of chr3. What if we have multiple instances? What if we had wanted to replace chr1? This would effect chr10-19 as well! There are many things to consider :).

    +
    +
    +
    $ sed "s/chr1/chr2/" sample_1.sam > sample_2.sam
    +
    +
    +
    +
    +

    10 Bonus exercise 3

    +

    Bash loops are great for moving or renaming multiple files as well as many many other uses.

    +

    Create a couple of files as seen below

    +
    $ touch one.bam two.sam three.bam four.sam five.bam six.sam
    +

    All the files are actually in bam format. What a crazy mistake! Create a bash loop that changes all files ending in .sam to end with .bam instead.

    +

    The bash loop syntax is this:

    +
    $ for _variable_ in _pattern_; do _command with $variable_; done
    +

    To rename file1 to file2 you write this:

    +
    $ mv file1 file2
    +

    which effectively is the same thing as

    +
    $ cp file1 file2
    +$ rm file1
    +

    Ponder how this can be used to your advantage:

    +
    $ i=filename
    +$ echo ${i/name}stuff
    +filestuff
    +
    +
    +
    $ for f in *.sam
    +do
    +  mv $f ${f/.sam}.bam;
    +done
    +
    +
    + + +
    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/linux/slide_linux_advanced.pdf b/2311/topics/linux/slide_linux_advanced.pdf new file mode 100644 index 00000000..d44985c1 Binary files /dev/null and b/2311/topics/linux/slide_linux_advanced.pdf differ diff --git a/2311/topics/linux/slide_linux_filetypes.pdf b/2311/topics/linux/slide_linux_filetypes.pdf new file mode 100644 index 00000000..684c57c5 Binary files /dev/null and b/2311/topics/linux/slide_linux_filetypes.pdf differ diff --git a/2311/topics/linux/slide_linux_intro.pdf b/2311/topics/linux/slide_linux_intro.pdf new file mode 100644 index 00000000..ce3239d7 Binary files /dev/null and b/2311/topics/linux/slide_linux_intro.pdf differ diff --git a/2311/topics/linux/slide_qol_termexp.pdf b/2311/topics/linux/slide_qol_termexp.pdf new file mode 100644 index 00000000..2cf98460 Binary files /dev/null and b/2311/topics/linux/slide_qol_termexp.pdf differ diff --git a/2311/topics/other/assets/HG00097_1_fastqc.html b/2311/topics/other/assets/HG00097_1_fastqc.html new file mode 100644 index 00000000..5cfebd4e --- /dev/null +++ b/2311/topics/other/assets/HG00097_1_fastqc.html @@ -0,0 +1,187 @@ +HG00097_1.fq FastQC Report
    FastQCFastQC Report
    on 4 nov 2020
    HG00097_1.fq

    [OK]Basic Statistics

    MeasureValue
    FilenameHG00097_1.fq
    File typeConventional base calls
    EncodingSanger / Illumina 1.9
    Total Sequences29532
    Sequences flagged as poor quality0
    Sequence length101
    %GC39

    [FAIL]Per base sequence quality

    Per base quality graph

    [OK]Per sequence quality scores

    Per Sequence quality graph

    [OK]Per base sequence content

    Per base sequence content

    [WARN]Per sequence GC content

    Per sequence GC content graph

    [OK]Per base N content

    N content graph

    [OK]Sequence Length Distribution

    Sequence length distribution

    [OK]Sequence Duplication Levels

    Duplication level graph

    [OK]Overrepresented sequences

    No overrepresented sequences

    [OK]Adapter Content

    Adapter graph

    \ No newline at end of file diff --git a/2311/topics/other/assets/HG00097_2_fastqc.html b/2311/topics/other/assets/HG00097_2_fastqc.html new file mode 100644 index 00000000..4577de8e --- /dev/null +++ b/2311/topics/other/assets/HG00097_2_fastqc.html @@ -0,0 +1,187 @@ +HG00097_2.fq FastQC Report
    FastQCFastQC Report
    on 4 nov 2020
    HG00097_2.fq

    [OK]Basic Statistics

    MeasureValue
    FilenameHG00097_2.fq
    File typeConventional base calls
    EncodingSanger / Illumina 1.9
    Total Sequences29532
    Sequences flagged as poor quality0
    Sequence length101
    %GC39

    [FAIL]Per base sequence quality

    Per base quality graph

    [OK]Per sequence quality scores

    Per Sequence quality graph

    [OK]Per base sequence content

    Per base sequence content

    [WARN]Per sequence GC content

    Per sequence GC content graph

    [OK]Per base N content

    N content graph

    [OK]Sequence Length Distribution

    Sequence length distribution

    [OK]Sequence Duplication Levels

    Duplication level graph

    [OK]Overrepresented sequences

    No overrepresented sequences

    [OK]Adapter Content

    Adapter graph

    \ No newline at end of file diff --git a/2311/topics/other/assets/HG00100_1_fastqc.html b/2311/topics/other/assets/HG00100_1_fastqc.html new file mode 100644 index 00000000..5ac528f5 --- /dev/null +++ b/2311/topics/other/assets/HG00100_1_fastqc.html @@ -0,0 +1,187 @@ +HG00100_1.fq FastQC Report
    FastQCFastQC Report
    on 4 nov 2020
    HG00100_1.fq

    [OK]Basic Statistics

    MeasureValue
    FilenameHG00100_1.fq
    File typeConventional base calls
    EncodingSanger / Illumina 1.9
    Total Sequences41902
    Sequences flagged as poor quality0
    Sequence length100-108
    %GC39

    [OK]Per base sequence quality

    Per base quality graph

    [OK]Per sequence quality scores

    Per Sequence quality graph

    [OK]Per base sequence content

    Per base sequence content

    [WARN]Per sequence GC content

    Per sequence GC content graph

    [OK]Per base N content

    N content graph

    [WARN]Sequence Length Distribution

    Sequence length distribution

    [OK]Sequence Duplication Levels

    Duplication level graph

    [OK]Overrepresented sequences

    No overrepresented sequences

    [OK]Adapter Content

    Adapter graph

    \ No newline at end of file diff --git a/2311/topics/other/assets/HG00100_2_fastqc.html b/2311/topics/other/assets/HG00100_2_fastqc.html new file mode 100644 index 00000000..06e111c6 --- /dev/null +++ b/2311/topics/other/assets/HG00100_2_fastqc.html @@ -0,0 +1,187 @@ +HG00100_2.fq FastQC Report
    FastQCFastQC Report
    on 4 nov 2020
    HG00100_2.fq

    [OK]Basic Statistics

    MeasureValue
    FilenameHG00100_2.fq
    File typeConventional base calls
    EncodingSanger / Illumina 1.9
    Total Sequences41902
    Sequences flagged as poor quality0
    Sequence length100-108
    %GC39

    [OK]Per base sequence quality

    Per base quality graph

    [OK]Per sequence quality scores

    Per Sequence quality graph

    [OK]Per base sequence content

    Per base sequence content

    [WARN]Per sequence GC content

    Per sequence GC content graph

    [OK]Per base N content

    N content graph

    [WARN]Sequence Length Distribution

    Sequence length distribution

    [OK]Sequence Duplication Levels

    Duplication level graph

    [OK]Overrepresented sequences

    No overrepresented sequences

    [OK]Adapter Content

    Adapter graph

    \ No newline at end of file diff --git a/2311/topics/other/assets/HG00101_1_fastqc.html b/2311/topics/other/assets/HG00101_1_fastqc.html new file mode 100644 index 00000000..78f32d06 --- /dev/null +++ b/2311/topics/other/assets/HG00101_1_fastqc.html @@ -0,0 +1,187 @@ +HG00101_1.fq FastQC Report
    FastQCFastQC Report
    on 4 nov 2020
    HG00101_1.fq

    [OK]Basic Statistics

    MeasureValue
    FilenameHG00101_1.fq
    File typeConventional base calls
    EncodingSanger / Illumina 1.9
    Total Sequences22831
    Sequences flagged as poor quality0
    Sequence length101
    %GC38

    [OK]Per base sequence quality

    Per base quality graph

    [OK]Per sequence quality scores

    Per Sequence quality graph

    [OK]Per base sequence content

    Per base sequence content

    [WARN]Per sequence GC content

    Per sequence GC content graph

    [OK]Per base N content

    N content graph

    [OK]Sequence Length Distribution

    Sequence length distribution

    [OK]Sequence Duplication Levels

    Duplication level graph

    [OK]Overrepresented sequences

    No overrepresented sequences

    [OK]Adapter Content

    Adapter graph

    \ No newline at end of file diff --git a/2311/topics/other/assets/HG00101_2_fastqc.html b/2311/topics/other/assets/HG00101_2_fastqc.html new file mode 100644 index 00000000..aeb769ff --- /dev/null +++ b/2311/topics/other/assets/HG00101_2_fastqc.html @@ -0,0 +1,187 @@ +HG00101_2.fq FastQC Report
    FastQCFastQC Report
    on 4 nov 2020
    HG00101_2.fq

    [OK]Basic Statistics

    MeasureValue
    FilenameHG00101_2.fq
    File typeConventional base calls
    EncodingSanger / Illumina 1.9
    Total Sequences22831
    Sequences flagged as poor quality0
    Sequence length101
    %GC38

    [OK]Per base sequence quality

    Per base quality graph

    [OK]Per sequence quality scores

    Per Sequence quality graph

    [OK]Per base sequence content

    Per base sequence content

    [WARN]Per sequence GC content

    Per sequence GC content graph

    [OK]Per base N content

    N content graph

    [OK]Sequence Length Distribution

    Sequence length distribution

    [OK]Sequence Duplication Levels

    Duplication level graph

    [OK]Overrepresented sequences

    No overrepresented sequences

    [OK]Adapter Content

    Adapter graph

    \ No newline at end of file diff --git a/2311/topics/other/assets/mac_keyboard_alt.jpg b/2311/topics/other/assets/mac_keyboard_alt.jpg new file mode 100644 index 00000000..2cf99eb6 Binary files /dev/null and b/2311/topics/other/assets/mac_keyboard_alt.jpg differ diff --git a/2311/topics/other/assets/mac_keyboard_normal.jpg b/2311/topics/other/assets/mac_keyboard_normal.jpg new file mode 100644 index 00000000..1dea2848 Binary files /dev/null and b/2311/topics/other/assets/mac_keyboard_normal.jpg differ diff --git a/2311/topics/other/assets/mac_keyboard_shift.jpg b/2311/topics/other/assets/mac_keyboard_shift.jpg new file mode 100644 index 00000000..7af577fd Binary files /dev/null and b/2311/topics/other/assets/mac_keyboard_shift.jpg differ diff --git a/2311/topics/other/assets/mac_keyboard_shitfAlt.jpg b/2311/topics/other/assets/mac_keyboard_shitfAlt.jpg new file mode 100644 index 00000000..36113de0 Binary files /dev/null and b/2311/topics/other/assets/mac_keyboard_shitfAlt.jpg differ diff --git a/2311/topics/other/assets/thinlinc_00.png b/2311/topics/other/assets/thinlinc_00.png new file mode 100644 index 00000000..61381e32 Binary files /dev/null and b/2311/topics/other/assets/thinlinc_00.png differ diff --git a/2311/topics/other/assets/thinlinc_01.png b/2311/topics/other/assets/thinlinc_01.png new file mode 100644 index 00000000..a74ef41e Binary files /dev/null and b/2311/topics/other/assets/thinlinc_01.png differ diff --git a/2311/topics/other/assets/thinlinc_02.png b/2311/topics/other/assets/thinlinc_02.png new file mode 100644 index 00000000..97cca358 Binary files /dev/null and b/2311/topics/other/assets/thinlinc_02.png differ diff --git a/2311/topics/other/assets/thinlinc_03.png b/2311/topics/other/assets/thinlinc_03.png new file mode 100644 index 00000000..84b3a75b Binary files /dev/null and b/2311/topics/other/assets/thinlinc_03.png differ diff --git a/2311/topics/other/lab_connect.html b/2311/topics/other/lab_connect.html new file mode 100644 index 00000000..ae737ab6 --- /dev/null +++ b/2311/topics/other/lab_connect.html @@ -0,0 +1,578 @@ + + + + + + + + + + +Connecting to UPPMAX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Connecting to UPPMAX

    +
    +
    + Connecting to UPPMAX through SSH and GUI (Browser and ThinLinc) +
    +
    +
    +
    + + +
    + + + + +
    + + +
    + + + + +
    + + + + +

    We will teach you two different ways to connect to UPPMAX. From UPPMAX point of view it doesn’t matter which one you use, and you can change whenever you want to or even use both ways simultaiously. The first one is a text-based SSH connection, and the other one is a graphical remote desktop. The latter one is useful if you need to view images or documents in GUI programs without having to first download the image/document to your own computer first. Since it is using graphics, it will require you to have an internet connection that is good and stable.

    +

    The reason we will teach you two ways is that some parts of this course will require you to view plots and images, and adding an additional download step would just unneccesarily complicate things.

    +
    +

    1 SSH connection

    +

    Let’s look at the text-based SSH approach first. This type of connection work just fine even on slow internet connections since it only transmitts small amounts of text when you work with it. You will need an SSH program to do this, which fortunately is included in most major operating systems:

    +
      +
    • Linux: Use Terminal (Included by default)
    • +
    • OSX: Use Terminal (Included by default)
    • +
    • Windows: Use Powershell or Command prompt, both should be installed by default
    • +
    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    Where username is mentioned, change to your user name.

    +
    +
    +

    Fire up the available SSH program and enter the following:

    +
    $ ssh username@rackham.uppmax.uu.se
    +

    Enter your password when prompted. As you type, nothing will show on the screen. No stars, no dots. It is supposed to be that way. Just type the password and press enter, it will be fine.

    +

    Now your screen should look something like this:

    +
    dahlo@dahlo-xps ~ $ ssh dahlo@rackham.uppmax.uu.se
    +Last login: Fri May 18 15:03:59 2018 from mi04.icm.uu.se
    + _   _ ____  ____  __  __    _    __  __
    +| | | |  _ \|  _ \|  \/  |  / \   \ \/ /   | System:    rackham4
    +| | | | |_) | |_) | |\/| | / _ \   \  /    | User:      dahlo
    +| |_| |  __/|  __/| |  | |/ ___ \  /  \    |
    + \___/|_|   |_|   |_|  |_/_/   \_\/_/\_\   |
    +
    +###############################################################################
    +
    +       User Guides: http://www.uppmax.uu.se/support/user-guides
    +       FAQ: http://www.uppmax.uu.se/support/faq
    +
    +       Write to support@uppmax.uu.se, if you have questions or comments.
    +
    +
    +dahlo@rackham4 ~ $
    +

    Now you are connected to UPPMAX and can start working.

    +
    +
    +

    2 Remote desktop

    +

    You can work on UPPMAX interactively through a graphical-user-interface (GUI) desktop environment using ThinLinc.

    +

    We have a ThinLinc server running at one of the login nodes which allows users to run a remote desktop. It can be reached from a web browser (Chrome and Firefox are the recommended web browsers) or from the ThinLink App. For more details please look here: https://uppmax.uu.se/support-sv/user-guides/thinlinc-graphical-connection-guide/

    +
    +

    2.1 Web browser

    +

    To be able to login via a web browser you will have to set up two-factor authentication first. Follow the instructions at the UPPMAX homepage, and once you are done you can continue below.

    +
      +
    1. Go to the login page, https://rackham-gui.uppmax.uu.se/

    2. +
    3. Enter your UPPMAX username.

    4. +
    5. Enter your UPPMAX password, followed by your current two-factor authentication code. Eg. if your password is hunter2 and your current two-factor authentication code is 123456 you will enter hunter2123456 as your password.

      +
      +
      +

      +
      +
    6. +
    7. It will ask you which profile you want to use, so first press the Forward button. Then you can choose which desktop environment you want to use. Xfce is pretty straight-forward and easy to use, but feel free to try either of them. You get to choose every time you login so it’s not a permanent choice.

      +
      +
      +

      +
      +
    8. +
    9. Once your desktop has been loaded, start a terminal either by clicking the black terminal icon at the bottom of the screen, or by pressing the Applications button in the top left corner and select Terminal Emulator.

      +
      +
      +

      +
      +
    10. +
    +
    + +
    +
    +

    3 After connection to UPPMAX

    +

    From this point forward there is no difference between the two different ways of connection to UPPMAX. Both ways result in you having a terminal running on UPPMAX and from UPPMAX point of view they are the same.

    + + +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/2311/topics/other/lab_download_files.html b/2311/topics/other/lab_download_files.html new file mode 100644 index 00000000..3a82a4a6 --- /dev/null +++ b/2311/topics/other/lab_download_files.html @@ -0,0 +1,520 @@ + + + + + + + + + +Uppmax IO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Uppmax IO

    +

    Downloading and uploading files from Uppmax

    +
    +
    + + +
    + + + + +
    + + +
    + + + + +
    + + + + +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    In code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window.

    +
    +
    +
    +

    1 Local workspace

    +

    Start by creating a folder on your laptop where the files that you will download should end up. You need to have write permission in this folder. This folder will be referred to as your local workspace throughout these instructions.

    +

    Open a terminal window on your laptop and move into your local workspace.

    +
    +
    +

    2 Download a file from UPPMAX

    +

    Lets assume that you have a file “results.txt” in the following folder on UPPMAX:

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/somefolder/
    +
    +
    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    username and somefolder should be replaced with your real username and a real folder name.

    +
    +
    +

    To download the file to your local workspace type:

    +
    +
    +
    Local Terminal
    +
    +
    scp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/somefolder/results.txt .
    +
    +

    Note that the last . means that the file will keep the original name.

    +
    +
    +

    3 Upload a file to UPPMAX

    +

    Now lets imagine that you have developed a script on your laptop and want to upload it to UPPMAX. The script is stored in your local workspace and is called “script.sh”. Type this in your local workspace to upload the file to UPPMAX:

    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    username and somefolder should be replaced with your real username and a real folder name.

    +
    +
    +
    +
    +
    Local Terminal
    +
    +
    scp script.sh username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/somefolder/.
    +
    + + +
    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/other/lab_mac_keyboard.html b/2311/topics/other/lab_mac_keyboard.html new file mode 100644 index 00000000..4f3d0376 --- /dev/null +++ b/2311/topics/other/lab_mac_keyboard.html @@ -0,0 +1,435 @@ + + + + + + + + + +Keyboard Guide + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Keyboard Guide

    +

    Key combinations for a Mac keyboard

    +
    +
    + + +
    + + + + +
    + + +
    + + + + +
    + + + + +

    Normal

    +
    +
    +

    +
    +
    +

    Holding shift

    +
    +
    +

    +
    +
    +

    Holding alt

    +
    +
    +

    +
    +
    +

    Holding alt+shift

    +
    +
    +

    +
    +
    + + + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/2311/topics/other/lab_open_session.html b/2311/topics/other/lab_open_session.html new file mode 100644 index 00000000..a01ba87b --- /dev/null +++ b/2311/topics/other/lab_open_session.html @@ -0,0 +1,462 @@ + + + + + + + + + +Open session + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Open session

    +
    +
    + + +
    + + + + +
    + + +
    + + + + +
    + + + + +
    +

    0.1 Friday at 13:15

    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RoomTopicStaff
    Room 1Whole genome sequencing, variant callingMalin Larsson, Diana Ekman
    Room 2RNA-Seq, scRNA-SeqJulie Lorent, Juliana Assis, Prasoon Agarwal, Roy Francis
    Room 3Bash, Uppmax, ComputingMartin Dahlö
    Room 4Epigenetics, Chip-Seq, RNA-Seq, scRNASeq, small RNAAgata Smialowska, Vincent van Hoef
    Room 5NGI, Assembly, Long read sequencingAdam Ameur, Estelle Proux
    Room 6Metagenomics, Prokaryots, RNA-SeqDag Ahrén, Lokesh Manoharan, John Sundh
    +
    +
    +
    + + +
    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/other/lab_qc.html b/2311/topics/other/lab_qc.html new file mode 100644 index 00000000..471ff8bc --- /dev/null +++ b/2311/topics/other/lab_qc.html @@ -0,0 +1,659 @@ + + + + + + + + + + + +Read quality + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Read quality

    +
    +
    + Quality control of short reads with FastQC +
    +
    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Malin Larsson

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +

    1 FastQC

    +

    FastQC performes a series of quality control analyses, called modules. The output is a HTML report with one section for each module, and a summary evaluation of the results in the top. Entirely normal results are marked with a green tick, slightly abnormal results raise warnings (orange exclamation mark), and very unusual results raise failures (red cross).

    +

    It is important to stress that although the analyses appear to give a pass/fail result, these evaluations must be taken in the context of what you expect from your library. A ‘normal’ sample as far as FastQC is concerned is random and diverse. Some experiments may be expected to produce libraries which are biased in particular ways. You should treat the summary evaluations therefore as pointers to where you should concentrate your attention and understand why your library may not look random and diverse.

    +
    +
    +

    2 Data

    +

    We will run FastQC on three low-coverage whole genome sequencing (WGS) samples from the public 1000 Genomes project. To speed up the analysis we will only use data from a small genomic region. These are the exact same samples as will be used in the variant-calling workflow lab on Wednesday.

    + + + + + + + + + + + + + + + + + + + + + +
    SampleDescription
    HG00097Low coverage WGS
    HG00100Low coverage WGS
    HG00101Low coverage WGS
    +
    +
    +

    3 Run FastQC

    +
    +

    3.1 Connect to Uppmax

    +

    During this lab it is best to connect to UPPMAX via a remote desktop (ThinLinc). Instructions for this is available in Canvas under Contents > Additional content > Connecting to UPPMAX. Please follow the instructions in section 1.2 Remote desktop connection.

    +
    +
    +

    3.2 Book a node

    +

    To be able to run analyses in the terminal you should book a compute node (or in this case just one core of a node). Make sure you only do this once each day because we have reserved one core per student for the course. If you haven’t already reserved a core today please use this command:

    +
    +
    +
    salloc -A naiss2023-22-862 -t 04:00:00 -p core -n 1 --no-shell &
    +
    +
    +

    Once your job allocation has been granted (should not take long) you can connect to the node using ssh. To find out the name of your node, use:

    +
    squeue -u username
    +

    The node name is found under nodelist header, you should only see one. Connect to that node:

    +
    ssh -Y <nodename>
    +
    +
    +

    3.3 Create a workspace

    +

    You should work in your folder under the course’s nobackup folder, just like you have done during the previous labs. Start by creating a workspace for this exercise in your folder, and then move into it.

    +
    +
    +
    mkdir /proj/naiss2023-22-862/nobackup/username/qc
    +cd /proj/naiss2023-22-862/nobackup/username/qc
    +
    +
    +
    + +
    +

    3.5 Accessing FastQC

    +

    FastQC is installed in the module system on UPPMAX. Modules must be loaded every time you login to Rackham, or when you connect to a new compute node.
    +First load the bioinfo-tools module:

    +
    module load bioinfo-tools
    +

    This makes it possible to load FastQC:

    +
    module load FastQC/0.11.8
    +
    +
    +

    3.6 Run FastQC

    +

    Run FastQC on all fastq files:

    +
    fastqc -q *.fq
    +

    The output is .html documents that shows quality scores along the reads, and other information. Please check what new files were generated with the command:

    +
    ls -lrt
    +
    +
    +
    +

    4 Check the results

    +

    The output from FastQC is a HTML report that should be opened in a web browser. When you have connected to Uppmax via ThinLinc you can open it on Rackham with this command:

    +
    firefox --no-remote filename.html &
    +

    We have made the output files that you just created available through the links below, so that you can look at them via your local web-browser:

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    SampleRead 1Read 2
    HG00097HG00097_1.fqHG00097_2.fq
    HG00100HG00100_1.fqHG00100_2.fq
    HG00101HG00101_1.fqHG00101_2.fq
    +
    +

    4.1 Per Base Sequence Quality

    +

    This module shows the distribution of the quality scores at each position in the reads. The quality scores are represented by a Box and Whisker plot with the following elements:

    +
      +
    • The central red line is the median value.
    • +
    • The yellow box represents the inter-quartile range (25-75%).
    • +
    • The upper and lower whiskers represent the 10% and 90% points
    • +
    • The blue line represents the mean quality
    • +
    +

    The background of the graph divides the y axis into very good quality calls (green), calls of reasonable quality (orange), and calls of poor quality (red).

    +
    +

    4.1.1 Questions

    +
      +
    1. Which positions in the reads have a median phred-score above 28 (very good quality calls) in each sample?
      +
    2. +
    3. Do any of the samples have warnings or failures in the Per Base Sequence Quality module?
    4. +
    5. Why? Please look in the documentation of this module.
    6. +
    +
    +
    +
    +

    4.2 Sequence Length Distribution

    +

    This module shows the length distribution of the reads in the file.

    +
    +

    4.2.1 Questions

    +
      +
    1. How long are the reads?
    2. +
    3. Do any of the samples have warnings or failures in the Sequence Length Distribution module?
    4. +
    5. Why? Please look in the documentation of this module
    6. +
    +
    +
    +
    +
    +

    5 Answers

    +

    When you have finished the exercise, please have a look at this document with answers to questions, and compare them with your answers.

    +
    +
    +

    6 Documentation

    + + + +
    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/other/lab_qc_answers.pdf b/2311/topics/other/lab_qc_answers.pdf new file mode 100644 index 00000000..1a2d8da2 Binary files /dev/null and b/2311/topics/other/lab_qc_answers.pdf differ diff --git a/2311/topics/other/lab_tetralith.html b/2311/topics/other/lab_tetralith.html new file mode 100644 index 00000000..915e14a1 --- /dev/null +++ b/2311/topics/other/lab_tetralith.html @@ -0,0 +1,591 @@ + + + + + + + + + + + +Working on Tetralith cluster + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Working on Tetralith cluster

    +

    Alternative cluster instructions

    +
    +
    + Guide to connecting and working on the backup cluster using Singularity image. +
    +
    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Malin Larsson

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +

    1 Connect to NSC via ThinLinc

    +

    The ThinLinc client can be downloaded for free from http://www.cendio.com/downloads/clients/. It is available for Windows, Mac OS X, Linux and Solaris.

    +

    To use ThinLinc to connect to Tetralith:

    +
      +
    1. If you haven’t already done so, download the ThinLinc client matching your local computer (i.e Windows, Linux, MacOS X or Solaris) and install it.
    2. +
    3. Start the client.
    4. +
    5. Change the “Server” setting to “tetralith.nsc.liu.se”.
    6. +
    7. Change the “Name” setting to your Tetralith username (e.g x_abcde).
    8. +
    9. You do not need to change any other settings.
    10. +
    11. Enter your cluster Tetralith password in the “Password” box.
    12. +
    13. Press the “Connect” button.
    14. +
    15. Enter the 6-digit code generated by the two-factor authentication app on your phone.
    16. +
    17. If you connect for the first time, you will see the “The server’s host key is not cached …” dialog. Verify that the fingerprint shown on your screen matches the one listed below! If it does not match, press Abort and then contact NSC Support!
    18. +
    +

    Tetralith SSH server host key fingerprint: 20:19:f4:6b:38:d6:e7:ac:e6:7c:8e:38:0a:7f:34:dc

    +

    After a few seconds, a window with a simple desktop session in it will appear. From the Applications menu, start a Terminal Window.

    +
    +
    +

    2 Interactive session

    +

    Start an interactive session with three compute cores for todays lab:

    +
    +
    +
    interactive -A naiss2023-22-862 -t 04:00:00 -n 3
    +
    +
    +

    Please adjust the requested time depending on what lab you will be working on. After a minute or so you should have gotten your interactive job.

    +
    +
    +
    + +
    +
    +Tip +
    +
    +
    +

    Note that your terminal prompt changed from <nsc_username>@tetralith$ to something like <nsc_username>@n424$ (or another node name), which means that you are now running on one of the compute nodes.

    +
    +
    +
    +
    +

    3 UPPMAX singularity container

    +

    We will use a singularity container (a virtual computer) that mimics the UPPMAX computing environment. Once you have started the singularity container your environment will look exactly as on UPPMAX, and the software used in this workshop will be available through the module system inside the container. Use this command to start the singularity container:

    +
    +
    +
    singularity shell -B /proj/naiss2023-22-862/users:/proj/naiss2023-22-862/nobackup -B /proj/naiss2023-22-862 /proj/naiss2023-22-862/ngsintro.sif
    +
    +
    +
    +
    +
    + +
    +
    +Tip +
    +
    +
    +

    Your terminal prompt changed to something like <nsc_username>@offline-uppmax$. This means that you have moved into a “virtual computer” that mimics the UPPMAX environment.

    +
    +
    +

    In the singularity container type this to make the module system behave properly:

    +
    +
    +
    source /uppmax_init
    +
    +
    +

    Everything from this point and onwards should be identical to running the exercise on UPPMAX. To close the singularity container later on just type exitin the terminal, but don’t do that now.

    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    Note: Since this is not actually running on uppmax, none of the queue system commands (squeue, sbatch, jobinfo etc) will work.

    +
    +
    +
    +
    +

    4 Cluster workspace

    +

    While running the UPPMAX singularity container, create a workspace for this exercise. This will be the “cluster workspace” in which you should perform the analyses, as if you would have worked on UPPMAX.

    +

    The name of the workspace depends on what lab you are working on. For example, if you are working on the introduction to Linux lab then call the workspace “linux_tutorial”. Once the workspace is created you should go into it.

    +
    +
    +
    mkdir /proj/naiss2023-22-862/nobackup/<nsc_username>/linux_tutorial
    +cd /proj/naiss2023-22-862/nobackup/<nsc_username>/linux_tutorial
    +
    +
    +

    When you have the UPPMAX singularity container up and running you can follow regular lab instructions, except that you should not connect to UPPMAX or book a node, and you should work in the cluster workspace defined here. Also, IGV is started with a special command,see below.

    +
    +
    +

    5 IGV

    +

    To start IGV at NSC type this in the command:

    +
    +
    +
    /proj/naiss2023-22-862/igv/igv.sh
    +
    +
    +

    You can use the same command both when running the UPPMAX singularity container and from a normal terminal window at NSC.

    +
    +
    +

    6 Exit the UPPMAX singularity container

    +

    When you are done with the lab just type exit to close the singularity container:

    +
    +
    +
    offline-uppmax$ exit
    +
    +
    +

    All files and folders that you create in /proj/naiss2023-22-862/nobackup/nsc_username/ while running the singularity container can be reached also from outside of the container, in this folder on Tetralith:

    +
    +
    +
    /proj/naiss2023-22-862/users/<nsc_username>/
    +
    +
    + + +
    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/other/slide_data_management.pdf b/2311/topics/other/slide_data_management.pdf new file mode 100644 index 00000000..170eda41 Binary files /dev/null and b/2311/topics/other/slide_data_management.pdf differ diff --git a/2311/topics/other/slide_introduction.pdf b/2311/topics/other/slide_introduction.pdf new file mode 100644 index 00000000..af881569 Binary files /dev/null and b/2311/topics/other/slide_introduction.pdf differ diff --git a/2311/topics/other/slide_nbis.pdf b/2311/topics/other/slide_nbis.pdf new file mode 100644 index 00000000..90c261c3 Binary files /dev/null and b/2311/topics/other/slide_nbis.pdf differ diff --git a/2311/topics/other/slide_ngs_pipelines.pdf b/2311/topics/other/slide_ngs_pipelines.pdf new file mode 100644 index 00000000..2fa50054 Binary files /dev/null and b/2311/topics/other/slide_ngs_pipelines.pdf differ diff --git a/2311/topics/other/slide_qc.pdf b/2311/topics/other/slide_qc.pdf new file mode 100644 index 00000000..4303565c Binary files /dev/null and b/2311/topics/other/slide_qc.pdf differ diff --git a/2311/topics/other/slide_sequencing.pdf b/2311/topics/other/slide_sequencing.pdf new file mode 100644 index 00000000..bfc62fa5 Binary files /dev/null and b/2311/topics/other/slide_sequencing.pdf differ diff --git a/2311/topics/rnaseq/assets/ac.jpg b/2311/topics/rnaseq/assets/ac.jpg new file mode 100644 index 00000000..8311506e Binary files /dev/null and b/2311/topics/rnaseq/assets/ac.jpg differ diff --git a/2311/topics/rnaseq/assets/accuracy.svg b/2311/topics/rnaseq/assets/accuracy.svg new file mode 100644 index 00000000..f603177e --- /dev/null +++ b/2311/topics/rnaseq/assets/accuracy.svg @@ -0,0 +1 @@ +accuracy \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/batch-effect.svg b/2311/topics/rnaseq/assets/batch-effect.svg new file mode 100644 index 00000000..4212d631 --- /dev/null +++ b/2311/topics/rnaseq/assets/batch-effect.svg @@ -0,0 +1 @@ +batch-effect \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/clipping_good.png b/2311/topics/rnaseq/assets/clipping_good.png new file mode 100644 index 00000000..0c136858 Binary files /dev/null and b/2311/topics/rnaseq/assets/clipping_good.png differ diff --git a/2311/topics/rnaseq/assets/compare-aligners-quality.jpg b/2311/topics/rnaseq/assets/compare-aligners-quality.jpg new file mode 100644 index 00000000..e4c62936 Binary files /dev/null and b/2311/topics/rnaseq/assets/compare-aligners-quality.jpg differ diff --git a/2311/topics/rnaseq/assets/compare-aligners-speed.png b/2311/topics/rnaseq/assets/compare-aligners-speed.png new file mode 100644 index 00000000..fb0a6f57 Binary files /dev/null and b/2311/topics/rnaseq/assets/compare-aligners-speed.png differ diff --git a/2311/topics/rnaseq/assets/correlation.png b/2311/topics/rnaseq/assets/correlation.png new file mode 100644 index 00000000..3b2c4ac5 Binary files /dev/null and b/2311/topics/rnaseq/assets/correlation.png differ diff --git a/2311/topics/rnaseq/assets/dge-clustering.png b/2311/topics/rnaseq/assets/dge-clustering.png new file mode 100644 index 00000000..449888bd Binary files /dev/null and b/2311/topics/rnaseq/assets/dge-clustering.png differ diff --git a/2311/topics/rnaseq/assets/dge-counts.png b/2311/topics/rnaseq/assets/dge-counts.png new file mode 100644 index 00000000..8b327246 Binary files /dev/null and b/2311/topics/rnaseq/assets/dge-counts.png differ diff --git a/2311/topics/rnaseq/assets/dge-dispersion.png b/2311/topics/rnaseq/assets/dge-dispersion.png new file mode 100644 index 00000000..ebc4d783 Binary files /dev/null and b/2311/topics/rnaseq/assets/dge-dispersion.png differ diff --git a/2311/topics/rnaseq/assets/dge-ma.png b/2311/topics/rnaseq/assets/dge-ma.png new file mode 100644 index 00000000..107cadc2 Binary files /dev/null and b/2311/topics/rnaseq/assets/dge-ma.png differ diff --git a/2311/topics/rnaseq/assets/dge-mds.png b/2311/topics/rnaseq/assets/dge-mds.png new file mode 100644 index 00000000..e5c4894a Binary files /dev/null and b/2311/topics/rnaseq/assets/dge-mds.png differ diff --git a/2311/topics/rnaseq/assets/dge-volcano.png b/2311/topics/rnaseq/assets/dge-volcano.png new file mode 100644 index 00000000..d80fefa2 Binary files /dev/null and b/2311/topics/rnaseq/assets/dge-volcano.png differ diff --git a/2311/topics/rnaseq/assets/dge.png b/2311/topics/rnaseq/assets/dge.png new file mode 100644 index 00000000..682c34fe Binary files /dev/null and b/2311/topics/rnaseq/assets/dge.png differ diff --git a/2311/topics/rnaseq/assets/distribution.jpg b/2311/topics/rnaseq/assets/distribution.jpg new file mode 100644 index 00000000..cc0f16f4 Binary files /dev/null and b/2311/topics/rnaseq/assets/distribution.jpg differ diff --git a/2311/topics/rnaseq/assets/end.png b/2311/topics/rnaseq/assets/end.png new file mode 100644 index 00000000..8e35da17 Binary files /dev/null and b/2311/topics/rnaseq/assets/end.png differ diff --git a/2311/topics/rnaseq/assets/fastqc_bad.png b/2311/topics/rnaseq/assets/fastqc_bad.png new file mode 100644 index 00000000..a86193ee Binary files /dev/null and b/2311/topics/rnaseq/assets/fastqc_bad.png differ diff --git a/2311/topics/rnaseq/assets/fastqc_good.png b/2311/topics/rnaseq/assets/fastqc_good.png new file mode 100644 index 00000000..32e51b14 Binary files /dev/null and b/2311/topics/rnaseq/assets/fastqc_good.png differ diff --git a/2311/topics/rnaseq/assets/gene-body-coverage.png b/2311/topics/rnaseq/assets/gene-body-coverage.png new file mode 100644 index 00000000..6913425b Binary files /dev/null and b/2311/topics/rnaseq/assets/gene-body-coverage.png differ diff --git a/2311/topics/rnaseq/assets/go.jpg b/2311/topics/rnaseq/assets/go.jpg new file mode 100644 index 00000000..07f1b653 Binary files /dev/null and b/2311/topics/rnaseq/assets/go.jpg differ diff --git a/2311/topics/rnaseq/assets/heatmap.png b/2311/topics/rnaseq/assets/heatmap.png new file mode 100644 index 00000000..5aec763f Binary files /dev/null and b/2311/topics/rnaseq/assets/heatmap.png differ diff --git a/2311/topics/rnaseq/assets/help.png b/2311/topics/rnaseq/assets/help.png new file mode 100644 index 00000000..7219e50a Binary files /dev/null and b/2311/topics/rnaseq/assets/help.png differ diff --git a/2311/topics/rnaseq/assets/igv-ankrd2.png b/2311/topics/rnaseq/assets/igv-ankrd2.png new file mode 100644 index 00000000..23b848b7 Binary files /dev/null and b/2311/topics/rnaseq/assets/igv-ankrd2.png differ diff --git a/2311/topics/rnaseq/assets/igv-scd1.png b/2311/topics/rnaseq/assets/igv-scd1.png new file mode 100644 index 00000000..2b05670a Binary files /dev/null and b/2311/topics/rnaseq/assets/igv-scd1.png differ diff --git a/2311/topics/rnaseq/assets/igv-tm7sf2.png b/2311/topics/rnaseq/assets/igv-tm7sf2.png new file mode 100644 index 00000000..65feb046 Binary files /dev/null and b/2311/topics/rnaseq/assets/igv-tm7sf2.png differ diff --git a/2311/topics/rnaseq/assets/igv.png b/2311/topics/rnaseq/assets/igv.png new file mode 100644 index 00000000..c85aa677 Binary files /dev/null and b/2311/topics/rnaseq/assets/igv.png differ diff --git a/2311/topics/rnaseq/assets/inner_distance.png b/2311/topics/rnaseq/assets/inner_distance.png new file mode 100644 index 00000000..d8cb45f1 Binary files /dev/null and b/2311/topics/rnaseq/assets/inner_distance.png differ diff --git a/2311/topics/rnaseq/assets/kegg.png b/2311/topics/rnaseq/assets/kegg.png new file mode 100644 index 00000000..c3be6dc2 Binary files /dev/null and b/2311/topics/rnaseq/assets/kegg.png differ diff --git a/2311/topics/rnaseq/assets/ma.png b/2311/topics/rnaseq/assets/ma.png new file mode 100644 index 00000000..2b61ab85 Binary files /dev/null and b/2311/topics/rnaseq/assets/ma.png differ diff --git a/2311/topics/rnaseq/assets/multiqc.png b/2311/topics/rnaseq/assets/multiqc.png new file mode 100644 index 00000000..0f0971dd Binary files /dev/null and b/2311/topics/rnaseq/assets/multiqc.png differ diff --git a/2311/topics/rnaseq/assets/normalisation.png b/2311/topics/rnaseq/assets/normalisation.png new file mode 100644 index 00000000..f0cb2382 Binary files /dev/null and b/2311/topics/rnaseq/assets/normalisation.png differ diff --git a/2311/topics/rnaseq/assets/pbsc.jpg b/2311/topics/rnaseq/assets/pbsc.jpg new file mode 100644 index 00000000..0e92c8aa Binary files /dev/null and b/2311/topics/rnaseq/assets/pbsc.jpg differ diff --git a/2311/topics/rnaseq/assets/pbsq.jpg b/2311/topics/rnaseq/assets/pbsq.jpg new file mode 100644 index 00000000..388488fe Binary files /dev/null and b/2311/topics/rnaseq/assets/pbsq.jpg differ diff --git a/2311/topics/rnaseq/assets/pca.png b/2311/topics/rnaseq/assets/pca.png new file mode 100644 index 00000000..761a779f Binary files /dev/null and b/2311/topics/rnaseq/assets/pca.png differ diff --git a/2311/topics/rnaseq/assets/pcr-duplicates.png b/2311/topics/rnaseq/assets/pcr-duplicates.png new file mode 100644 index 00000000..7dfc6bb2 Binary files /dev/null and b/2311/topics/rnaseq/assets/pcr-duplicates.png differ diff --git a/2311/topics/rnaseq/assets/psgc.jpg b/2311/topics/rnaseq/assets/psgc.jpg new file mode 100644 index 00000000..ffffb23d Binary files /dev/null and b/2311/topics/rnaseq/assets/psgc.jpg differ diff --git a/2311/topics/rnaseq/assets/psqs.jpg b/2311/topics/rnaseq/assets/psqs.jpg new file mode 100644 index 00000000..bff0a855 Binary files /dev/null and b/2311/topics/rnaseq/assets/psqs.jpg differ diff --git a/2311/topics/rnaseq/assets/pvca.png b/2311/topics/rnaseq/assets/pvca.png new file mode 100644 index 00000000..ad0fb8e9 Binary files /dev/null and b/2311/topics/rnaseq/assets/pvca.png differ diff --git a/2311/topics/rnaseq/assets/qc.jpg b/2311/topics/rnaseq/assets/qc.jpg new file mode 100644 index 00000000..a0852818 Binary files /dev/null and b/2311/topics/rnaseq/assets/qc.jpg differ diff --git a/2311/topics/rnaseq/assets/qcfail.jpg b/2311/topics/rnaseq/assets/qcfail.jpg new file mode 100644 index 00000000..92f37c51 Binary files /dev/null and b/2311/topics/rnaseq/assets/qcfail.jpg differ diff --git a/2311/topics/rnaseq/assets/qorts.png b/2311/topics/rnaseq/assets/qorts.png new file mode 100644 index 00000000..e739f3ff Binary files /dev/null and b/2311/topics/rnaseq/assets/qorts.png differ diff --git a/2311/topics/rnaseq/assets/qorts_alignments.svg b/2311/topics/rnaseq/assets/qorts_alignments.svg new file mode 100644 index 00000000..c234a726 --- /dev/null +++ b/2311/topics/rnaseq/assets/qorts_alignments.svg @@ -0,0 +1 @@ +Created with Highcharts 5.0.6PercentagesQoRTs: Alignment LocationsUnique Gene: CDSUnique Gene: UTRAmbig GeneNo Gene: IntronNo Gene: One Kb From GeneNo Gene: Ten Kb From GeneNo Gene: Middle Of NowhereCCC13-01B-qortsCCC13-02T-qortsCCC13-04B-qortsCCC13-05T-qortsCCC16-02B-qortsCCC16-03T-qortsCCC16-05B-qortsCCC19-01T-qortsCCC19-03B-qortsCCC19-04T-qortsCCC20-01B-qortsCCC20-02T-qortsCCC20-04B-qortsCCC20-05T-qortsLLL13-02B-qortsLLL13-03T-qortsLLL13-05B-qortsLLL16-01T-qortsLLL16-03B-qortsLLL16-04T-qortsLLL19-01B-qortsLLL19-02T-qortsLLL19-04B-qortsLLL19-05T-qortsLLL20-02B-qortsLLL20-03T-qortsLLL20-05B-qorts0102030405060708090100Created with MultiQC \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_counts.svg b/2311/topics/rnaseq/assets/rnaseq_counts.svg new file mode 100644 index 00000000..3b0727b5 --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_counts.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_library_prep.svg b/2311/topics/rnaseq/assets/rnaseq_library_prep.svg new file mode 100644 index 00000000..bc7978e0 --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_library_prep.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_mapping.svg b/2311/topics/rnaseq/assets/rnaseq_mapping.svg new file mode 100644 index 00000000..94a5854e --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_mapping.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_read_through.svg b/2311/topics/rnaseq/assets/rnaseq_read_through.svg new file mode 100644 index 00000000..b5e5ecb3 --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_read_through.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_read_type.svg b/2311/topics/rnaseq/assets/rnaseq_read_type.svg new file mode 100644 index 00000000..52f70ea3 --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_read_type.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_transcription.svg b/2311/topics/rnaseq/assets/rnaseq_transcription.svg new file mode 100644 index 00000000..8b3f474e --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_transcription.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_union.svg b/2311/topics/rnaseq/assets/rnaseq_union.svg new file mode 100644 index 00000000..aca0f026 --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_union.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_workflow.svg b/2311/topics/rnaseq/assets/rnaseq_workflow.svg new file mode 100644 index 00000000..77b250f0 --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_workflow.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseq_workflow_dge.svg b/2311/topics/rnaseq/assets/rnaseq_workflow_dge.svg new file mode 100644 index 00000000..02cc088b --- /dev/null +++ b/2311/topics/rnaseq/assets/rnaseq_workflow_dge.svg @@ -0,0 +1 @@ +rnaseq \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/rnaseqcomp.gif b/2311/topics/rnaseq/assets/rnaseqcomp.gif new file mode 100644 index 00000000..1f4960e0 Binary files /dev/null and b/2311/topics/rnaseq/assets/rnaseqcomp.gif differ diff --git a/2311/topics/rnaseq/assets/saturation.jpg b/2311/topics/rnaseq/assets/saturation.jpg new file mode 100644 index 00000000..eb6d97d8 Binary files /dev/null and b/2311/topics/rnaseq/assets/saturation.jpg differ diff --git a/2311/topics/rnaseq/assets/scattered.gif b/2311/topics/rnaseq/assets/scattered.gif new file mode 100644 index 00000000..c74456a5 Binary files /dev/null and b/2311/topics/rnaseq/assets/scattered.gif differ diff --git a/2311/topics/rnaseq/assets/sdl.jpg b/2311/topics/rnaseq/assets/sdl.jpg new file mode 100644 index 00000000..39b0d110 Binary files /dev/null and b/2311/topics/rnaseq/assets/sdl.jpg differ diff --git a/2311/topics/rnaseq/assets/seqmonk.jpg b/2311/topics/rnaseq/assets/seqmonk.jpg new file mode 100644 index 00000000..0c58231c Binary files /dev/null and b/2311/topics/rnaseq/assets/seqmonk.jpg differ diff --git a/2311/topics/rnaseq/assets/sequence.jpg b/2311/topics/rnaseq/assets/sequence.jpg new file mode 100644 index 00000000..962d9a4f Binary files /dev/null and b/2311/topics/rnaseq/assets/sequence.jpg differ diff --git a/2311/topics/rnaseq/assets/star_alignment_plot.svg b/2311/topics/rnaseq/assets/star_alignment_plot.svg new file mode 100644 index 00000000..2aae34d7 --- /dev/null +++ b/2311/topics/rnaseq/assets/star_alignment_plot.svg @@ -0,0 +1 @@ +Created with Highcharts 4.2.5PercentagesSTAR Alignment ScoresUniquely mappedMapped to multiple lociMapped to too many lociUnmapped: too shortUnmapped: otherCCC13-01BCCC13-02BCCC13-03BCCC13-04BCCC13-05BCCC16-01BCCC16-02BCCC16-03BCCC16-04BCCC16-05BCCC19-01BCCC19-02BCCC19-03BCCC19-04BCCC19-05BCCC20-01BCCC20-02BCCC20-03BCCC20-04BCCC20-05BLLL13-01BLLL13-02BLLL13-03BLLL13-04BLLL13-05BLLL16-01BLLL16-02BLLL16-03BLLL16-04BLLL16-05BLLL19-01BLLL19-02BLLL19-03BLLL19-04BLLL19-05BLLL20-01BLLL20-02BLLL20-03BLLL20-04BLLL20-05B05101520253035404550556065707580859095100Created with MultiQC \ No newline at end of file diff --git a/2311/topics/rnaseq/assets/systembio.png b/2311/topics/rnaseq/assets/systembio.png new file mode 100644 index 00000000..bd5fc5b4 Binary files /dev/null and b/2311/topics/rnaseq/assets/systembio.png differ diff --git a/2311/topics/rnaseq/assets/tview.png b/2311/topics/rnaseq/assets/tview.png new file mode 100644 index 00000000..4aae29b8 Binary files /dev/null and b/2311/topics/rnaseq/assets/tview.png differ diff --git a/2311/topics/rnaseq/assets/volcano.png b/2311/topics/rnaseq/assets/volcano.png new file mode 100644 index 00000000..f70db0ae Binary files /dev/null and b/2311/topics/rnaseq/assets/volcano.png differ diff --git a/2311/topics/rnaseq/lab_rnaseq.html b/2311/topics/rnaseq/lab_rnaseq.html new file mode 100644 index 00000000..4ba2b2cb --- /dev/null +++ b/2311/topics/rnaseq/lab_rnaseq.html @@ -0,0 +1,1916 @@ + + + + + + + + + + + +RNASeq Workflow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    RNASeq Workflow

    +
    +
    + Analysis of bulk RNA-Seq data to determine genome-wide gene expression +
    +
    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Roy Francis / Dag Ahrén

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +

    1 Introduction

    +

    RNA-seq has become a powerful approach to study the continually changing cellular transcriptome. Here, one of the most common questions is to identify genes that are differentially expressed between two conditions, e.g. controls and treatment. The main exercise in this tutorial will take you through a basic bioinformatic analysis pipeline to answer just that, it will show you how to find differentially expressed (DE) genes.

    +

    Main exercise

    +
      +
    • 01 Check the quality of the raw reads with FastQC
    • +
    • 02 Map the reads to the reference genome using HISAT2
    • +
    • 03 Assess the post-alignment quality using QualiMap
    • +
    • 04 Count the reads overlapping with genes using featureCounts
    • +
    • 05 Find DE genes using DESeq2 in R
    • +
    +

    RNA-seq experiment does not necessarily end with a list of DE genes. If you have time after completing the main exercise, try one (or more) of the bonus exercises. The bonus exercises can be run independently of each other, so choose the one that matches your interest. Bonus sections are listed below.

    +

    Bonus exercises

    +
      +
    • 01 Functional annotation of DE genes using GO/Reactome databases
    • +
    • 02 RNA-Seq figures and plots using R
    • +
    • 03 Visualisation of RNA-seq BAM files using IGV genome browser
    • +
    +
    +
    +
    + +
    +
    +General guide +
    +
    +
    +
      +
    • In paths, remember to change username with your actual UPPMAX username.

    • +
    • You are welcome to try your own solutions to the problems, before checking the solution. Click the button to see the suggested solution. There is more than one way to complete a task. Discuss with person next to you and ask us when in doubt.

    • +
    • Input code blocks are displayed like shown below.

    • +
    +
    +
    command
    +
    +
    +
    +
    +
    +

    2 Data description

    +

    The data used in this exercise is from the paper: Poitelon, Yannick, et al. YAP and TAZ control peripheral myelination and the expression of laminin receptors in Schwann cells. Nature neuroscience 19.7 (2016): 879. In this study, YAP and TAZ genes were knocked-down in Schwann cells to study myelination, using the sciatic nerve in mice as a model.

    +

    Myelination is essential for nervous system function. Schwann cells interact with neurons and the basal lamina to myelinate axons using receptors, signals and transcription factors. Hippo pathway is a conserved pathway involved in cell contact inhibition, and it acts to promote cell proliferation and inhibits apoptosis. The pathway integrates mechanical signals (cell polarity, mechanotransduction, membrane tension) and gene expression response. In addition to its role in organ size control, the Hippo pathway has been implicated in tumorigenesis, for example its deregulation occurs in a broad range of human carcinomas. Transcription co-activators YAP and TAZ are two major downstream effectors of the Hippo pathway, and have redundant roles in transcriptional activation.

    +

    The material for RNA-seq was collected from 2 conditions (Wt and KO), each with 3 biological replicates.

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AccessionConditionReplicate
    SRR3222409KO1
    SRR3222410KO2
    SRR3222411KO3
    SRR3222412Wt1
    SRR3222413Wt2
    SRR3222414Wt3
    +
    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    For the purpose of this tutorial, to shorten the time needed to run various bioinformatics steps, we have picked reads for a single chromosome (Chr 19) and downsampled the reads. We randomly sampled, without replacement, 25% reads from each sample, using fastq-sample from the toolset fastq-tools.

    +
    +
    +
    +
    +

    3 Main exercise

    +

    The main exercise covers Differential Gene Expression (DGE) workflow from raw reads to a list of differentially expressed genes.

    +
    +

    3.1 Using Uppmax

    +
    +
    +
    + +
    +
    +Use ThinLinc +
    +
    +
    +

    If you have issues opening GUI windows from UPPMAX through the terminal, it is recommended to use ThinLinc.

    +
    +
    +

    If you are not on ThinLinc, connect to UPPMAX first. Remember to replace username.

    +
    +
    ssh -Y username@rackham.uppmax.uu.se
    +
    +

    Book a node.

    +

    For the RNA-Seq part of the course, we will work on the Rackham cluster. A standard compute node on cluster Rackham has 128 GB of RAM and 20 cores. We will use 1 core per person for this session. Therefore, each core gives you 6.4 GB of RAM. The code below is valid to run at the start of the day. If you are running it in the middle of a day, you need to decrease the time (-t). Do not run this twice and also make sure you are not running computations on a login node.

    +

    Book compute resources for RNA-Seq lab.

    +
    +
    +
    salloc -A naiss2023-22-862 -t 03:00:00 -p core -n 1 --no-shell
    +
    +
    +

    Check allocation. Remember to replace username.

    +
    squeue -u username
    +

    Once allocation is granted, log on to the compute node. Remember to replace nodename.

    +
    ssh -Y nodename
    +
    +

    3.1.1 Set-up directory

    +

    Setting up the directory structure is an important step as it helps to keep our raw data, intermediate data and results in an organised manner. All work must be carried out at this location /proj/naiss2023-22-862/nobackup/username/ where username is your user name.

    +

    Create a directory named rnaseq. All RNA-Seq related activities must be carried out in this sub-directory named rnaseq.

    +
    +
    mkdir rnaseq
    +
    +

    Create the directory structure as shown below.

    +
    username/
    +rnaseq/
    +  +-- 1_raw/
    +  +-- 2_fastqc/
    +  +-- 3_mapping/
    +  +-- 4_qualimap/
    +  +-- 5_dge/
    +  +-- 6_multiqc/
    +  +-- reference/
    +  |   +-- mouse_chr19_hisat2/
    +  +-- scripts/
    +  +-- funannot/
    +  +-- plots
    +
    +
    +
    cd rnaseq
    +mkdir 1_raw 2_fastqc 3_mapping 4_qualimap 5_dge 6_multiqc reference scripts funannot plots
    +cd reference
    +mkdir mouse_chr19_hisat2
    +cd ..
    +
    +
    +

    The 1_raw directory will hold the raw fastq files (soft-links). 2_fastqc will hold FastQC outputs. 3_mapping will hold the mapping output files. 4_qualimap will hold the QualiMap output files. 5_dge will hold the counts from featureCounts and all differential gene expression related files. 6_multiqc will hold MultiQC outputs. reference directory will hold the reference genome, annotations and aligner indices. The funannot and plots directory are optional for bonus steps.

    +

    It might be a good idea to open an additional terminal window. One to navigate through directories and another for scripting in the scripts directory.

    +
    + +
    +
    +

    3.2 FastQC

    +

    Quality check using FastQC

    +

    After receiving raw reads from a high throughput sequencing centre it is essential to check their quality. FastQC provides a simple way to do some quality control check on raw sequence data. It provides a modular set of analyses which you can use to get a quick impression of whether your data has any problems of which you should be aware before doing any further analysis.

    +

    Change into the 2_fastqc directory. Use pwd to check if you are standing in the correct directory.

    +
    +
    +
    cd ../2_fastqc
    +pwd
    +
    +
    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/rnaseq/2_fastqc
    +
    +
    +

    Load Uppmax modules bioinfo-tools and FastQC FastQC/0.11.9.

    +
    +
    module load bioinfo-tools
    +module load FastQC/0.11.9
    +
    +

    Once the module is loaded, FastQC program is available through the command fastqc. Use fastqc --help to see the various parameters available to the program. We will use -o to specify the output directory path and finally, the name of the input fastq file to analyse. The syntax to run one file will look like below.

    +

    Don’t run this. It’s just a template.

    +
    +
    fastqc -o . ../1_raw/filename.fq.gz
    +
    +

    Based on the above command, we will write a bash loop script to process all fastq files in the directory. Writing multi-line commands through the terminal can be a pain. Therefore, we will run larger scripts from a bash script file. Move to your scripts directory and create a new file named fastqc.sh.

    +
    +
    +
    cd ../scripts
    +pwd
    +
    +
    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/rnaseq/scripts
    +
    +
    +

    The command below creates a new file in the current directory.

    +
    +
    touch fastqc.sh
    +
    +

    Use a text editor (nano,Emacs,gedit etc.) to edit fastqc.sh.

    +

    gedit behaves like a regular text editor with a standard graphical interface.

    +
    +
    gedit fastqc.sh &
    +
    +

    Adding & at the end sends that process to the background, so that the console is free to accept new commands.

    +

    Then add the lines below and save the file.

    +
    +
    #!/bin/bash
    +
    +module load bioinfo-tools
    +module load FastQC/0.11.9
    +
    +for i in ../1_raw/*.gz
    +do
    +    echo "Running $i ..."
    +    fastqc -o . "$i"
    +done
    +
    +

    This script loops through all files ending in .gz. In each iteration of the loop, it executes fastqc on the file. The -o . flag to fastqc indicates that the output must be exported in this current directory (ie; the directory where this script is run).

    +

    Change to the 2_fastqc directory. Use pwd to check if you are standing in the correct directory. Run the script file fastqc.sh

    +
    +
    +
    cd ../2_fastqc
    +pwd
    +
    +
    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/rnaseq/2_fastqc
    +
    +
    +
    +
    bash ../scripts/fastqc.sh
    +
    +

    After the fastqc run, there should be a .zip file and a .html file for every fastq file. The .html file is the report that you need. Download the .html files to your computer and open them in a web browser. You do not need to necessarily look at all files now. We will do a comparison with all samples when using the MultiQC tool.

    +

    Run this step in a LOCAL terminal and NOT on Uppmax. Open a terminal locally on your computer, move to a suitable download directory and run the command below to download one html report.

    +

    Remember to replace username (twice).

    +
    +
    +
    scp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/2_fastqc/SRR3222409-19_1_fastqc.html .
    +
    +
    +

    or download the whole directory.

    +
    +
    +
    scp -r username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/2_fastqc .
    +
    +
    +
    +
    +
    + +
    +
    +Downloading using a GUI +
    +
    +
    +

    You can optionally use an SFTP browser like Filezilla or Cyberduck for a GUI interface. Those using MobaXterm, it has an embedded SFTP file browser to drag and drop.

    +
    +
    +

    Go back to the FastQC website and compare your report with the sample report for Good Illumina data and Bad Illumina data.

    +

    Discuss based on your reports, whether your data is of good enough quality and/or what steps are needed to fix it.

    +
    +
    +

    3.3 HISAT2

    +

    Mapping reads using HISAT2

    +

    After verifying that the quality of the raw sequencing reads is acceptable, we will map the reads to the reference genome. There are many mappers/aligners available, so it may be good to choose one that is adequate for your type of data. Here, we will use a software called HISAT2 (Hierarchical Indexing for Spliced Alignment of Transcripts) as it is a good general purpose splice-aware aligner. It is fast and does not require a lot of RAM. Before we begin mapping, we need to obtain genome reference sequence (.fasta file) and build an aligner index. Due to time constraints, we will build an index only on chromosome 19.

    +
    +

    3.3.1 Get reference

    +

    It is best if the reference genome (.fasta) and annotation (.gtf) files come from the same source to avoid potential naming conventions problems. It is also good to check in the manual of the aligner you use for hints on what type of files are needed to do the mapping. We will not be using the annotation (.gtf) during mapping, but we will use it during quantification.

    +

    What is the idea behind building an aligner index? What files are needed to build one? Where do we take them from? Could one use an index that was generated for another project? Check out the HISAT2 manual indexer section for answers. Browse through Ensembl and try to find the files needed. Note that we are working with Mouse (Mus musculus).

    +

    Move into the reference directory and download the Chr 19 genome (.fasta) file and the genome-wide annotation file (.gtf) from Ensembl.

    +

    You should be standing here to run this:

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/rnaseq/reference
    +
    +
    +

    You are most likely to use the latest version of ensembl release genome and annotations when starting a new analysis. For this exercise, we will choose ensembl version 99.

    +
    +
    wget ftp://ftp.ensembl.org/pub/release-99/fasta/mus_musculus/dna/Mus_musculus.GRCm38.dna.chromosome.19.fa.gz
    +wget ftp://ftp.ensembl.org/pub/release-99/gtf/mus_musculus/Mus_musculus.GRCm38.99.gtf.gz
    +
    +

    Decompress the files for use.

    +
    +
    gunzip Mus_musculus.GRCm38.dna.chromosome.19.fa.gz
    +gunzip Mus_musculus.GRCm38.99.gtf.gz
    +
    +

    From the full gtf file, we will also extract chr 19 alone to create a new gtf file for use later.

    +
    +
    cat Mus_musculus.GRCm38.99.gtf | grep -E "^#|^19" > Mus_musculus.GRCm38.99-19.gtf
    +
    +

    The grep command is set to use regular expression with the -E argument. And it’s looking for lines starting with # or 19. # fetches the header and comments while 19 denotes all rows with annotations for chromosome 19.

    +

    Check what you have in your directory.

    +
    +
    ls -l
    +
    +
    +
    drwxrwsr-x 2 user gXXXXXXX 4.0K Jan 22 21:59 mouse_chr19_hisat2
    +-rw-rw-r-- 1 user gXXXXXXX  26M Jan 22 22:46 Mus_musculus.GRCm38.99-19.gtf
    +-rw-rw-r-- 1 user gXXXXXXX 771M Jan 22 22:10 Mus_musculus.GRCm38.99.gtf
    +-rw-rw-r-- 1 user gXXXXXXX  60M Jan 22 22:10 Mus_musculus.GRCm38.dna.chromosome.19.fa
    +
    +
    +
    +

    3.3.2 Build index

    +

    Move into the reference directory if not already there. Load module HISAT2. Remember to load bioinfo-tools if you haven’t done so already.

    +
    +
    module load bioinfo-tools
    +module load HISAT2/2.1.0
    +
    +

    To search for the tool or other versions of a tool, use module spider hisat.

    +

    Create a new bash script in your scripts directory named hisat2_index.sh and add the following lines:

    +
    +
    #!/bin/bash
    +
    +# load module
    +module load bioinfo-tools
    +module load HISAT2/2.1.0
    +
    +hisat2-build \
    +  -p 1 \
    +  Mus_musculus.GRCm38.dna.chromosome.19.fa \
    +  mouse_chr19_hisat2/mouse_chr19_hisat2
    +
    +

    The above script builds a HISAT2 index using the command hisat2-build. It should use 1 core for computation. The paths to the FASTA (.fa) genome file is specified. And the output path is specified. The output describes the output directory and the prefix for output files. The output directory must be present before running this script. Check hisat2-build --help for the arguments and descriptions.

    +

    Use pwd to check if you are standing in the correct directory. Then, run the script from the reference directory.

    +
    +
    bash ../scripts/hisat2_index.sh
    +
    +

    Once the indexing is complete, move into the mouse_chr19_hisat2 directory and make sure you have all the files.

    +
    +
    ls -l mouse_chr19_hisat2/
    +
    +
    +
    -rw-rw-r-- 1 user gXXXXXXX 23M Sep 19 12:30 mouse_chr19_hisat2.1.ht2
    +-rw-rw-r-- 1 user gXXXXXXX 14M Sep 19 12:30 mouse_chr19_hisat2.2.ht2
    +-rw-rw-r-- 1 user gXXXXXXX  53 Sep 19 12:29 mouse_chr19_hisat2.3.ht2
    +-rw-rw-r-- 1 user gXXXXXXX 14M Sep 19 12:29 mouse_chr19_hisat2.4.ht2
    +-rw-rw-r-- 1 user gXXXXXXX 25M Sep 19 12:30 mouse_chr19_hisat2.5.ht2
    +-rw-rw-r-- 1 user gXXXXXXX 15M Sep 19 12:30 mouse_chr19_hisat2.6.ht2
    +-rw-rw-r-- 1 user gXXXXXXX  12 Sep 19 12:29 mouse_chr19_hisat2.7.ht2
    +-rw-rw-r-- 1 user gXXXXXXX   8 Sep 19 12:29 mouse_chr19_hisat2.8.ht2
    +
    +

    The index for the whole genome would be created in a similar manner. It just requires more time to run.

    +
    +
    +

    3.3.3 Map reads

    +

    Now that we have the index ready, we are ready to map reads. Move to the directory 3_mapping. Use pwd to check if you are standing in the correct directory.

    +

    You should be standing here to run this:

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping
    +
    +
    +

    We will create softlinks to the fastq files from here to make things easier.

    +
    +
    cd 3_mapping
    +ln -s ../1_raw/* .
    +
    +

    These are the parameters that we want to specify for the mapping run:

    +
      +
    • Specify the number of threads
    • +
    • Specify the full genome index path
    • +
    • Specify a summary file
    • +
    • Indicate read1 and read2 since we have paired-end reads
    • +
    • Direct the output (SAM) to a file
    • +
    +

    HISAT2 aligner arguments can be obtained by running hisat2 --help. We should end with a script that looks like below to run one of the samples.

    +
    +
    hisat2 \
    +  -p 1 \
    +  -x ../reference/mouse_chr19_hisat2/mouse_chr19_hisat2 \
    +  --summary-file "SRR3222409-19.summary" \
    +  -1 SRR3222409-19_1.fq.gz \
    +  -2 SRR3222409-19_2.fq.gz \
    +  -S SRR3222409-19.sam
    +
    +

    Let’s break this down a bit. -p options denotes that it will use 1 thread. In a real world scenario, we might want to use 8 to 12 threads. -x denotes the full path (with prefix) to the aligner index we built in the previous step. --summary-file specifies a summary file to write alignments metrics such as mapping rate etc. -1 and -2 specifies the input fastq files. Both are used here because this is a paired-end sequencing. -S denotes the output SAM file.

    +

    But, we will not run it as above. We will make some more changes to it. We want to make the following changes:

    +
      +
    • Rather than writing the output as a SAM file, we want to direct the output to another tool samtools to order alignments by coordinate and to export in BAM format
    • +
    • Generalise the above script to be used as a bash script to read any two input files and to automatically create the output filename.
    • +
    +

    Now create a new bash script file named hisat2_align.sh in your scripts directory and add the script below to it.

    +
    +
    #!/bin/bash
    +
    +module load bioinfo-tools
    +module load HISAT2/2.1.0
    +module load samtools/1.8
    +
    +# get output filename prefix
    +prefix=$( basename $1 | sed -E 's/_.+$//' )
    +
    +hisat2 \
    +  -p 1 \
    +  -x ../reference/mouse_chr19_hisat2/mouse_chr19_hisat2 \
    +  --summary-file "${prefix}.summary" \
    +  -1 $1 \
    +  -2 $2 | samtools sort -O BAM > "${prefix}.bam"
    +
    +

    In the above script, the two input fasta files are not hard coded, rather we use $1 and $2 because they will be passed in as arguments.

    +

    The output filename prefix is automatically created using this line prefix=$( basename $1 | sed -E 's/_.+$//' ) from input filename of $1. For example, a file with path /bla/bla/sample_1.fq.gz will have the directory stripped off using the function basename to get sample_1.fq.gz. This is piped (|) to sed where all text starting from _ to end of string (specified by this regular expression _.+$ matching _1.fq.gz) is removed and the prefix will be just sample. This approach will work only if your filenames are labelled suitably.

    +

    Lastly, the SAM output is piped (|) to the tool samtools for sorting and written in BAM format.

    +

    Now we can run the bash script like below while standing in the 3_mapping directory.

    +
    +
    bash ../scripts/hisat2_align.sh sample_1.fq.gz sample_2.fq.gz
    +
    +

    Similarly run the other samples.

    +
    +
    +
    + +
    +
    +Optional +
    +
    +
    +

    Try to create a new bash loop script (hisat2_align_batch.sh) to iterate over all fastq files in the directory and run the mapping using the hisat2_align.sh script. Note that there is a bit of a tricky issue here. You need to use two fastq files (_1 and _2) per run rather than one file. There are many ways to do this and here is one.

    +
    +
    ## find only files for read 1 and extract the sample name
    +lines=$(find *_1.fq.gz | sed "s/_1.fq.gz//")
    +
    +for i in ${lines}
    +do
    +  ## use the sample name and add suffix (_1.fq.gz or _2.fq.gz)
    +  echo "Mapping ${i}_1.fq.gz and ${i}_2.fq.gz ..."
    +  bash ../scripts/hisat2_align.sh ${i}_1.fq.gz ${i}_2.fq.gz
    +done
    +
    +

    Run the hisat2_align_batch.sh script in the 3_mapping directory.

    +
    +
    bash ../scripts/hisat2_align_batch.sh
    +
    +
    +
    +

    At the end of the mapping jobs, you should have the following list of output files for every sample:

    +
    +
    ls -l
    +
    +
    +
    -rw-rw-r-- 1 user gXXXXXXX 16M Sep 19 12:30 SRR3222409-19.bam
    +-rw-rw-r-- 1 user gXXXXXXX 604 Sep 19 12:30 SRR3222409-19.summary
    +
    +

    The .bam file contains the alignment of all reads to the reference genome in binary format. BAM files are not human readable directly. To view a BAM file in text format, you can use samtools view functionality.

    +
    +
    module load samtools/1.8
    +samtools view SRR3222409-19.bam | head
    +
    +
    +
    SRR3222409.13658290 163 19  3084385 60  95M3S   =   3084404 120 CTTTAAGATAAGTGCCGGTTGCAGCCAGCTGTGAGAGCTGCACTCCCTTCTCTGCTCTAAAGTTCCCTCTTCTCAGAAGGTGGCACCACCCTGAGCTG  DB@D@GCHHHEFHIIG<CHHHIHHIIIIHHHIIIIGHIIIIIFHIGHIHIHIIHIIHIHIIHHHHIIIIIIHFFHHIIIGCCCHHHH1GHHIIHHIII  AS:i:-3 ZS:i:-18    XN:i:0  XM:i:0  XO:i:0  XG:i:0  NM:i:0  MD:Z:95 YS:i:-6 YT:Z:CP NH:i:1
    +SRR3222409.13658290 83  19  3084404 60  101M    =   3084385 -120    TGCAGCCAGCTGTGAGAGCTGCACTCCCTTCTCTGCTCTAAAGTTCCCTCTTCTCAGAAGGTGGCACCACCCTGAGCTGCTGGCAGTGAGTCTGTTCCAAG   IIIIHECHHH?IHHHIIIHIHIIIHEHHHCHHHIHIIIHHIHIIIHHHHHHIHEHIIHIIHHIIHHIHHIGHIGIIIIIIIHHIIIHHIHEHCHHG@<<BD   AS:i:-6 ZS:i:-16    XN:i:0  XM:i:1  XO:i:0  XG:i:0  NM:i:1  MD:Z:76T24  YS:i:-3 YT:Z:CP NH:i:1
    +SRR3222409.13741570 163 19  3085066 60  15M2I84M    =   3085166 201 ATAGTACCTGGCAACAAAAAAAAAAAAGCTTTTGGCTAAAGACCAATGTGTTTAAGAGATAAAAAAAGGGGTGCTAATACAGAAGCTGAGGCCTTAGAAGA   0B@DB@HCCH1<<CGECCCGCHHIDD?01<<G1</<1<FH1F11<1111<<<<11<CGC1<G1<F//DHHI0/01<<1FG11111111<111<1D1<1D1<   AS:i:-20    XN:i:0  XM:i:3  XO:i:1  XG:i:2  NM:i:5  MD:Z:40T19C27T10    YS:i:0  YT:Z:CP NH:i:1
    +
    +

    Can you identify what some of these columns are? SAM format description is available here. SAM output specifically from HISAT is described here, especially the tags.

    +

    The summary file gives a summary of the mapping run. This file is used by MultiQC later to collect mapping statistics. Inspect one of the mapping log files to identify the number of uniquely mapped reads and multi-mapped reads.

    +
    +
    cat SRR3222409-19.summary
    +
    +
    +
    156992 reads; of these:
    +  156992 (100.00%) were paired; of these:
    +    7984 (5.09%) aligned concordantly 0 times
    +    147178 (93.75%) aligned concordantly exactly 1 time
    +    1830 (1.17%) aligned concordantly >1 times
    +    ----
    +    7984 pairs aligned concordantly 0 times; of these:
    +      690 (8.64%) aligned discordantly 1 time
    +    ----
    +    7294 pairs aligned 0 times concordantly or discordantly; of these:
    +      14588 mates make up the pairs; of these:
    +        5987 (41.04%) aligned 0 times
    +        4085 (28.00%) aligned exactly 1 time
    +        4516 (30.96%) aligned >1 times
    +98.09% overall alignment rate
    +
    +

    Next, we need to index these BAM files. Indexing creates .bam.bai files which are required by many downstream programs to quickly and efficiently locate reads anywhere in the BAM file.

    +

    Index all BAM files. Write a for-loop to index all BAM files using the command samtools index file.bam.

    +
    +
    module load samtools/1.8
    +
    +for i in *.bam
    +  do
    +    echo "Indexing $i ..."
    +    samtools index $i
    +  done
    +
    +

    Now, we should have .bai index files for all BAM files.

    +
    +
    ls -l
    +
    +
    +
    -rw-rw-r-- 1 user gXXXXXXX 16M Sep 19 12:30 SRR3222409-19.bam
    +-rw-rw-r-- 1 user gXXXXXXX 43K Sep 19 12:32 SRR3222409-19.bam.bai
    +
    +

    If you are running short of time or unable to run the mapping, you can copy over results for all samples that have been prepared for you before class. They are available at this location: /sw/courses/ngsintro/rnaseq/main/3_mapping/.

    +
    +
    +
    cp -r /sw/courses/ngsintro/rnaseq/main/3_mapping/* /proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/
    +
    +
    +


    +
    +
    +
    +

    3.4 QualiMap

    +

    Post-alignment QC using QualiMap

    +

    Some important quality aspects, such as saturation of sequencing depth, read distribution between different genomic features or coverage uniformity along transcripts, can be measured only after mapping reads to the reference genome. One of the tools to perform this post-alignment quality control is QualiMap. QualiMap examines sequencing alignment data in SAM/BAM files according to the features of the mapped reads and provides an overall view of the data that helps to the detect biases in the sequencing and/or mapping of the data and eases decision-making for further analysis.

    +

    There are other tools with similar functionality such as RNASeqQC or QoRTs.

    +

    Read through QualiMap documentation and see if you can figure it out how to run it to assess post-alignment quality on the RNA-seq mapped samples.

    +

    Load the QualiMap module version 2.2.1 and create a bash script named qualimap.sh in your scripts directory.

    +

    Add the following script to it. Note that we are using the smaller GTF file with chr19 only.

    +
    +
    #!/bin/bash
    +
    +# load modules
    +module load bioinfo-tools
    +module load QualiMap/2.2.1
    +
    +# get output filename prefix
    +prefix=$( basename "$1" .bam)
    +
    +unset DISPLAY
    +
    +qualimap rnaseq -pe \
    +  -bam $1 \
    +  -gtf "../reference/Mus_musculus.GRCm38.99-19.gtf" \
    +  -outdir "../4_qualimap/${prefix}/" \
    +  -outfile "$prefix" \
    +  -outformat "HTML" \
    +  --java-mem-size=6G >& "${prefix}-qualimap.log"
    +
    +

    The line prefix=$( basename "$1" .bam) is used to remove directory path and .bam from the input filename and create a prefix which will be used to label output. The export unset DISPLAY forces a ‘headless mode’ on the JAVA application, which would otherwise throw an error about X11 display. If that doesn’t work, one can also try export DISPLAY=:0 or export DISPLAY="". The last part >& "${prefix}-qualimap.log" saves the standard-out as a log file.

    +

    Create a new bash loop script named qualimap_batch.sh with a bash loop to run the qualimap script over all BAM files. The loop should look like below.

    +
    +
    for i in ../3_mapping/*.bam
    +do
    +    echo "Running QualiMap on $i ..."
    +    bash ../scripts/qualimap.sh $i
    +done
    +
    +

    Run the loop script qualimap_batch.sh in the directory 4_qualimap.

    +
    +
    bash ../scripts/qualimap_batch.sh
    +
    +

    Qualimap should have created a directory for every BAM file.

    +
    +
    drwxrwsr-x 5 user gXXXXXXX 4.0K Jan 22 22:53 SRR3222409-19
    +-rw-rw-r-- 1 user gXXXXXXX  669 Jan 22 22:53 SRR3222409-19-qualimap.log
    +
    +

    Inside every directory, you should see:

    +
    +
    ls -l
    +
    +
    +
    drwxrwsr-x 2 user gXXXXXXX 4.0K Jan 22 22:53 css
    +drwxrwsr-x 2 user gXXXXXXX 4.0K Jan 22 22:53 images_qualimapReport
    +-rw-rw-r-- 1 user gXXXXXXX  12K Jan 22 22:53 qualimapReport.html
    +drwxrwsr-x 2 user gXXXXXXX 4.0K Jan 22 22:53 raw_data_qualimapReport
    +-rw-rw-r-- 1 user gXXXXXXX 1.2K Jan 22 22:53 rnaseq_qc_results.txt
    +
    +

    Download the results.

    +

    When downloading the HTML files, note that you MUST also download the dependency files (ie; css folder and images_qualimapReport folder), otherwise the HTML file may not render correctly. Remember to replace username (twice).

    +
    +
    +
    scp -r username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/4_qualimap .
    +
    +
    +

    Check the QualiMap report for one sample and discuss if the sample is of good quality. You only need to do this for one file now. We will do a comparison with all samples when using the MultiQC tool.

    +

    If you are running out of time or were unable to run QualiMap, you can also copy pre-run QualiMap output from this location: /sw/courses/ngsintro/rnaseq/main/4_qualimap/.

    +
    +
    +
    cp -r /sw/courses/ngsintro/rnaseq/main/4_qualimap/* /proj/naiss2023-22-862/nobackup/username/rnaseq/4_qualimap/
    +
    +
    +


    +
    +
    +

    3.5 featureCounts

    +

    Counting mapped reads using featureCounts

    +

    After ensuring mapping quality, we can move on to enumerating reads mapping to genomic features of interest. Here we will use featureCounts, an ultrafast and accurate read summarisation program, that can count mapped reads for genomic features such as genes, exons, promoter, gene bodies, genomic bins and chromosomal locations.

    +

    Read featureCounts documentation and see if you can figure it out how to use paired-end reads using an unstranded library to count fragments overlapping with exonic regions and summarise over genes.

    +

    Load the subread module on Uppmax. Create a bash script named featurecounts.sh in the directory scripts.

    +

    We could run featureCounts on each BAM file, produce a text output for each sample and combine the output. But the easier way is to provide a list of all BAM files and featureCounts will combine counts for all samples into one text file.

    +

    Below is the script that we will use:

    +
    +
    #!/bin/bash
    +
    +# load modules
    +module load bioinfo-tools
    +module load subread/2.0.0
    +
    +featureCounts \
    +  -a "../reference/Mus_musculus.GRCm38.99.gtf" \
    +  -o "counts.txt" \
    +  -F "GTF" \
    +  -t "exon" \
    +  -g "gene_id" \
    +  -p \
    +  -s 0 \
    +  -T 1 \
    +  ../3_mapping/*.bam
    +
    +

    In the above script, we indicate the path of the annotation file (-a "../reference/Mus_musculus.GRCm38.99.gtf"), specify the output file name (-o "counts.txt"), specify that that annotation file is in GTF format (-F "GTF"), specify that reads are to be counted over exonic features (-t "exon") and summarised to the gene level (-g "gene_id"). We also specify that the reads are paired-end (-p), the library is unstranded (-s 0) and the number of threads to use (-T 1).

    +

    Run the featurecounts bash script in the directory 5_dge. Use pwd to check if you are standing in the correct directory.

    +

    You should be standing here to run this:

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/rnaseq/5_dge
    +
    +
    +
    +
    bash ../scripts/featurecounts.sh
    +
    +

    You should have two output files:

    +
    +
    ls -l
    +
    +
    +
    -rw-rw-r-- 1 user gXXXXXXX 2.8M Sep 15 11:05 counts.txt
    +-rw-rw-r-- 1 user gXXXXXXX  658 Sep 15 11:05 counts.txt.summary
    +
    +

    Inspect the files and try to make sense of them.

    +
    +
    +
    + +
    +
    +Important +
    +
    +
    +

    For downstream steps, we will NOT use this counts.txt file. Instead we will use counts_full.txt from the back-up folder. This contains counts across all chromosomes. This is located here: /sw/courses/ngsintro/rnaseq/main/5_dge/. Copy this file to your 5_dge directory.

    +

    Remember to replace username.

    +
    +
    +
    cp /sw/courses/ngsintro/rnaseq/main/5_dge/counts_full.txt /proj/naiss2023-22-862/nobackup/username/rnaseq/5_dge/
    +
    +
    +
    +
    +


    +
    +
    +

    3.6 MultiQC

    +

    Combined QC report using MultiQC

    +

    We will use the tool MultiQC to crawl through the output, log files etc from FastQC, HISAT2, QualiMap and featureCounts to create a combined QC report.

    +

    Move to the 6_multiqc directory. You should be standing here to run this:

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/rnaseq/6_multiqc
    +
    +
    +

    And run this in the terminal.

    +
    +
    module load bioinfo-tools
    +module load MultiQC/1.11
    +
    +multiqc --interactive ../
    +
    +
    +
      /// MultiQC 🔍 | v1.11
    +
    +|           multiqc | Search path : /crex/proj/XXXXXXX/nobackup/username/rnaseq
    +|         searching | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 298/298  
    +|          qualimap | Found 6 RNASeq reports
    +|    feature_counts | Found 6 reports
    +|           bowtie2 | Found 6 reports
    +|            fastqc | Found 12 reports
    +|           multiqc | Compressing plot data
    +|           multiqc | Report      : multiqc_report.html
    +|           multiqc | Data        : multiqc_data
    +|           multiqc | MultiQC complete
    +
    +

    The output should look like below:

    +
    +
    ls -l
    +
    +
    +
    drwxrwsr-x 2 user gXXXXXXX 4.0K Sep  6 22:33 multiqc_data
    +-rw-rw-r-- 1 user gXXXXXXX 1.3M Sep  6 22:33 multiqc_report.html
    +
    +

    Download the MultiQC HTML report to your computer and inspect the report.

    +

    Run this step in a LOCAL terminal and NOT on Uppmax. Remember to replace username (twice).

    +
    +
    +
    scp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/6_multiqc/multiqc_report.html .
    +
    +
    +


    +
    +
    +

    3.7 DESeq2

    +

    Differential gene expression using DESeq2

    +

    The easiest way to perform differential expression is to use one of the statistical packages, within R environment, that were specifically designed for analyses of read counts arising from RNA-seq, SAGE and similar technologies. Here, we will use one such package called DESeq2. Learning R is beyond the scope of this course so we prepared basic ready to run R scripts to find DE genes between conditions KO and Wt.

    +

    Move to the 5_dge directory and load R modules for use.

    +
    +
    module load R/4.0.0
    +module load R_packages/4.0.0
    +
    +

    Use pwd to check if you are standing in the correct directory. Copy the following file to the 5_dge directory: /sw/courses/ngsintro/rnaseq/main/5_dge/dge.R

    +

    Make sure you have the counts_full.txt. If not, you can copy this file too: /sw/courses/ngsintro/rnaseq/main/5_dge/counts_full.txt

    +
    +
    +
    cp /sw/courses/ngsintro/rnaseq/main/5_dge/dge.R .
    +cp /sw/courses/ngsintro/rnaseq/main/5_dge/counts_full.txt .
    +
    +
    +

    Now, run the R script from the schell in 5_dge directory.

    +
    +
    Rscript dge.R
    +
    +

    If you are curious what’s inside dge.R, you are welcome to explore it using a text editor.

    +

    This should have produced the following output files:

    +
    +
    ls -l
    +
    +
    +
    -rw-rw-r-- 1 user gXXXXXXX 282K Jan 22 23:16 counts_vst_full.Rds
    +-rw-rw-r-- 1 user gXXXXXXX 1.7M Jan 22 23:16 counts_vst_full.txt
    +-rw-rw-r-- 1 user gXXXXXXX 727K Jan 22 23:16 dge_results_full.Rds
    +-rw-rw-r-- 1 user gXXXXXXX 1.7M Jan 22 23:16 dge_results_full.txt
    +
    +

    Essentially, we have two outputs: dge_results_full and counts_vst_full. dge_results_full is the list of differentially expressed genes. This is available in human readable tab-delimited .txt file and R readable binary .Rds file. The counts_vst_full is variance-stabilised normalised counts, useful for exploratory analyses.

    +

    Copy the results text file (dge_results_full.txt) to your computer and inspect the results. What are the columns? How many differentially expressed genes are present after adjusted p-value of 0.05? How many genes are upregulated and how many are down-regulated? How does this change if we set a fold-change cut-off of 1?

    +

    Open in a spreadsheet editor like Microsoft Excel or LibreOffice Calc.

    +

    If you do not have the results or were unable to run the DGE step, you can copy these two here which will be required for functional annotation (optional).

    +
    +
    +
    cp /sw/courses/ngsintro/rnaseq/main/5_dge/dge_results_full.txt .
    +cp /sw/courses/ngsintro/rnaseq/main/5_dge/dge_results_full.Rds .
    +cp /sw/courses/ngsintro/rnaseq/main/5_dge/counts_vst_full.txt .
    +cp /sw/courses/ngsintro/rnaseq/main/5_dge/counts_vst_full.Rds .
    +
    +
    +
    +
    +
    +

    4 Bonus exercises

    +
    +
    +
    + +
    +
    +Optional +
    +
    +
    +

    These exercises are optional and to be run only if you have time and you want to explore this topic further.

    +
    +
    +
    +

    4.1 Functional annotation

    +

    In this part of the exercise we will address the question which biological processes are affected in the experiment; in other words we will functionally annotate the results of the analysis of differential gene expression (performed in the main part of the exercise). We will use Gene Ontology (GO) and Reactome databases.

    +

    When performing this type of analysis, one has to keep in mind that the analysis is only as accurate as the annotation available for your organism. So, if working with non-model organisms which do have experimentally-validated annotations (computationally inferred), the results may not be fully reflecting the actual situation.

    +

    There are many methods to approach the question as to which biological processes and pathways are over-represented amongst the differentially expressed genes, compared to all the genes included in the DE analysis. They use several types of statistical tests (e.g. hypergeometric test, Fisher’s exact test etc.), and many have been developed with microarray data in mind. Not all of these methods are appropriate for RNA-seq data, which as you remember from the lecture, exhibit length bias in power of detection of differentially expressed genes (i.e. longer genes, which tend to gather more reads, are more likely to be detected as differentially expressed than shorter genes, solely because of the length).

    +

    We will use the R / Bioconductor package goseq, specifically designed to work with RNA-seq data. This package provides methods for performing Gene Ontology and pathway analysis of RNA-seq data, taking length bias into account.

    +

    In this part, we will use the same data as in the main workflow. The starting point of the exercise is the file with results of the differential expression produced in the main part of the exercise.

    +
    +

    4.1.1 Preparation

    +

    Change to the funannot directory in your rnaseq directory.

    +
    +
    cd funannot
    +
    +

    Copy this file /sw/courses/ngsintro/rnaseq/bonus/funannot/annotate_de_results.R to your rnaseq/funannot directory.

    +

    Remember to replace username.

    +
    +
    +
    cp /sw/courses/ngsintro/rnaseq/bonus/funannot/annotate_de_results.R /proj/naiss2023-22-862/nobackup/username/rnaseq/funannot/
    +
    +
    +

    We need some annotation information, so we will copy this file /sw/courses/ngsintro/rnaseq/main/reference/mm-biomart99-genes.txt.gz to your rnaseq/reference directory.

    +
    +
    +
    cp /sw/courses/ngsintro/rnaseq/main/reference/mm-biomart99-genes.txt.gz /proj/naiss2023-22-862/nobackup/username/rnaseq/reference/
    +
    +
    +

    Then uncompress the file. gunzip ../reference/mm-biomart99-genes.txt.gz

    +

    Load R module and R packages

    +
    +
    module load R/4.0.0
    +module load R_packages/4.0.0
    +
    +

    Run the functional annotation script from the linux terminal.

    +
    +
    Rscript annotate_de_results.R
    +
    +

    It will fetch dge_results_full.Rds from 5_dge/ and annotation files from reference/. When completed, you should find a directory named funannot_results.

    +
    +
    ls -l
    +
    +
    +
    -rw-rw-r-- 1 user gXXXXXXX 44K Jan 22 23:37 go_down.txt
    +-rw-rw-r-- 1 user gXXXXXXX 15K Jan 22 23:37 go_up.txt
    +-rw-rw-r-- 1 user gXXXXXXX 800 Jan 22 23:37 reactome_down.txt
    +-rw-rw-r-- 1 user gXXXXXXX 794 Jan 22 23:37 reactome_up.txt
    +
    +
    +
    +

    4.1.2 Interpretation

    +

    The results are saved as tables in the directory funannot_results. There are four tables: GO terms for up-regulated genes (go_up.txt), GO terms for down-regulated genes (go_down.txt) and similarily, Reactome pathways for up-regulated genes (reactome_up.txt) and Reactome pathways for down-regulated genes (reactome_down.txt).

    +

    Take a quick look at some of these files.

    +
    +
    head go_down.txt
    +
    +

    The columns of the results tables are:

    +
    +
    # go
    +category over_represented_pvalue under_represented_pvalue numDEInCat numInCat term ontology
    +# reactome
    +category over_represented_pvalue under_represented_pvalue numDEInCat numInCat path_name
    +
    +

    You can view the tables in a text editor (nano,gedit etc), and try to find GO terms and pathways relevant to the experiment using a word search functionality. You could download these files to your computer and import them into a spreadsheet program like MS Excel or LibreOffice Calc.

    +

    Try to use grep to find a match using a keyword, say phosphorylation.

    +
    +
    cat go_down.txt | grep "phosphorylation"
    +
    +

    Have a look at the GO terms and see if you think the functional annotation reflects the biology of the experiments we have just analysed?

    +
    +
    +
    +

    4.2 RNA-Seq plots

    +

    Creating high quality plots of RNA-seq analysis are most easily done using R. Depending on your proficiency in reading R code and using R, you can in this section either just call scripts from the command lines with a set of arguments or you can open the R script in a text editor, and run the code step by step from an interactive R session.

    +

    Copy the R script files from the following directory: /sw/courses/ngsintro/rnaseq/bonus/plots/ to your plots directory.

    +

    Remember to replace username.

    +
    +
    +
    cp /sw/courses/ngsintro/rnaseq/bonus/plots/*.R /proj/naiss2023-22-862/nobackup/username/rnaseq/plots/
    +
    +
    +

    You should have the following files:

    +
    +
    ls -l
    +
    +
    +
    -rw-rw-r-- 1 user gXXXXXXX 2.0K Sep 20  2016 gene.R
    +-rw-rw-r-- 1 user gXXXXXXX  842 Sep 22  2016 heatmap.R
    +-rw-rw-r-- 1 user gXXXXXXX  282 Sep 22  2016 ma.R
    +-rw-rw-r-- 1 user gXXXXXXX  340 Sep 22  2016 pca.R
    +-rw-rw-r-- 1 user gXXXXXXX  669 Sep 22  2016 volcano.R
    +
    +

    It is important that you load module R and R_packages.

    +
    +
    module load R/4.0.0
    +module load R_packages/4.0.0
    +
    +
    +

    4.2.1 PCA plot

    +

    A popular way to visualise general patterns of gene expression in your data is to produce either PCA (Principal Component Analysis) or MDS (Multi Dimensional Scaling) plots. These methods aim at summarising the main patterns of expression in the data and display them on a two-dimensional space and still retain as much information as possible. To properly evaluate these kind of results is non-trivial, but in the case of RNA-seq data we often use them to get an idea of the difference in expression between treatments and also to get an idea of the similarity among replicates. If the plots shows clear clusters of samples that corresponds to treatment it is an indication of treatment actually having an effect on gene expression. If the distance between replicates from a single treatment is very large it suggests large variance within the treatment, something that will influence the detection of differentially expressed genes between treatments.

    +

    Move to the plots/ directory. Then run the pca.R script like below.

    +
    +
    Rscript pca.R
    +
    +

    This generates a file named pca.png in the plots folder. To view it, use eog pca.png & or copy it to your local disk.

    +
    +
    +
    +
    +

    +
    +
    +
    +
    +

    Do samples cluster as expected? Are there any odd or mislabelled samples? Based on these results, would you expect to find a large number of significant DE genes?

    +
    +
    +

    4.2.2 MA plot

    +

    An MA-plot plots the mean expression and estimated log-fold-change for all genes in an analysis.

    +

    Run the ma.R script in the plots directory.

    +
    +
    Rscript ma.R
    +
    +

    This generates a file named ma.png in the plots folder. To view it, use eog ma.png & or copy it to your local disk.

    +
    +
    +
    +
    +

    +
    +
    +
    +
    +

    What do you think the blue dots represent?

    +
    +
    +

    4.2.3 Volcano plot

    +

    A related type of figure will instead plot fold change (on log2 scale) on the x-axis and -log10 p-value on the y-axis. Scaling like this means that genes with lowest p-value will be found at the top of the plot. In this example we will highlight (in blue) the genes that are significant (p-val 0.05 after correction for multiple testing).

    +

    Run the script named volcano.R in the plots directory.

    +
    +
    Rscript volcano.R
    +
    +

    This generates a file named volcano.png in the plots folder. To view it, use eog volcano.png & or copy it to your local disk.

    +
    +
    +
    +
    +

    +
    +
    +
    +
    +

    Anything noteworthy about the patterns in the plot? Is there a general trend in the direction of change in gene expression as a consequence of the experiment?

    +
    +
    +

    4.2.4 Heatmap

    +

    Another popular plots for genome-wide expression patterns is heatmap for a set of genes. If you run the script called heatmap.R, it will extract the top 50 genes that have the lowest p-value in the experiment and create a heatmap from these. In addition to color-coding the expression levels over samples for the genes it also clusters the samples and genes based on inferred distance between them.

    +

    Run the script named heatmap.R in the plots directory.

    +
    +
    Rscript heatmap.R
    +
    +

    This generates a file named heatmap.png in the plots folder. To view it, use eog heatmap.png & or copy it to your local disk.

    +
    +
    +
    +
    +

    +
    +
    +
    +
    +

    Compare this plot to a similar plot in the paper behind the data.

    +
    +
    +
    +

    4.3 IGV browser

    +

    Data visualisation is important to be able to clearly convey results, but can also be very helpful as tool for identifying issues and note-worthy patterns in the data. In this part you will use the BAM files you created earlier in the RNA-seq lab and use IGV (Integrated Genomic Viewer) to visualise the mapped reads and genome annotations. In addition we will produce high quality plots of both the mapped read data and the results from differential gene expression.

    +

    If you are already familiar with IGV you can load the mouse genome and at least one BAM file from each of the treatments that you created earlier. The functionality of IGV is the same as if you look at genomic data, but there are a few of the features that are more interesting to use for RNA-seq data.

    +

    Integrated genomics viewer from Broad Institute is a nice graphical interface to view bam files and genome annotations. It also has tools to export data and some functionality to look at splicing patterns in RNA-seq data sets. Even though it allows for some basic types of analysis it should be used more as a nice way to look at your mapped data. Looking at data in this way might seem like a daunting approach as you can not check more than a few regions, but in in many cases it can reveal mapping patterns that are hard to catch with just summary statistics.

    +

    For this tutorial you can chose to run IGV directly on your own computer or on Uppmax . If you chose to run it on your own computer you will have to download some of the BAM files (and the corresponding index files) from Uppmax. If you have not yet installed IGV you also have to download the program.

    +
    +
    +
    + +
    +
    +Local +
    +
    +
    +

    Copy two BAM files (one from each experimental group, for example; SRR3222409-19 and SRR3222412-19) and the associated index (.bam.bai) files to your computer by running the below command in a LOCAL terminal and NOT on Uppmax.

    +

    Remember to replace username.

    +
    +
    +
    scp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/SRR3222409-19.bam ./
    +scp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/SRR3222409-19.bam.bai ./
    +scp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/SRR3222412-19.bam ./
    +scp username@rackham.uppmax.uu.se:/proj/naiss2023-22-862/nobackup/username/rnaseq/3_mapping/SRR3222412-19.bam.bai ./
    +
    +
    +

    Alternatively, you can use an SFTP browser like Filezilla or Cyberduck for a GUI interface. Windows users can also use the MobaXterm SFTP file browser to drag and drop.

    +
    +
    +
    +
    +
    + +
    +
    +Uppmax +
    +
    +
    +

    For Linux and Mac users, Log in to Uppmax in a way so that the generated graphics are exported via the network to your screen. This will allow any graphical interface that you start on your compute node to be exported to your computer. However, as the graphics are exported over the network, it can be fairly slow in redrawing windows and the experience can be fairly poor.

    +

    Login in to Uppmax with X-forwarding enabled:

    +
    +
    ssh -Y username@rackham.uppmax.uu.se
    +ssh -Y computenode
    +
    +

    An alternative method is to login through Rackham-GUI. Once you log into this interface you will have a linux desktop interface in a browser window. This interface is running on the login node, so if you want to do any heavy lifting you need to login to your reserved compute node also here. This is done by opening a terminal in the running linux environment and log on to your compute node as before. NB! If you have no active reservation you have to do that first.

    +

    Load necessary modules and start IGV

    +
    +
    module load bioinfo-tools
    +module load IGV/2.8.13
    +igv-core
    +
    +

    This should start the IGV so that it is visible on your screen. If not please try to reconnect to Uppmax or consider running IGV locally as that is often the fastest and most convenient solution.

    +
    +
    +

    Once we have the program running, you select the genome that you would like to load. Choose Mouse mm10. Note that if you are working with a genome that are not part of the available genomes in IGV, one can create genome files from within IGV. Please check the manual of IGV for more information on that.

    +

    To open your BAM files, go to File > Load from file... and select your BAM file and make sure that you have a .bai index for that BAM file in the same folder. You can repeat this and open multiple BAM files in the same window, which makes it easy to compare samples. Then select Chr19 since we only have data for that one chromosome.

    +

    For every file you open a number of panels are opened that visualise the data in different ways. The first panel named Coverage summarises the coverage of base-pairs in the window you have zoomed to. The second panel shows the reads as they are mapped to the genome. If one right click with the mouse on the read panel there many options to group and color reads. The bottom panel named Refseq genes shows the gene models from the annotation.

    +

    To see actual reads you have to zoom in until the reads are drawn on screen. If you have a gene of interest you can also use the search box to directly go to that gene.

    +

    Here is the list of top 30 differentially expressed genes on Chr19 ordered by absolute fold change. The adjusted p value is shown as padj, the average expression of the gene is shown as baseMean.

    +
          ensembl_gene_id external_gene_name    baseMean log2FoldChange         padj   gene_biotype
    +1  ENSMUSG00000117896           AA387883    59.94083     -2.7846887 1.943690e-17         lncRNA
    +2  ENSMUSG00000024799             Tm7sf2   947.63388     -2.0385744 1.677171e-44 protein_coding
    +3  ENSMUSG00000025172             Ankrd2    59.28633      1.7519899 1.261004e-08 protein_coding
    +4  ENSMUSG00000049134               Nrap   220.59983      1.6993887 1.067822e-08 protein_coding
    +5  ENSMUSG00000024935             Slc1a1    63.82987      1.6821634 1.652208e-09 protein_coding
    +6  ENSMUSG00000037071               Scd1  6678.59981     -1.4473717 2.961722e-14 protein_coding
    +7  ENSMUSG00000024665              Fads2  3269.79425     -1.4152150 3.134559e-29 protein_coding
    +8  ENSMUSG00000024747            Aldh1a7    65.81205     -1.3544431 1.002599e-06 protein_coding
    +9  ENSMUSG00000025216               Lbx1    26.03640      1.3356124 1.328372e-04 protein_coding
    +10 ENSMUSG00000056290             Ms4a4b    23.27050      1.3299845 5.015617e-05 protein_coding
    +11 ENSMUSG00000025221             Kcnip2    34.13675     -1.3165310 1.463369e-04 protein_coding
    +12 ENSMUSG00000032648               Pygm  1129.47092      1.2452572 2.736196e-04 protein_coding
    +13 ENSMUSG00000043639              Rbm20    51.36261      1.1816554 7.774718e-04 protein_coding
    +14 ENSMUSG00000118032            Gm50147    39.53043     -1.1797580 3.794393e-04         lncRNA
    +15 ENSMUSG00000036278            Macrod1   244.02353      1.0824415 4.984802e-07 protein_coding
    +16 ENSMUSG00000025203               Scd2 44054.03491     -1.0504733 1.874759e-11 protein_coding
    +17 ENSMUSG00000010663              Fads1  4074.38868     -1.0503935 1.470460e-18 protein_coding
    +18 ENSMUSG00000060675             Plaat3  5284.36470     -1.0462725 2.114719e-13 protein_coding
    +19 ENSMUSG00000016496              Cd274    35.91671      1.0175443 5.632932e-03 protein_coding
    +20 ENSMUSG00000024673              Ms4a1    25.80723      1.0130356 6.294275e-03 protein_coding
    +21 ENSMUSG00000032773              Chrm1    76.11444      0.9262597 7.665519e-04 protein_coding
    +22 ENSMUSG00000067279            Ppp1r3c   162.14777      0.9018589 3.672613e-04 protein_coding
    +23 ENSMUSG00000025013               Tll2   108.20333     -0.9012959 1.249858e-03 protein_coding
    +24 ENSMUSG00000006457              Actn3  1322.01659      0.8988003 1.352229e-02 protein_coding
    +25 ENSMUSG00000075289             Carns1  1003.91026     -0.8819988 4.982949e-10 protein_coding
    +26 ENSMUSG00000075010           AW112010    56.94897      0.8128744 4.027595e-02         lncRNA
    +27 ENSMUSG00000025227            Mfsd13a   107.55434     -0.8126676 1.107050e-03 protein_coding
    +28 ENSMUSG00000067242               Lgi1   506.42577     -0.7842945 2.570293e-06 protein_coding
    +29 ENSMUSG00000024812               Tjp2  1478.96029     -0.7627251 9.004722e-07 protein_coding
    +30 ENSMUSG00000047368            Abhd17b  1562.07350     -0.7625545 5.750875e-07 protein_coding
    +

    Have a look at few of the interesting genes on Chr19 using the external_gene_name identifier. Look into gene Tm7sf2 or Ankrd2. You might have to right-click and change option to Squished to see more reads.

    +

    Do you expect these genes to be differentially expressed?

    +

    To see some genes with large number of reads, see Scd1 or Scd2.

    +

    IGV view of gene Tm7sf2 across 6 samples.

    +
    +
    +

    +
    +
    +

    IGV view of gene Ankrd2 across 6 samples.

    +
    +
    +

    +
    +
    +

    IGV view of gene Scd1 across 6 samples.

    +

    For more detailed information on the splice reads you can instead of just looking at the splice panel right click on the read panel and select Sashimi plots. This will open a new window showing in an easy readable fashion how reads are spliced in mapping and you will also be able to see that there are differences in between what locations reads are spliced. This hence gives some indication on the isoform usage of the gene.

    +

    Do you think the reads are from a stranded or unstranded library?

    +

    One can visualise all genes in a given pathway using the gene list option under Regions in the menu. If you need hints for how to proceed, see Gene List tutorial at Broad. But, we only have data from one chromosome, so this is not that useful now.

    +
    +
    +
    +

    5 sbatch

    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    You are not required to run anything practically in this section. This is just to read and understand.

    +
    +
    +

    We have throughout this tutorial written bash scripts and run them from the terminal directly. Remember that we are not running on the login node. We have pre-allocated resources, then logged in to a compute node to run tasks. This is called working interactively on Uppmax. This is fine for tutorials and testing purposes. But, if you were to actually work on Uppmax, you would follow a slightly different approach.

    +

    The standard workflow on Uppmax is to login to the login node and then submit tasks as jobs to something called a Slurm queue. We haven’t used this option, because it involves waiting for an unpredictable amount of time for your submitted job to execute. In this section, we will take a look at how to modify a standard bash script to work with Slurm job submission.

    +

    This is how our standard bash script for mapping looks like:

    +
    +
    #!/bin/bash
    +
    +# load modules
    +module load bioinfo-tools
    +module load HISAT2/2.1.0
    +module load samtools/1.8
    +
    +# create output filename prefix
    +prefix=$( basename "$1" | sed -E 's/_.+$//' )
    +
    +hisat2 \
    +-p 8 \
    +-x ../reference/mouse_chr19_hisat2/mouse_chr19_hisat2 \
    +--summary-file "${prefix}.summary" \
    +-1 $1 \
    +-2 $2 | samtools sort -O BAM > "${prefix}.bam"
    +
    +

    We add SBATCH commands to the above script. The new script looks like this:

    +
    +
    +
    #!/bin/bash
    +#SBATCH -A naiss2023-22-862
    +#SBATCH -p core
    +#SBATCH -n 8
    +#SBATCH -t 3:00:00
    +#SBATCH -J hisat2-align
    +
    +# load modules
    +module load bioinfo-tools
    +module load HISAT2/2.1.0
    +module load samtools/1.8
    +
    +# create output filename prefix
    +prefix=$( basename "$1" | sed -E "s/_.+$//" )
    +
    +hisat2 \
    + -p 8 \
    + -x ../reference/mouse_chr19_hisat2/mouse_chr19_hisat2 \
    + --summary-file "${prefix}-summary.txt" \
    + -1 $1 \
    + -2 $2 | samtools sort -O BAM > "${prefix}.bam"
    +
    +
    +

    The SBATCH commands in the above script is specifying the account name to use resources from, the required number of cores, the time required for the job and a job name.

    +

    If you run this as a normal bash script like this ./hisat2_align.sh ... or bash ./hisat2_align.sh ..., the SBATCH comments have no effect (they are treated as comments) and the contents of the script will immediately start executing. But if you run this as script as sbatch ./hisat2_align.sh ..., the script is submitted as a job to the Uppmax Slurm queue. In this case, the SBATCH lines are interpreted and used by Slurm. At some point, your submitted job will reach the top of the queue and then the script will start to be executed.

    +

    You can check your jobs in the queue by running the following command.

    +
    +
    jobinfo -u user
    +
    +

    And this gives a list like this:

    +
    +
    CLUSTER: rackham
    +Running jobs:
    +   JOBID PARTITION   NAME USER        ACCOUNT ST          START_TIME  TIME_LEFT  NODES CPUS NODELIST(REASON)
    + 5006225      core (null) user       gXXXXXXX  R 2018-09-12T14:00:03      44:31      1    1 r169
    + 5006229      core (null) user       gXXXXXXX  R 2018-09-12T14:00:03      44:31      1    1 r169
    + 5006352      core (null) user       gXXXXXXX  R 2018-09-12T14:04:14      48:42      1    1 r178
    + 5006355      core (null) user       gXXXXXXX  R 2018-09-12T14:05:17      49:45      1    1 r169
    + 5006356      core (null) user       gXXXXXXX  R 2018-09-12T14:06:08      50:36      1    5 r179
    +
    +

    If the job is pending, then you will see PD in the ST column. If your job is running, you should see R. Once your job starts running, you will see a file named slurm-XXXX.out in the directory in which you submitted the job. This is the standard-out from that job. ie; everything that you would normally see printed to your screen when running locally, is printed to this file when running as a job. Once the job is over, one would inspect the slurm output file.

    +
    +
    head slurm-XXXX.out
    +tail slurm-XXXX.out
    +cat slurm-XXXX.out
    +
    +
    +
    +

    6 Nextflow

    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    You are not required to run anything practically in this section. This is just to read and understand.

    +
    +
    +

    Everything you have done today and more is easily done using structured pipelines. Nextflow is a popular framework for creating bioinformatic pipelines and nf-core is a collection of curated analyses pipelines. Here, we will discuss the steps for analysing our current dataset using the nf-core rnaseq pipeline for bulk RNA-Seq. The nf-core website and pipeline specific pages are good sources of information on what the pipeline does and what parameters can be changed.

    +
    +
    +

    +
    +
    +

    We need a samplesheet.csv to define our samples. In this case, the full size samples are used. For single-end reads, fastq_2 column is left empty.

    +
    sample,fastq_1,fastq_2,strandedness
    +ko_1,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222409_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222409_2.fq.gz,unstranded
    +ko_2,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222410_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222410_2.fq.gz,unstranded
    +ko_3,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222411_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222411_2.fq.gz,unstranded
    +wt_1,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222412_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222412_2.fq.gz,unstranded
    +wt_2,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222413_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222413_2.fq.gz,unstranded
    +wt_3,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222414_1.fq.gz,/crex/course_data/ngsintro/rnaseq/main_full/1_raw/SRR3222414_2.fq.gz,unstranded
    +

    We need a params.config file to define parameters such as input, output, genome, annotation etc.

    +
    params.input = "samplesheet.csv"
    +params.outdir = "results"
    +params.aligner = "star_salmon"
    +
    +params.fasta = "/sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa"
    +params.gtf = "/sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf"
    +gene_bed = "/sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed"
    +star_index = "/sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/version2.7.x/"
    +

    And lastly we have a nextflow.sh which will be our bash script for launching the job.

    +
    +
    +
    #!/bin/bash
    +
    +#SBATCH -A naiss2023-22-862
    +#SBATCH -p core
    +#SBATCH -n 1
    +#SBATCH -t 4:00:00
    +#SBATCH -J nf-core
    +
    +module load bioinfo-tools
    +module load Nextflow/21.10.6
    +module load nf-core/2.1
    +NXF_HOME=.
    +
    +nextflow run nf-core/rnaseq -r 3.7 -c params.config -profile uppmax --project naiss2023-22-862 -resume
    +
    +
    +

    Notice that we use -profile uppmax since this is run on Uppmax. The job is then submitted by simply running sbatch nextflow.sh.

    +

    The slurm output from this job looks like this:

    +
    Note that NXF_HOME is set to $HOME/.nextflow
    +Please change NXF_HOME to a place in your project directory (export NXF_HOME=yourprojectfolder)
    +
    +N E X T F L O W  ~  version 21.10.6
    +Launching `nf-core/rnaseq` [happy_sammet] - revision: e0dfce9af5 [3.7]
    +
    +
    +------------------------------------------------------
    +                                        ,--./,-.
    +        ___     __   __   __   ___     /,-._.--~'
    +  |\ | |__  __ /  ` /  \ |__) |__         }  {
    +  | \| |       \__, \__/ |  \ |___     \`-._,-`-,
    +                                        `._,._,'
    +  nf-core/rnaseq v3.7
    +------------------------------------------------------
    +Core Nextflow options
    +  revision                  : 3.7
    +  runName                   : happy_sammet
    +  containerEngine           : singularity
    +  launchDir                 : /crex/course_data/ngsintro/rnaseq/main_full/nextflow
    +  workDir                   : /crex/course_data/ngsintro/rnaseq/main_full/nextflow/work
    +  projectDir                : ./assets/nf-core/rnaseq
    +  userName                  : royfranc
    +  profile                   : uppmax
    +  configFiles               : /crex/course_data/ngsintro/rnaseq/main_full/nextflow/assets/nf-core/rnaseq/nextflow.config, /crex/course_data/ngsintro/rnaseq/main_full/nextflow/params.config
    +
    +Input/output options
    +  input                     : samplesheet.csv
    +  outdir                    : results
    +
    +Reference genome options
    +  fasta                     : /sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa
    +  gtf                       : /sw/data/igenomes/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf
    +  save_reference            : true
    +  igenomes_base             : /sw/data/igenomes/
    +
    +Institutional config options
    +  config_profile_description: UPPMAX (Rackham) cluster profile provided by nf-core/configs.
    +  config_profile_contact    : Phil Ewels (@ewels)
    +  config_profile_url        : https://www.uppmax.uu.se/
    +
    +Max job request options
    +  max_cpus                  : 20
    +  max_memory                : 970 GB
    +  max_time                  : 10d
    +
    +Generic options
    +  tracedir                  : null/pipeline_info
    +
    +!! Only displaying parameters that differ from the pipeline defaults !!
    +------------------------------------------------------
    +If you use nf-core/rnaseq for your analysis please cite:
    +
    +* The pipeline
    +  https://doi.org/10.5281/zenodo.1400710
    +
    +* The nf-core framework
    +  https://doi.org/10.1038/s41587-020-0439-x
    +
    +* Software dependencies
    +  https://github.com/nf-core/rnaseq/blob/master/CITATIONS.md
    +------------------------------------------------------
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -
    +
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:PREPAR... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:INPUT_... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:CAT_FASTQ -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:FASTQC... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:FASTQC... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:ALIGN_... -
    +[-        ] process > NFCORE_RNASEQ:RNASEQ:ALIGN_... -
    +
    +...
    +skipping many lines here
    +...
    +
    +[3d/d294eb] process > NFCORE_RNASEQ:RNASEQ:CUSTOM... [100%] 1 of 1 ✔
    +[de/a03037] process > NFCORE_RNASEQ:RNASEQ:MULTIQ... [100%] 1 of 1 ✔
    +-[nf-core/rnaseq] 6/6 samples passed STAR 5% mapped threshold:
    +    90.41%: ko_2
    +    89.8%: ko_3
    +    87.15%: ko_1
    +    89.7%: wt_2
    +    90.29%: wt_3
    +    91.02%: wt_1
    +    ..see pipeline reports for full list
    +-
    +-[nf-core/rnaseq] Pipeline completed successfully-
    +Completed at: 13-Jan-2023 14:39:08
    +Duration    : 1h 45m 30s
    +CPU hours   : 90.4
    +Succeeded   : 207
    +

    The output results directory looks like this:

    +
    results/
    +├── fastqc
    +├── genome
    +│   ├── genes.bed
    +│   ├── genome.fa.fai
    +│   ├── genome.fa.sizes
    +│   ├── genome_genes.gtf
    +│   ├── genome.transcripts.fa
    +│   ├── index
    +│   └── rsem
    +├── multiqc
    +│   └── star_salmon
    +├── pipeline_info
    +│   ├── samplesheet.valid.csv
    +│   └── software_versions.yml
    +├── star_salmon
    +│   ├── bigwig
    +│   ├── deseq2_qc
    +│   ├── dupradar
    +│   ├── featurecounts
    +│   ├── ko_1
    +│   ├── ko_1.markdup.sorted.bam
    +│   ├── ko_1.markdup.sorted.bam.bai
    +│   ├── ko_2
    +│   ├── ko_2.markdup.sorted.bam
    +│   ├── ko_2.markdup.sorted.bam.bai
    +│   ├── ko_3
    +│   ├── ko_3.markdup.sorted.bam
    +│   ├── ko_3.markdup.sorted.bam.bai
    +│   ├── log
    +│   ├── picard_metrics
    +│   ├── preseq
    +│   ├── qualimap
    +│   ├── rseqc
    +│   ├── salmon.merged.gene_counts_length_scaled.rds
    +│   ├── salmon.merged.gene_counts_length_scaled.tsv
    +│   ├── salmon.merged.gene_counts.rds
    +│   ├── salmon.merged.gene_counts_scaled.rds
    +│   ├── salmon.merged.gene_counts_scaled.tsv
    +│   ├── salmon.merged.gene_counts.tsv
    +│   ├── salmon.merged.gene_tpm.tsv
    +│   ├── salmon.merged.transcript_counts.rds
    +│   ├── salmon.merged.transcript_counts.tsv
    +│   ├── salmon.merged.transcript_tpm.tsv
    +│   ├── salmon_tx2gene.tsv
    +│   ├── samtools_stats
    +│   ├── stringtie
    +│   ├── wt_1
    +│   ├── wt_1.markdup.sorted.bam
    +│   ├── wt_1.markdup.sorted.bam.bai
    +│   ├── wt_2
    +│   ├── wt_2.markdup.sorted.bam
    +│   ├── wt_2.markdup.sorted.bam.bai
    +│   ├── wt_3
    +│   ├── wt_3.markdup.sorted.bam
    +│   └── wt_3.markdup.sorted.bam.bai
    +└── trimgalore
    +

    This pipeline takes you from raw reads to counts including read QC, mapping, mapping QC and quantification as well as a complete collated overview of all steps as a MultiQC report (multiqc/star_salmon/multiqc_report.html). The star_salmon/salmon.merged.gene_counts.tsv is the counts file that you would use for downstream differential gene expression using DESeq2.

    +

    For standard analyses steps, it is recommended to use a pipeline as the tools are up-to-date and the analyses steps are reproducible using exactly the same versions of tools.

    +
    +
    +

    7 Simon’s analysis

    +

    We had Simon Andrews from the Babraham institute with us on one of the workshops and he did his own exploration into the dataset from this paper using his tool SeqMonk. It’s an excellent read and highly recommended. His report is available on the Contents page.

    +
    +
    +

    8 Conclusion

    +

    We hope that you enjoyed getting your hands wet working on some real-ish data. In this tutorial, we have covered the most important data processing steps that may be enough when the libraries are good. If not, there are plenty of troubleshooting procedures to try before discarding the data. And once the count table are in place, the biostatistics and data mining begins. There are no well-defined solutions here, all depends on the experiment and questions to be asked, but we strongly advise learning R. Not only to use the specifically designed statistical packages to analyse NGS count data, but also to be able to handle the data and results as well as to generate high-quality plots. There are many available tools and well-written tutorials with examples to learn from.

    +

    For those interested in RNA-Seq analysis, SciLifeLab offers a more advanced course in RNA-Seq analysis each semester. For more information, see SciLifeLab events.

    + + +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/2311/topics/rnaseq/slide_rnaseq.html b/2311/topics/rnaseq/slide_rnaseq.html new file mode 100644 index 00000000..f62e12bd --- /dev/null +++ b/2311/topics/rnaseq/slide_rnaseq.html @@ -0,0 +1,1722 @@ + + + + + + + + + + + + + + + + + Bulk RNASeq Analysis + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +

    Bulk RNASeq Analysis

    + +
    +
    +
    +Roy Francis / Dag Ahrén +
    +
    +
    + +

    13-Nov-2023

    +
    + +
    +

    What is RNA?

    +

    +
      +
    • The transcriptome is spatially and temporally dynamic
    • +
    • Data comes from functional units (coding regions)
    • +
    • Only a tiny fraction of the genome
    • +
    + +
    +
    +

    Applications

    +
      +
    • Identify gene sequences in genomes (annotation)
    • +
    • Learn about gene function
    • +
    • Differential gene expression
    • +
    • Explore isoform and allelic expression
    • +
    • Understand co-expression, pathways and networks
    • +
    • Gene fusion
    • +
    • RNA editing
    • +
    +
    +
    +

    Workflow

    +

    +

    +

    Conesa et al. (2016)

    +
    +
    +

    De-Novo assembly

    +
      +
    • When no reference genome available
    • +
    • To identify novel genes/transcripts/isoforms
    • +
    • Identify fusion genes
    • +
    • Assemble transcriptome from short reads
    • +
    • Access quality of assembly and refine
    • +
    • Map reads back to assembled transcriptome
    • +
    +
    +

    Trinity, SOAPdenovo-Trans, Oases, rnaSPAdes, Hsieh et al. (2019), Wang & Gribskov (2017)

    +
    +
    +
    +

    Experimental design

    +
    +
    + +
    +

    +
    +
    + +
    +
    +

    Library & Sequencing

    +
    +
    +

    +
    +

    +
      +
    • polyA selection/Ribosomal RNA depletion
    • +
    • single-end/Paired-end
    • +
    +
    +
    +
    +
    +

    Library prep

    +
      +
    • 80% of the RNA in a cell is ribosomal RNA (rRNA)
    • +
    • rRNA can be eliminated using polyA selection or rRNA depletion
    • +
    • PolyA selection mostly captures only protein-coding genes / mRNA but gives cleaner results
    • +
    • Depletion of rRNA is the solution if it’s important to retain all RNA species
    • +
    • smallRNAs are purified through size selection
    • +
    • PCR amplification may be needed for low quantity input (See section PCR duplicates)
    • +
    • Preferably opt for stranded (directional) libraries Zhao et al. (2015), Levin et al. (2010) +
        +
      • Accurately identify sense/antisense transcript
      • +
      • Resolve overlapping genes
      • +
    • +
    • Exome capture
    • +
    • Library normalisation to concentrate specific transcripts
    • +
    • Libraries should have high complexity/low duplication. Daley & Smith (2013)
    • +
    +
    +
    +

    Sequencing

    +
      +
    • Short reads vs long reads (Illumina/PacBio)
    • +
    • Read length Chhangawala et al. (2015) +
        +
      • Greater than 50bp does not improve DGE
      • +
      • Longer reads better for isoforms
      • +
    • +
    • Pooling samples
    • +
    • Sequencing depth (Coverage/Reads per sample)
    • +
    • Single-end reads (Cheaper)
    • +
    • Paired-end reads +
        +
      • Increased mappable reads
      • +
      • Increased power in assemblies
      • +
      • Better for structural variation and isoforms
      • +
      • Decreased false-positives for DGE
      • +
    • +
    • More replicates are better than more depth Liu et al. (2014)
    • +
    +

    Corley et al. (2017), SciLifeLab

    +
    +
    +

    Workflow • DGE

    +

    +
    +
    +

    Read QC

    +
      +
    • Number of reads
    • +
    • Per base sequence quality
    • +
    • Per sequence quality score
    • +
    • Per base sequence content
    • +
    • Per sequence GC content
    • +
    • Per base N content
    • +
    • Sequence length distribution
    • +
    • Sequence duplication levels
    • +
    • Overrepresented sequences
    • +
    • Adapter content
    • +
    • Kmer content
    • +
    +

    +

    FastQC, MultiQC

    +

    https://sequencing.qcfail.com/

    +

    +
    +
    +

    FastQC

    +
    +
    +

    Good quality

    +
    +
    +

    +
    +
    +
    +

    Poor quality

    +
    +
    +

    +
    +
    +
    +
    +
    +
    +

    Read QC • PBSQ, PSQS

    +

    Per base sequence quality
    +

    +

    Per sequence quality scores
    +

    +
    + +
    +

    Trimming

    +
    +
    +
      +
    • Trimming reads to remove adapter/readthrough or low quality bases
    • +
    • Related options are hard clipping, filtering reads
    • +
    • Sliding window trimming
    • +
    • Filter by min/max read length +
        +
      • Remove reads less than ~18nt
      • +
    • +
    • Demultiplexing/Splitting
    • +
    +

    When to avoid trimming?

    +
      +
    • Read trimming may not always be necessary Liao & Shi (2020)
    • +
    • Fixed read length may sometimes be more important
    • +
    • Expected insert size distribution may be more important for assemblers
    • +
    +

    Cutadapt, fastp, Prinseq

    +
    +

    +
    +
    +
    +
    +

    Mapping

    +

    +
      +
    • Aligning reads back to a reference sequence
    • +
    • Mapping to genome vs transcriptome
    • +
    • Splice-aware alignment (genome) (STAR, HISAT2 etc)
    • +
    +

    STAR, HiSat2, Baruzzo et al. (2017)

    +
    +
    +

    Aligners • Metrics

    +
    +
    +

    +
    +

    +

    +
    +
    +

    Baruzzo et al. (2017)

    +
    +
    +

    Aligners time and RAM

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ProgramTime_MinMemory_GB
    HISATx122.74.3
    HISATx247.74.3
    HISAT26.74.3
    STAR2528
    STARx250.528
    GSNAP291.920.2
    TopHat211704.3
    +
    +
    +

    Mapping

    +
      +
    • Reads (FASTQ)
    • +
    +
    @ST-E00274:179:HHYMLALXX:8:1101:1641:1309 1:N:0:NGATGT
    +NCATCGTGGTATTTGCACATCTTTTCTTATCAAATAAAAAGTTTAACCTACTCAGTTATGCGCATACGTTTTTTGATGGCATTTCCATAAACCGATTTTTTTTTTATGCACGTACCCAAAACGTGCAGAAAAATACGCTGCTAGAAATGTA
    ++
    +#AAAFAFA<-AFFJJJAFA-FFJJJJFFFAJJJJ-<FFJJJ-A-F-7--FA7F7-----FFFJFA<FFFFJ<AJ--FF-A<A-<JJ-7-7-<FF-FFFJAFFAA--A--7FJ-7----77-A--7F7)---7F-A----7)7-----7<<-
    +

    @instrument:runid:flowcellid:lane:tile:xpos:ypos read:isfiltered:controlnumber:sampleid

    +
      +
    • Reference Genome/Transcriptome (FASTA)
    • +
    +
    >1 dna:chromosome chromosome:GRCz10:1:1:58871917:1 REF
    +GATCTTAAACATTTATTCCCCCTGCAAACATTTTCAATCATTACATTGTCATTTCCCCTC
    +CAAATTAAATTTAGCCAGAGGCGCACAACATACGACCTCTAAAAAAGGTGCTGTAACATG
    +
      +
    • Annotation (GTF/GFF)
    • +
    +
    #!genome-build GRCz10
    +#!genebuild-last-updated 2016-11
    +4       ensembl_havana  gene    6732    52059   .       -       .       gene_id "ENSDARG00000104632"; gene_version "2"; gene_name "rerg"; gene_source "ensembl_havana"; gene_biotype "protein_coding"; havana_gene "OTTDARG00000044080"; havana_gene_version "1";
    +

    seq source feature start end score strand frame attribute

    +

    Illumina FASTQ format, GTF format

    +
    +
    +

    Alignment

    +
      +
    • SAM/BAM (Sequence Alignment Map format)
    • +
    +
    ST-E00274:188:H3JWNCCXY:4:1102:32431:49900      163     1       1       60      8S139M4S      =       385     535     TATTTAGAGATCTTAAACATCCATTCCCCCTGCAAACATTTTCAATCATTACATTGTCATTTTCCCTCCAAATTAAATTTAGCCAGAGGCGCACAACATACGACCTCTAAAAAAGGTGCTGGAACATGTACCTATATGCAGCACCACCATC     AAAFAFFAFFFFJ7FFFFJ<JAFA7F-<AJ7JJ<FFFJ--<FAJF<7<7FAFJ-<AFA<-JJJ-AF-AJ-FF<F--A<FF<-7777-7JA-77A---F-7AAFF-FJA--77FJ<--77)))7<JJA<J77<-------<7--))7)))7-    NM:i:4   MD:Z:12T0T40C58T25      AS:i:119        XS:i:102        XA:Z:17,-53287490,4S33M4D114M,11;     MQ:i:60 MC:Z:151M       RG:Z:ST-E00274_188_H3JWNCCXY_4
    +

    query flag ref pos mapq cigar mrnm mpos tlen seq qual opt

    +

    Never store alignment files in raw SAM format. Always compress it! SAM format

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FormatSize_GB
    SAM7.4
    BAM1.9
    CRAM lossless Q1.4
    CRAM 8 bins Q0.8
    CRAM no Q0.26
    +
    +
    +

    Visualisation • IGV

    + +

    IGV, UCSC Genome Browser, SeqMonk

    +
    +
    +

    Visualisation • tview

    +

    samtools tview alignment.bam genome.fasta

    + +
    +
    +

    Visualisation • SeqMonk

    + +

    SeqMonk

    +
    +
    +

    Alignment QC

    +
      +
    • Number of reads mapped/unmapped/paired etc
    • +
    • Uniquely mapped
    • +
    • Insert size distribution
    • +
    • Coverage
    • +
    • Gene body coverage
    • +
    • Biotype counts / Chromosome counts
    • +
    • Counts by region: gene/intron/non-genic
    • +
    • Sequencing saturation
    • +
    • Strand specificity
    • +
    +

    STAR (final log file), samtools stats, bamtools stats, QoRTs, RSeQC, Qualimap

    +
    +
    +

    Alignment QC • STAR Log

    +

    MultiQC can be used to summarise and plot STAR log files.

    + +
    +
    +

    Alignment QC • Features

    +

    QoRTs was run on all samples and summarised using MultiQC.

    + +
    +
    +

    Alignment QC • QoRTs

    + +
    +
    +

    Alignment QC • Examples

    +
    +
    +

    Read mapping profile

    +
    +

    Gene body coverage
    +Sigurgeirsson et al. (2014)

    +
    +
    + +
    +
    +

    Alignment QC • Examples

    +
    +
    +

    Insert size
    +

    +
    +

    Saturation curve
    +

    +

    Francis et al. (2013)

    +
    +
    + +
    +
    +

    Quantification • Counts

    +
    +
    +
      +
    • Read counts = gene expression
    • +
    • Reads can be quantified on any feature (gene, transcript, exon etc)
    • +
    • Intersection on gene models
    • +
    • Gene/Transcript level
    • +
    +

    +

    featureCounts, HTSeq

    +
    +

    +
    +
    +
    +
    +

    Quantification

    +
    +
    +

    PCR duplicates

    +
      +
    • Computational deduplication not recommended Klepikova et al. (2017), Parekh et al. (2016)
    • +
    • Use PCR-free library-prep kits
    • +
    • Use UMIs during library-prep Fu et al. (2018)
    • +
    +

    Multi-mapping

    +
      +
    • Added (BEDTools multicov)
    • +
    • Discard (featureCounts, HTSeq)
    • +
    • Distribute counts (Cufflinks, featureCounts)
    • +
    • Rescue +
        +
      • Probabilistic assignment (Rcount, Cufflinks)
      • +
      • Prioritise features (Rcount)
      • +
      • Probabilistic assignment with EM (RSEM)
      • +
    • +
    +
    +

    +
    +
    + +
    +
    +

    Quantification • Abundance

    +
      +
    • Count methods +
        +
      • Provide no inference on isoforms
      • +
      • Cannot accurately measure fold change
      • +
    • +
    + +
      +
    • Probabilistic assignment +
        +
      • Deconvolute ambiguous mappings
      • +
      • Transcript-level
      • +
      • cDNA reference
      • +
    • +
    +

    Kallisto, Salmon

    +
      +
    • Ultra-fast & alignment-free
    • +
    • Bootstrapping & quantification confidence
    • +
    • Transcript-level counts
    • +
    • Transcript-level estimates improves gene-level estimates Soneson et al. (2015), tximport
    • +
    • Evaluation and comparison of isoform quantification tools Zhang et al. (2017)
    • +
    +

    RSEM, Kallisto, Salmon

    + +
    +
    +

    Quantification QC

    +
    ENSG00000000003    140   242   188   143   287   344   438   280   253
    +ENSG00000000005    0     0     0     0     0     0     0     0     0
    +ENSG00000000419    69    98    77    55    52    94    116   79    69
    +ENSG00000000457    56    75    104   79    157   205   183   178   153
    +ENSG00000000460    33    27    23    19    27    42    69    44    40
    +
    +
    +
      +
    • Pairwise correlation between samples must be high (>0.9)
    • +
    +

    +
    +
      +
    • Count QC using RNASeqComp
    • +
    +

    +

    RNASeqComp, Teng et al. (2016)

    +
    +
    +
    +
    +

    MultiQC

    + +
    +
    +

    Normalisation

    +
      +
    • Control for Sequencing depth, compositional bias and more
    • +
    • Median of Ratios (DESeq2) and TMM (edgeR) perform the best
    • +
    +

    +
      +
    • For DGE using DGE packages, use raw counts
    • +
    • For clustering, heatmaps etc use VST, VOOM or RLOG
    • +
    • For own analysis, plots etc, use TPM
    • +
    • Other solutions: spike-ins/house-keeping genes
    • +
    +

    +

    Dillies et al. (2013), Evans et al. (2018), Wagner et al. (2012)

    +
    +
    +

    Exploratory

    +
    +
    +
      +
    • Remove lowly expressed genes
    • +
    • Heatmaps, MDS, PCA etc.
    • +
    +

    +

    pheatmap

    +
    +
      +
    • Transform raw counts to VST, VOOM, RLOG, TPM etc
    • +
    +

    +
    +
    +
    +
    +

    Batch correction

    +
      +
    • Estimate variation explained by variables (PVCA)
    • +
    + +
      +
    • Find confounding effects as surrogate variables (SVA)
    • +
    • Model known batches in the LM/GLM model
    • +
    • Correct known batches (ComBat from SVA)(Only if you are desperate! Zindler et al. (2020))
    • +
    • Interactively evaluate batch effects and correction (BatchQC) Manimaran et al. (2016)
    • +
    +
    +
    +

    Differential expression

    + +
      +
    • Univariate testing gene-by-gene
    • +
    • More descriptive, less predictive
    • +
    +
    +
    +

    Differential expression

    +
      +
    • DESeq2, edgeR (Neg-binom > GLM > Test)
    • +
    • Limma-Voom (Neg-binom > Voom-transform > LM > Test)
    • +
    • DESeq2 ~age+condition +
        +
      • Estimate size factors estimateSizeFactors()
      • +
      • Estimate gene-wise dispersion estimateDispersions()
      • +
      • Fit curve to gene-wise dispersion estimates
      • +
      • Shrink gene-wise dispersion estimates
      • +
      • GLM fit for each gene
      • +
      • Wald test nbinomWaldTest()
      • +
    • +
    + +

    DESeq2, edgeR, limma, Seyednasrollah et al. (2015)

    +
    +
    +

    DGE

    +
      +
    • Results results()
    • +
    +
    log2 fold change (MLE): type type2 vs control
    +Wald test p-value: type type2 vs control
    +DataFrame with 1 row and 6 columns
    +                        baseMean     log2FoldChange             lfcSE
    +                       <numeric>          <numeric>         <numeric>
    +ENSG00000000003 242.307796723287 -0.932926089608546 0.114285150312285
    +                             stat               pvalue                 padj
    +                        <numeric>            <numeric>            <numeric>
    +ENSG00000000003 -8.16314356729037 3.26416150242775e-16 1.36240609998527e-14
    +
      +
    • Summary summary()
    • +
    +
    out of 17889 with nonzero total read count
    +adjusted p-value < 0.1
    +LFC > 0 (up)       : 4526, 25%
    +LFC < 0 (down)     : 5062, 28%
    +outliers [1]       : 25, 0.14%
    +low counts [2]     : 0, 0%
    +(mean count < 3)
    +
    +
    +

    DGE

    +
    +
    +
      +
    • MA plot plotMA()
    • +
    +

    +
      +
    • Volcano plot
    • +
    +

    +
    +
      +
    • Normalised counts plotCounts()
    • +
    +

    +

    +
    +
    +
    +
    +

    Functional analysis • GO

    +
      +
    • Gene set analysis (GSA)
    • +
    • Gene set enrichment analysis (GSEA)
    • +
    • Gene ontology / Reactome databases
    • +
    +

    +

    +
    +
    +

    Functional analysis • Kegg

    +
      +
    • Pathway analysis (Kegg)
    • +
    + +

    DAVID, clusterProfiler, ClueGO, ErmineJ, pathview

    +
    +
    +

    Summary

    +
      +
    • Sound experimental design to avoid confounding
    • +
    • Plan carefully about lib prep, sequencing etc based on experimental objective
    • +
    • For DGE, biological replicates may be more important than other considerations (paired-end, sequencing depth, long reads etc)
    • +
    • Discard low quality bases, reads, genes and samples
    • +
    • Verify that tools and methods align with data assumptions
    • +
    • Experiment with multiple pipelines and tools
    • +
    • QC! QC everything at every step
    • +
    +
    +

    Conesa, A., Madrigal, P., Tarazona, S., Gomez-Cabrero, D., Cervera, A., McPherson, A., … & Mortazavi, A. (2016). A survey of best practices for RNA-seq data analysis. Genome biology, 17(1), 1-19.

    +
    +
    +
    +

    Further learning

    + +

    +
    +
    +

    +
    +

    Thank you. Questions?

    +
    +
    +
    +

    References

    +
    +
    +Baruzzo, G., Hayer, K. E., Kim, E. J., Di Camillo, B., FitzGerald, G. A., & Grant, G. R. (2017). Simulation-based comprehensive benchmarking of RNA-seq aligners. Nature Methods, 14(2), 135–139. https://www.nature.com/articles/nmeth.4106 +
    +
    +Chhangawala, S., Rudy, G., Mason, C. E., & Rosenfeld, J. A. (2015). The impact of read length on quantification of differentially expressed genes and splice junction detection. Genome Biology, 16(1), 1–10. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4531809/ +
    +
    +Conesa, A., Madrigal, P., Tarazona, S., Gomez-Cabrero, D., Cervera, A., McPherson, A., Szcześniak, M. W., Gaffney, D. J., Elo, L. L., Zhang, X., et al. (2016). A survey of best practices for RNA-seq data analysis. Genome Biology, 17(1), 1–19. +
    +
    +Corley, S. M., MacKenzie, K. L., Beverdam, A., Roddam, L. F., & Wilkins, M. R. (2017). Differentially expressed genes from RNA-seq and functional enrichment results are affected by the choice of single-end versus paired-end reads and stranded versus non-stranded protocols. BMC Genomics, 18(1), 1–13. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5442695/ +
    +
    +Daley, T., & Smith, A. D. (2013). Predicting the molecular complexity of sequencing libraries. Nature Methods, 10(4), 325–327. https://www.nature.com/articles/nmeth.2375 +
    +
    +Dillies, M.-A., Rau, A., Aubert, J., Hennequet-Antier, C., Jeanmougin, M., Servant, N., Keime, C., Marot, G., Castel, D., Estelle, J., et al. (2013). A comprehensive evaluation of normalization methods for illumina high-throughput RNA sequencing data analysis. Briefings in Bioinformatics, 14(6), 671–683. +
    +
    +Evans, C., Hardin, J., & Stoebel, D. M. (2018). Selecting between-sample RNA-seq normalization methods from the perspective of their assumptions. Briefings in Bioinformatics, 19(5), 776–792. +
    +
    +Francis, W. R., Christianson, L. M., Kiko, R., Powers, M. L., Shaner, N. C., & D Haddock, S. H. (2013). A comparison across non-model animals suggests an optimal sequencing depth for de novotranscriptome assembly. BMC Genomics, 14(1), 1–12. https://bmcgenomics.biomedcentral.com/articles/10.1186/1471-2164-14-167 +
    +
    +Fu, Y., Wu, P.-H., Beane, T., Zamore, P. D., & Weng, Z. (2018). Elimination of PCR duplicates in RNA-seq and small RNA-seq using unique molecular identifiers. Bmc Genomics, 19, 1–14. +
    +
    +Gallego Romero, I., Pai, A. A., Tung, J., & Gilad, Y. (2014). RNA-seq: Impact of RNA degradation on transcript quantification. BMC Biology, 12(1), 1–13. https://bmcbiol.biomedcentral.com/articles/10.1186/1741-7007-12-42 +
    +
    +Hart, S. N., Therneau, T. M., Zhang, Y., Poland, G. A., & Kocher, J.-P. (2013). Calculating sample size estimates for RNA sequencing data. Journal of Computational Biology, 20(12), 970–978. https://www.liebertpub.com/doi/10.1089/cmb.2012.0283 +
    +
    +Hsieh, P.-H., Oyang, Y.-J., & Chen, C.-Y. (2019). Effect of de novo transcriptome assembly on transcript quantification. Scientific Reports, 9(1), 8304. https://www.nature.com/articles/s41598-019-44499-3 +
    +
    +Klepikova, A. V., Kasianov, A. S., Chesnokov, M. S., Lazarevich, N. L., Penin, A. A., & Logacheva, M. (2017). Effect of method of deduplication on estimation of differential gene expression using RNA-seq. PeerJ, 5, e3091. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5357343/ +
    +
    +Levin, J. Z., Yassour, M., Adiconis, X., Nusbaum, C., Thompson, D. A., Friedman, N., Gnirke, A., & Regev, A. (2010). Comprehensive comparative analysis of strand-specific RNA sequencing methods. Nature Methods, 7(9), 709–715. https://www.nature.com/articles/nmeth.1491 +
    +
    +Liao, Y., & Shi, W. (2020). Read trimming is not required for mapping and quantification of RNA-seq reads at the gene level. NAR Genomics and Bioinformatics, 2(3), lqaa068. https://pubmed.ncbi.nlm.nih.gov/33575617/ +
    +
    +Liu, Y., Zhou, J., & White, K. P. (2014). RNA-seq differential expression studies: More sequence or more replication? Bioinformatics, 30(3), 301–304. https://academic.oup.com/bioinformatics/article/30/3/301/228651 +
    +
    +Manimaran, S., Selby, H. M., Okrah, K., Ruberman, C., Leek, J. T., Quackenbush, J., Haibe-Kains, B., Bravo, H. C., & Johnson, W. E. (2016). BatchQC: Interactive software for evaluating sample and batch effects in genomic data. Bioinformatics, 32(24), 3836–3838. +
    +
    +Marioni, J. C., Mason, C. E., Mane, S. M., Stephens, M., & Gilad, Y. (2008). RNA-seq: An assessment of technical reproducibility and comparison with gene expression arrays. Genome Research, 18(9), 1509–1517. https://genome.cshlp.org/content/18/9/1509.long +
    +
    +Parekh, S., Ziegenhain, C., Vieth, B., Enard, W., & Hellmann, I. (2016). The impact of amplification on differential expression analyses by RNA-seq. Scientific Reports, 6(1), 25533. https://www.nature.com/articles/srep25533 +
    +
    +Roberts, A., Trapnell, C., Donaghey, J., Rinn, J. L., & Pachter, L. (2011). Improving RNA-seq expression estimates by correcting for fragment bias. Genome Biology, 12(3), 1–14. +
    +
    +Schurch, N. J., Schofield, P., Gierliński, M., Cole, C., Sherstnev, A., Singh, V., Wrobel, N., Gharbi, K., Simpson, G. G., Owen-Hughes, T., et al. (2016). How many biological replicates are needed in an RNA-seq experiment and which differential expression tool should you use? Rna, 22(6), 839–851. https://rnajournal.cshlp.org/content/early/2016/03/30/rna.053959.115.abstract +
    +
    +Seyednasrollah, F., Laiho, A., & Elo, L. L. (2015). Comparison of software packages for detecting differential expression in RNA-seq studies. Briefings in Bioinformatics, 16(1), 59–70. +
    +
    +Sigurgeirsson, B., Emanuelsson, O., & Lundeberg, J. (2014). Sequencing degraded RNA addressed by 3’tag counting. PloS One, 9(3), e91851. https://pubmed.ncbi.nlm.nih.gov/24632678/ +
    +
    +Soneson, C., Love, M. I., & Robinson, M. D. (2015). Differential analyses for RNA-seq: Transcript-level estimates improve gene-level inferences. F1000Research, 4. +
    +
    +Teng, M., Love, M. I., Davis, C. A., Djebali, S., Dobin, A., Graveley, B. R., Li, S., Mason, C. E., Olson, S., Pervouchine, D., et al. (2016). A benchmark for RNA-seq quantification pipelines. Genome Biology, 17(1), 1–12. +
    +
    +Wagner, G. P., Kin, K., & Lynch, V. J. (2012). Measurement of mRNA abundance using RNA-seq data: RPKM measure is inconsistent among samples. Theory in Biosciences, 131, 281–285. +
    +
    +Wang, S., & Gribskov, M. (2017). Comprehensive evaluation of de novo transcriptome assembly programs and their effects on differential gene expression analysis. Bioinformatics, 33(3), 327–333. https://academic.oup.com/bioinformatics/article/33/3/327/2580374 +
    +
    +Zhang, C., Zhang, B., Lin, L.-L., & Zhao, S. (2017). Evaluation and comparison of computational tools for RNA-seq isoform quantification. BMC Genomics, 18(1), 1–11. +
    +
    +Zhao, S., Li, C.-I., Guo, Y., Sheng, Q., & Shyr, Y. (2018). RnaSeqSampleSize: Real data based sample size estimation for RNA sequencing. BMC Bioinformatics, 19(1), 1–8. https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-018-2191-5 +
    +
    +Zhao, S., Zhang, Y., Gordon, W., Quan, J., Xi, H., Du, S., Schack, D. von, & Zhang, B. (2015). Comparison of stranded and non-stranded RNA-seq transcriptome profiling and investigation of gene overlap. BMC Genomics, 16(1), 1–14. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4559181/ +
    +
    +Zindler, T., Frieling, H., Neyazi, A., Bleich, S., & Friedel, E. (2020). Simulating ComBat: How batch correction can lead to the systematic introduction of false positive results in DNA methylation microarray studies. BMC Bioinformatics, 21, 1–15. +
    +
    +
    +
    +

    Hands-On tutorial

    +

    Main exercise

    +
      +
    • 01 Check the quality of the raw reads with FastQC
    • +
    • 02 Map the reads to the reference genome using HISAT2
    • +
    • 03 Assess the post-alignment quality using QualiMap
    • +
    • 04 Count the reads overlapping with genes using featureCounts
    • +
    • 05 Find differentially expressed genes using DESeq2 in R
    • +
    +

    Bonus exercises

    +
      +
    • 01 Functional annotation of DE genes using GO/Reactome/Kegg databases
    • +
    • 02 RNA-Seq figures and plots using R
    • +
    • 03 Visualisation of RNA-seq BAM files using IGV genome browser
    • +
    +

    Data: /sw/courses/ngsintro/rnaseq/
    +Work: /proj/naiss2023-22-862/nobackup/user/rnaseq/

    +
    +
    +

    Hands-On tutorial

    +
    +
    +
      +
    • Course data directory
    • +
    +

    /sw/courses/ngsintro/rnaseq/

    +
    rnaseq/
    ++-- bonus/
    +|   +-- assembly/
    +|   +-- exon/
    +|   +-- funannot/
    +|   +-- plots/
    ++-- documents/
    ++-- main/
    +    +-- 1_raw/
    +    +-- 2_fastqc/
    +    +-- 3_mapping/
    +    +-- 4_qualimap/
    +    +-- 5_dge/
    +    +-- 6_multiqc/
    +    +-- reference/
    +    |   +-- mouse_chr19_hisat2/
    +    +-- scripts/
    +
    +
      +
    • Your work directory
    • +
    +

    /proj/naiss2023-22-862/nobackup/user/rnaseq/

    +
    [user]/
    +rnaseq/
    +  +-- 1_raw/
    +  +-- 2_fastqc/
    +  +-- 3_mapping/
    +  +-- 4_qualimap/
    +  +-- 5_dge/
    +  +-- 6_multiqc/
    +  +-- reference/
    +  |   +-- mouse_chr19_hisat2/
    +  +-- scripts/
    +  +-- funannot/
    +  +-- plots/
    +
    +
    + + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/2311/topics/uppmax/intro/assets/bam_binary.png b/2311/topics/uppmax/intro/assets/bam_binary.png new file mode 100644 index 00000000..1e137c10 Binary files /dev/null and b/2311/topics/uppmax/intro/assets/bam_binary.png differ diff --git a/2311/topics/uppmax/intro/lab_uppmax_intro.html b/2311/topics/uppmax/intro/lab_uppmax_intro.html new file mode 100644 index 00000000..2388d755 --- /dev/null +++ b/2311/topics/uppmax/intro/lab_uppmax_intro.html @@ -0,0 +1,750 @@ + + + + + + + + + + +Uppmax Introduction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Uppmax Introduction

    +

    High-performance computing cluster: UPPMAX

    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Martin Dahlö

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    In code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window.

    +
    +
    +
    +

    1 Connect to UPPMAX

    +

    The first step of this lab is to open a ssh connection to UPPMAX. Please refer to Connecting to UPPMAX for instructions. Once connected to UPPMAX, return here and continue reading the instructions below.

    +
    +
    +

    2 Logon to a node

    +

    Usually you would do most of the work in this lab directly on one of the login nodes at UPPMAX, but we have arranged for you to have one core each for better performance. This was covered briefly in the lecture notes.

    +

    Check which node you got when you booked resources this morning (replace username with your UPPMAX username)

    +
    $ squeue -u username
    +

    should look something like this

    +
    dahlo@rackham2 work $ squeue -u dahlo
    +             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
    +           3132376      core       sh    dahlo  R       0:04      1 r292
    +dahlo@rackham2 work $
    +

    where r292 is the name of the node I got (yours will probably be different). Note the numbers in the Time column. They show for how long the job has been running. When it reaches the time limit you requested (7 hours in this case) the session will shut down, and you will lose all unsaved data. Connect to this node from within UPPMAX.

    +
    $ ssh -Y r292
    +

    If the list is empty you can run the allocation command again and it should be in the list:

    +
    +
    +
    salloc -A naiss2023-22-862 -t 03:30:00 -p core -n 1 --no-shell
    +
    +
    +

    There is a UPPMAX specific tool called jobinfo that supplies the same kind of information as squeue that you can use as well ($ jobinfo -u username).

    +
    +
    +

    3 Copy files for lab

    +

    Now, you will need some files. To avoid all the course participants editing the same file all at once, undoing each other’s edits, each participant will get their own copy of the needed files. The files are located in the folder /sw/courses/ngsintro/linux/uppmax_tutorial

    +

    Next, copy the lab files from this folder. -r means recursively, which means all the files including sub-folders of the source folder. Without it, only files directly in the source folder would be copied, NOT sub-folders and files in sub-folders.

    +

    Remember to use tab-complete to avoid typos and too much writing.

    +
    +
    +
    cp -r <source> <destination>
    +cp -r /sw/courses/ngsintro/linux/uppmax_tutorial /proj/naiss2023-22-862/nobackup/username
    +
    +
    +

    Have a look in /proj/naiss2023-22-862/nobackup/<username>/uppmax_tutorial.

    +
    +
    +
    cd /proj/naiss2023-22-862/nobackup/username/uppmax_tutorial
    +
    +
    +
    $ ll
    +total 128K
    +drwxrwxr-x 2 dahlo dahlo 2,0K May 18 16:21 .
    +drwxrwxr-x 4 dahlo dahlo 2,0K May 18 15:34 ..
    +-rwxrwxr-x 1 dahlo dahlo 1,2K May 18 16:21 data.bam
    +-rw-rw-r-- 1 dahlo dahlo  232 May 18 16:21 job_template
    +$
    +
    +
    +

    4 Run programs

    +

    Among the files that were copied is data.bam. BAM is a popular format to store aligned sequence data, but since it is a, so called, binary format it doesn’t look that good if you are human. Try it using less:

    +
    $ less data.bam
    +
    +
    +

    +
    +
    +

    Not so pretty.. Luckily for us, there is a program called samtools that is made for reading BAM files. To use it on UPPMAX we must first load the module for samtools. Try starting samtools before loading the module.

    +
    $ samtools
    +-bash: samtools: command not found
    +$
    +

    That did not work, try it again after loading the module:

    +
    $ module load bioinfo-tools samtools/1.10
    +$ samtools
    +
    +Program: samtools (Tools for alignments in the SAM format)
    +Version: 1.10 (using htslib 1.10)
    +
    +Usage:   samtools <command> [options]
    +
    +Commands:
    +  -- Indexing
    +     dict           create a sequence dictionary file
    +     faidx          index/extract FASTA
    +     fqidx          index/extract FASTQ
    +     index          index alignment
    +
    +  -- Editing
    +     calmd          recalculate MD/NM tags and '=' bases
    +     fixmate        fix mate information
    +     reheader       replace BAM header
    +     targetcut      cut fosmid regions (for fosmid pool only)
    +     addreplacerg   adds or replaces RG tags
    +     markdup        mark duplicates
    +
    +  -- File operations
    +     collate        shuffle and group alignments by name
    +     cat            concatenate BAMs
    +     merge          merge sorted alignments
    +     mpileup        multi-way pileup
    +     sort           sort alignment file
    +     split          splits a file by read group
    +     quickcheck     quickly check if SAM/BAM/CRAM file appears intact
    +     fastq          converts a BAM to a FASTQ
    +     fasta          converts a BAM to a FASTA
    +
    +  -- Statistics
    +     bedcov         read depth per BED region
    +     coverage       alignment depth and percent coverage
    +     depth          compute the depth
    +     flagstat       simple stats
    +     idxstats       BAM index stats
    +     phase          phase heterozygotes
    +     stats          generate stats (former bamcheck)
    +
    +  -- Viewing
    +     flags          explain BAM flags
    +     tview          text alignment viewer
    +     view           SAM<->BAM<->CRAM conversion
    +     depad          convert padded BAM to unpadded BAM
    +

    All modules are unloaded when you disconnect from UPPMAX, so you will have to load the modules again every time you log in. If you load a module in a terminal window, it will not affect the modules you have loaded in another terminal window, even if both terminals are connected to UPPMAX. Each terminal is independent of the others.

    +

    To use samtools to view a BAM file, use the following line.

    +
    $ samtools view -h data.bam
    +@HD VN:1.0  SO:coordinate
    +@SQ SN:chr1 LN:249250621
    +@SQ SN:chr10    LN:135534747
    +@SQ SN:chr11    LN:135006516
    +@SQ SN:chr12    LN:133851895
    +@SQ SN:chr13    LN:115169878
    +@SQ SN:chr14    LN:107349540
    +@SQ SN:chr15    LN:102531392
    +@SQ SN:chr16    LN:90354753
    +

    -h also print the BAM file’s header, which is the rows starting with @ signs in the beginning of the file. These lines contain so called metadata; information about the data stored in the file. It contain things like which program was used to generate the BAM file and which chromosomes are present in the file. Try running the command without the -h to see the difference.

    +

    The not-binary version (ASCII, or text version) of a BAM file is called a SAM file, which was just printed directly into the terminal window. The SAM file is not to much use for us printed in the terminal window, aesthetics aside. It is probably much better to have the SAM file saved as an actual file, something that is very easy to do. Any text that is printed to the terminal can be saved to a file instead of the terminal window using a ‘crocodile mouth’, >

    +
    $ program arguments > outfile
    +

    which will launch a program named program, supply it with the argument arguments, and write any output that would have been printed to the screen to the file outfile instead.

    +

    To use this on samtools,

    +
    $ samtools view -h data.bam > data.sam
    +

    Look at the created file:

    +
    $ ll
    +

    The SAM file is now human readable. Try viewing it with less:

    +
    $ less data.sam
    +

    You can also edit the file with nano:

    +
    $ nano data.sam
    +

    Try deleting the whole last line in the file, save it, and exit nano.

    +
    +
    +

    5 Modules

    +

    To view which module you have loaded at the moment, type

    +
    $ module list
    +
    +Currently Loaded Modules:
    +  1) uppmax   2) bioinfo-tools   3) samtools/1.10
    +

    Let’s say that you want to make sure you are using the latest version samtools. Look at which version you have loaded at the moment (samtools/1.10).

    +

    Now type

    +
    $ module avail
    +

    to see which programs are available at UPPMAX. Can you find samtools in the list? Which is the latest version of samtools available at UPPMAX?

    +

    To change which samtools module you have loaded, you have to unload the the module you have loaded and then load the other module. To unload a module, use

    +
    $ module unload <module name>
    +

    Look in the list from $ module list to see the name of the module you want to unload. When the old module is unloaded, load samtools/0.1.19 (or try with the latest samtools module!).

    +
    +
    +

    6 Submitting a job

    +

    Not all jobs are as small as converting this tiny BAM file to a SAM file. Usually the BAM files are several gigabytes, and can take hours to convert to SAM files. You will not have reserved nodes waiting for you to do something either, so running programs is done by submitting a job to the queue system. What you submit to the queue system is a script file that will be executed as soon as it reaches the front of the queue. The scripting language used in these scripts is bash, which is the same language as you usually use in a terminal i.e. everything so far in the lecture and lab has been in the bash language (cd, ls, cp, mv, etc.).

    +

    Have a look at job_template in your uppmax_tutorial folder.

    +
    $ less job_template
    +
    +#! /bin/bash -l
    +#SBATCH -A gXXXXXXX
    +#SBATCH -p core
    +#SBATCH -J Template_script
    +#SBATCH -t 01:00:00
    +
    +# load some modules
    +module load bioinfo-tools
    +
    +# go to some directory
    +cd /proj/gXXXXXXX/nobackup/
    +
    +# do something
    +echo Hello world!
    +

    Edit this file to make the job convert data.bam to a SAM file named jobData.sam. Remember how the queue works? Try to approximate the runtime of the job (almost instant in this case) and increase it by ~50%, and use that time approximation when writing your script file. Longer jobs will wait longer in the queue because it is harder to fit them into gaps in the queue! Also remember to change the project ID to match this course occasion.

    +

    Remember, just write the command you would run if you were sitting by the computer, i.e. load the correct modules, go to the correct folder, and run samtools the right way.

    +

    Submit your job using sbatch:

    +
    $ sbatch job_template
    +
    +
    +

    7 Job queue

    +

    If you want to know how your jobs are doing in the queue, you can check their status with $ squeue -u username or $ jobinfo -u username.

    +

    Rewrite the previous sbatch file so that you book 3 days of time, and to use a node instead of a core. This will cause your job to stand in the queue for a bit longer, so that we can have a look at it while it is queuing. Submit it to the queue and run jobinfo.

    +
    $ jobinfo -u username
    +
    +CLUSTER: rackham
    +Running jobs:
    +   JOBID PARTITION                      NAME     USER        ACCOUNT ST          START_TIME  TIME_LEFT  NODES CPUS NODELIST(REASON)
    + 3134399   devcore                               dahlo       g20XXXXX  R 2018-05-18T16:32:54      59:25      1    1 r483
    +
    +Nodes in use:                            462
    +Nodes in devel, free to use:               2
    +Nodes in other partitions, free to use:    4
    +Nodes available, in total:               468
    +
    +Nodes in test and repair:                 13
    +Nodes, otherwise out of service:           5
    +Nodes, all in total:                     486
    +
    +Waiting jobs:
    +   JOBID    POS PARTITION                      NAME     USER        ACCOUNT ST          START_TIME   TIME_LEFT PRIORITY CPUS NODELIST(REASON)     FEATURES DEPENDENCY
    + 3134401    221      core           Template_script    dahlo       g20XXXXX PD                 N/A     1:00:00   100000    1           (None)       (null)
    +
    +Waiting bonus jobs:
    +$
    +

    If you look under the heading “Waiting jobs:” you’ll see a list of all the jobs you have in the queue that have not started yet. The most interesting column here is the POS column, which tells you which position in the queue you have (221 in my example). When you reach the first place, your job will start as soon as there are the resources you have asked for.

    +

    In our case, we are not really interested in running this job at all. Let’s cancel it instead. This can be done with the command scancel. Syntax:

    +
    $ scancel <job id>
    +

    You see the job id number in the output from jobinfo or squeue.

    +
    $ scancel 3134401
    +
    +
    +

    8 Interactive jobs

    +

    Sometimes it is more convenient to work interactively on a node instead of submitting your work as a job. Since you will not have the reservations we have during the course, you will have to book a node using the interactive command. Syntax:

    +
    $ interactive -A <project id> -t <time> -p <node or core>
    +

    This will create a booking for you which has a higher priority than the jobs submitted with sbatch. That means that they will start faster, but only if the booking is shorter than 12 hours. If the booking is longer than 12 hours, it will get the standard priority. When the job starts you will be transferred to the node you got automatically. No need to look which node you got using sbatch and then ssh:ing to it.

    +

    Try closing down your current session on the reserved node you connected to in the beginning of the lab by typing exit. Then make a new booking using interactive,

    +
    +
    +
    interactive -A naiss2023-22-862 -t 02:30:00 -p core
    +
    +
    +

    Congratulations, you are now ready to be let loose on the cluster!

    +
    +
    +

    9 Extra

    +

    Extra material if you finish too fast.

    +
    +

    9.1 The devel queue

    +

    If it is a really big job, it might be in the queue for a day or two before it starts, so it is important to know that the first thing it does is not crashing because you made a typo on line 7. One way to test this is to open a new connection to UPPMAX, and line by line try your code. Copy-paste (Ctrl+Shift+c and Ctrl+Shift+v in the terminal window) to make sure it’s really the code in the script you are trying.

    +

    If your script is longer than a couple of lines, this approach can be tiring. There are 12 nodes at UPPMAX that are dedicated to do quick test runs, which have a separate queue called devel. They are available for use more or less all the time since not very many are using them. To avoid people abusing the free nodes for their analysis, there is a 1 hour time limit for jobs on them. To submit jobs to this short testing queue, change -p to devel instead of node or core, and make sure -t is set to maximum 01:00:00. Try submitting the samtools sbatch file we used earlier to the devel queue and run it again.

    +
    +
    +

    9.2 Info about finished jobs

    +

    If you want information about jobs you have run in the past, you can use the tool finishedjobinfo. It will print information about the jobs you have run lately.

    +

    Fun things to look for in this information is jobstate which will tell you if the program reported any error while running. If so, jobstate will be FAILED and you could suspect that something didn’t go according to the plan, and you should check the output from that job run (the slurm-.out file) and see if you can solve the error.

    +

    Other good things to look for could be:

    +
      +
    • maxmemory_in_GiB: tells you how much memory the program used at most.
    • +
    • runtime: tells you how long time the program ran before it finished/failed
    • +
    +
    +
    +

    9.3 Time and space

    +

    Remember the commands uquota (show how much of your storage space you are using) and projinfo (shows you how much of your allocated time you have used) from the lecture? Try running them and see how you are doing.

    +
    +
    +
    + +
    +
    +Optional +
    +
    +
    +

    This optional material on uppmax pipelines will teach you the basics in creating pipelines. Continue with this if you finish the current lab ahead of time. Navigate to the exercise Uppmax Pipelines lab.

    +
    +
    + + +
    +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/2311/topics/uppmax/intro/slide_uppmax_intro.pdf b/2311/topics/uppmax/intro/slide_uppmax_intro.pdf new file mode 100644 index 00000000..06a17559 Binary files /dev/null and b/2311/topics/uppmax/intro/slide_uppmax_intro.pdf differ diff --git a/2311/topics/uppmax/pipeline/assets/dualTerminals.png b/2311/topics/uppmax/pipeline/assets/dualTerminals.png new file mode 100644 index 00000000..45f6332a Binary files /dev/null and b/2311/topics/uppmax/pipeline/assets/dualTerminals.png differ diff --git a/2311/topics/uppmax/pipeline/assets/slurmScript.png b/2311/topics/uppmax/pipeline/assets/slurmScript.png new file mode 100644 index 00000000..3084a176 Binary files /dev/null and b/2311/topics/uppmax/pipeline/assets/slurmScript.png differ diff --git a/2311/topics/uppmax/pipeline/lab_uppmax_pipeline.html b/2311/topics/uppmax/pipeline/lab_uppmax_pipeline.html new file mode 100644 index 00000000..55657626 --- /dev/null +++ b/2311/topics/uppmax/pipeline/lab_uppmax_pipeline.html @@ -0,0 +1,697 @@ + + + + + + + + + + +Uppmax Pipeline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Uppmax Pipeline

    +

    Building Bioinformatic pipelines

    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Martin Dahlö

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    In code blocks, the dollar sign ($) is not to be printed. The dollar sign is usually an indicator that the text following it should be typed in a terminal window.

    +
    +
    +
    +

    1 Connect to UPPMAX

    +

    The first step of this lab is to open a ssh connection to UPPMAX. Please refer to Connecting to UPPMAX for instructions. Once connected to UPPMAX, return here and continue reading the instructions below.

    +
    +
    +

    2 Logon to a node

    +

    Usually you would do most of the work in this lab directly on one of the login nodes at UPPMAX, but we have arranged for you to have one core each for better performance. This was covered briefly in the lecture notes.

    +

    Check which node you got when you booked resources this morning (replace username with your UPPMAX username)

    +
    $ squeue -u username
    +

    should look something like this

    +
    dahlo@rackham2 work $ squeue -u dahlo
    +             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
    +           3132376      core       sh    dahlo  R       0:04      1 r292
    +dahlo@rackham2 work $
    +

    where r292 is the name of the node I got (yours will probably be different). Note the numbers in the Time column. They show for how long the job has been running. When it reaches the time limit you requested (7 hours in this case) the session will shut down, and you will lose all unsaved data. Connect to this node from within UPPMAX.

    +
    $ ssh -Y r292
    +

    If the list is empty you can run the allocation command again and it should be in the list:

    +
    +
    +
    salloc -A naiss2023-22-862 -t 03:30:00 -p core -n 1 --no-shell
    +
    +
    +

    There is a UPPMAX specific tool called jobinfo that supplies the same kind of information as squeue that you can use as well ($ jobinfo -u username).

    +
    +
    +

    3 Copy files for lab

    +

    Now, you will need some files. To avoid all the course participants editing the same file all at once, undoing each other’s edits, each participant will get their own copy of the needed files. The files are located in the folder /sw/courses/ngsintro/linux/uppmax_pipeline_exercise/data.

    +

    Next, copy the lab files from this folder. -r means recursively, which means all the files including sub-folders of the source folder. Without it, only files directly in the source folder would be copied, NOT sub-folders and files in sub-folders.

    +

    Remember to use tab-complete to avoid typos and too much writing.

    +
    +
    +
    cp -r <source> <destination>
    +cp -r /sw/courses/ngsintro/linux/uppmax_pipeline_exercise/data/* /proj/naiss2023-22-862/nobackup/username/uppmax_pipeline_exercise
    +
    +
    +

    Have a look in /proj/naiss2023-22-862/nobackup/<username>/uppmax_pipeline_exercise.

    +
    +
    +
    cd /proj/naiss2023-22-862/nobackup/username/uppmax_pipeline_exercise
    +ll
    +
    +
    +

    If you see files, the copying was successful.

    +
    +
    +

    4 Running dummy pipelines

    +

    Most of the work you will do in the future will be about running multiple programs after each other. This can be done manually, with you sitting by the computer and typing commands, waiting for them to finish, then start the next program. But what happens if the first program finished sometime during the night? You will not be there to start the next program, and the computer will stand idle until you have time to start the program.

    +

    To avoid this, scripts can be used. First, we’ll do an analysis manually without scripts, just to get the hang of it. Then we’ll start writing scripts for it!

    +
    +

    4.1 Load the module

    +

    In this exercise, we’ll pretend that we are running analyses. This will give you a peek at what running programs in linux is like, and get you ready for the real stuff during the week!

    +

    The first thing you usually do is to load the modules for the programs you want to run. During this exercise we’ll only run my dummy scripts that don’t actually do any analysis, so they don’t have a module of their own. What we can do instead is to manually do what module loading usually does: to modify the $PATH variable.

    +

    The $PATH variable specifies directories where the computer should look for programs whenever you type a command. For instance, when you type

    +
    $ nano
    +

    how does the computer know which program to start? You gave it the name nano, but that could refer to any file named nano in the computer, yet it starts the correct one every time. The answer is that it looks in the directories stored in the $PATH variable and start the first program it finds that is named nano.

    +

    To see which directories that are available by default, type

    +
    $ echo $PATH
    +

    It should give you something like this, a list of directories, separated by colon signs:

    +
    $ echo $PATH
    +/home/dahlo/perl//bin/:/home/dahlo/.pyenv/shims:/home/dahlo/.pyenv/bin:
    +/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:
    +/sbin:/opt/thinlinc/bin:/sw/uppmax/bin:/home/dahlo/usr/bin
    +

    Try loading a module, and then look at the $PATH variable again. You’ll see that there are a few extra directories there now, after the module has been loaded.

    +
    $ module load bioinfo-tools samtools/1.6
    +$ echo $PATH
    +/sw/apps/bioinfo/samtools/1.6/rackham/bin:/home/dahlo/perl/bin:/home/dahlo/.pyenv/shims:
    +/home/dahlo/.pyenv/bin:/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:
    +/usr/sbin:/sbin:/opt/thinlinc/bin:/sw/uppmax/bin:/home/dahlo/usr/bin
    +

    To pretend that we are loading a module, instead of actually loading a module for them, we’ll manually do what the module system would have done. We will just add a the directory containing my dummy scripts to the $PATH variable, and it will be like we loaded the module for them. Now, when we type the name of one of my scripts, the computer will look in all the directories specified in the $PATH variable, which now includes the location where i keep my scripts. The computer will now find programs named as my scripts are and it will run them.

    +
    $ export PATH=$PATH:/sw/courses/ngsintro/linux/uppmax_pipeline_exercise/dummy_scripts
    +

    This will set the $PATH variable to whatever it is at the moment, and add a directory at the end of it. Note the lack of a dollar sign infront of the variable name directly after export. You don’t use dollar signs when assigning values to variables, and you always use dollar signs when getting values from variables.

    +
    +

    Important

    +

    The export command affects only the terminal you type it in. If you have 2 terminals open, only the terminal you typed it in will have a modified path. If you close that terminal and open a new one, it will not have the modified path.

    +
    +

    Enough with variables now. Let’s try the scripts out!

    +
    +
    +
    +

    5 Running the programs

    +

    Let’s pretend that we want to run an exome analysis. You will learn how to do this for real later this week. This kind of analysis usually has the following steps:

    +
      +
    1. Filter out low quality reads.
    2. +
    3. Align the reads to a reference genome.
    4. +
    5. Find all the SNPs in the data.
    6. +
    +

    To simulate this, I have written 3 programs:

    +
      +
    • filter_reads
    • +
    • align_reads
    • +
    • find_snps
    • +
    +

    To find out how to run the programs type

    +
    $ <program name> -h
    +
    or
    +$ <program name> --help
    +

    This is useful to remember, since most programs has this function. If you do this for the filter program, you get

    +
    $ filter_reads -h
    +Usage: filter_reads -i <input file> -o <output file> [-c <cutoff>]
    +
    +Example runs:
    +
    +# Filter the reads in <input> using the default cutoff value. Save filtered reads to <output>
    +filter_reads -i <input> -o <output>
    +Ex.
    +filter_reads -i my_reads.rawdata.fastq -o my_reads.filtered.fastq
    +
    +# Filter the reads in <input> using a more relaxed cutoff value. Save filtered reads to <output>
    +filter_reads --input <input> --output <output> --cutoff 30
    +Ex.
    +filter_reads --input ../../my_reads.rawdata.fastq --output /home/dahlo/results/my_reads.filtered.fastq --cutoff 30
    +
    +
    +Options:
    +  -h, --help            show this help message and exit
    +  -i INPUT, --input=INPUT
    +                        The path to your unfiltered reads file.
    +  -o OUTPUT, --output=OUTPUT
    +                        The path where to put the results of the filtering.
    +  -c CUTOFF, --cutoff=CUTOFF
    +                        The cutoff value for quality. Reads below this value
    +                        will be filtered (default: 35).
    +

    This help text tells you that the program has to be run a certain way. The options -i and -o are mandatory, since they are explicitly written. The hard brackets [ ] around -c <cutoff> means that the cutoff value is NOT mandatory. They can be specified if the user wishes to change the cutoff from the default values.

    +

    Further down, in the Options: section, each of the options are explained more in detail. You can also see that each option can be specified in two way, a short and a long format. The cutoff value can be specified either by the short -c, or the long --cutoff. It doesn’t matter which format you choose, it’s completely up to you, which ever you feel more comfortable with.

    +

    Right, so now you know how to figure out how to run programs (just type the program name, followed by a -h or --help). Try doing a complete exome sequencing analysis, following the steps below.

    +

    First, go to the exome directory in the lab directory that you copied to your folder in step 2 in this lab:

    +
    +
    +
    cd /proj/naiss2023-22-862/nobackup/username/uppmax_pipeline_exercise/exomeSeq
    +
    +
    +

    In there, you will find a folder called raw_data, containing a fastq file: my_reads.rawdata.fastq. This file contains the raw data that you will analyse.

    +
      +
    • Filter the raw data using the program filter_reads, to get rid of low quality reads.
    • +
    • Align the filtered reads with the program align_reads, to the human reference genome located here:
    • +
    +
    /sw/data/uppnex/reference/Homo_sapiens/hg19/concat_rm/Homo_sapiens.GRCh37.57.dna_rm.concat.fa
    +
      +
    • Find SNPs in your aligned data with the program find_snps. To find SNPs we have to have a reference to compare our data with. The same reference genome as you aligned to is the one to use.
    • +
    +

    Do one step at a time, and check the --help of the programs to find out how they are to be run. Remember to name your files logically so that you don’t confuse them with each other.

    +

    Most pipelines work in a way where the output of the current program is the input of the next program in the pipeline. In this pipeline, raw data gets filtered, the filtered data gets aligned, and the aligned data gets searched for SNPs. The intermediate steps are usually not interesting after you have reached the end of the pipeline. Then, only the raw data and the final result is important.

    +
    +
    +

    6 Scripting a dummy pipeline

    +

    To run the pipeline in a script, just do exactly as you just did, but write the exact same commands to a file instead of directly to the terminal. When you run the script, the computer will run the script one line at a time, until it reaches the end of the file. Just like you did manually in the previous step.

    +

    The simplest way to work with scripts is to have 2 terminals open. One will have nano started where you write your script file, and the other will be on the command line where you can test your commands to make sure they work before you put them in the script. When you are sure a command works, you copy/paste it to the terminal with the script file in it.

    +

    Start writing you script with nano:

    +
    +
    +
    cd /proj/naiss2023-22-862/nobackup/username/uppmax_pipeline_exercise/exomeSeq
    +nano exome_analysis_script.sh
    +
    +
    +

    The .sh ending is commonly used for shell scripts which is what we are creating. The default shell at UPPMAX is as we know called bash, so whenever we write sh the computer will use bash. If the default shell at UPPMAX would change for some reason, maybe to zsh or any other type of shell, sh would point the the new shell instead.

    +
    +
    +

    +
    +
    +

    Since our memory is far from perfect, try to always comment your scripts. The comments are rows that start with a hash sign #. These lines will not be interpreted as a command to be run, they will just be skipped. They are only meant for humans to read, and they are real lifesavers when you are reading old scripts you have forgotten what they do. Commands are hard for humans to read, so try to write a couple of words explaining what the command below does. You’ll be thankful later!

    +

    When you are finished with your script, you can test run it. To do that, use the program sh:

    +
    $ sh exome_analysis_script.sh
    +

    If you got everything right, you should see the whole pipeline being executed without you having to start each program manually. If something goes wrong, look at the output and try to figure out which step in the pipeline that get the error, and solve it.

    +

    A tip is to read the error list from the top-down. An error early in the pipeline will most likely cause a multitude of error further down the pipeline, so your best bet is to start from the top. Solve the problem, try the script again, until it works. The real beauty of scripts is that they can be re-run really easily. Maybe you have to change a variable or option in one of the early steps of the pipeline, just do it and re-run the whole thing.

    +
    +
    +

    7 Submitting a dummy pipeline

    +

    The whole point with computer centres like UPPMAX is that you can run multiple programs at the same time to speed things up. To do this efficiently you will have to submit jobs to the queue system. As you saw in yesterday’s exercise, it is ordinary shell scripts that you submit to the queue system, with a couple of extra options in the beginning. So to be able to submit our script to the queue system, the only thing we have to do is to add the queue system options in the beginning of the script.

    +

    The options needed by the queue are, as we learned yesterday:

    +
      +
    • Who is paying for the job?
    • +
    • How long time will the job need?
    • +
    • How many cores does the job need?
    • +
    +

    SLURM is also a bit strict when it comes formalities. It requires that you specify which program should be used to run the submitted script file. The standard program for this is bash, but we have to specify it on the first line of the script non the less. This is done by having the first line in the script looking link this:

    +
    #!/bin/bash -l
    +

    This is how Linux knows which program should open a file, since it does not care about the file ending like Windows commonly does (.ppt, .pdf, .html might be familiar file endings). The #! indicates that the next words will be the path to the program that should open the file. It could be #!/bin/bash, or #!/bin/python, or any other path to a executable program.

    +

    The -l after bash is a flag that tells bash that the script should be treated as a login shell, so everything behaves as when you are logged in. Without it commands like module and some other would not work. If it’s not a login shell, it’s running as a script, and then it does not need to bother making the interface human friendly so it will skip things to make it start faster and consume less resources.

    +

    The next couple of rows will contain all the options you want to give SLURM:

    +
    +
    +
    #!/bin/bash -l
    +#SBATCH -A naiss2023-22-862
    +#SBATCH -t 00:05:00
    +#SBATCH -p core
    +
    +
    +

    SLURM options always start with #SBATCH followed by a flag (-A for account, -t for time, -p for partition) and the value for that flag. Your script should now look something like this (ignore the old project id and path to the scripts):

    +
    +
    +

    +
    +
    +

    To submit this script to the queue:

    +
    $ sbatch exome_analysis_script.sh
    +
    +
    +

    8 RNAseq Analysis

    +

    The next step is to do a complete RNAseq analysis. The steps involved start off just like the exome analysis, but has a few extra steps. The goal of this part is to successfully run the pipeline using the queue system. To do this, you must construct the commands for each step, combine them in a script, include the SLURM options, and submit it. Much like what we did in the previous step, but with some complications.

    +

    Typical RNAseq analysis consists of multiple samples / time points:

    +
      +
    • Filter the reads for each sample.
    • +
    • Align the filtered reads for each sample to the same reference genome as before.
    • +
    • Do a differential expression analysis by comparing multiple samples.
    • +
    +

    The difficulty here is that you have not just 1 sample, you have 3 of them. And they all need to be filtered and aligned separately, and then compared to each other. The program that does the differential expression analysis in this exercise is called diff_exp and is located in the same directory as the previous scripts. The samples are filtered and aligned individually.

    + + +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/2311/topics/vc/assets/1_onesamplevc.png b/2311/topics/vc/assets/1_onesamplevc.png new file mode 100644 index 00000000..34b39749 Binary files /dev/null and b/2311/topics/vc/assets/1_onesamplevc.png differ diff --git a/2311/topics/vc/assets/2_jointvc.png b/2311/topics/vc/assets/2_jointvc.png new file mode 100644 index 00000000..7959a8c0 Binary files /dev/null and b/2311/topics/vc/assets/2_jointvc.png differ diff --git a/2311/topics/vc/assets/3_best_practise.png b/2311/topics/vc/assets/3_best_practise.png new file mode 100644 index 00000000..5840c92a Binary files /dev/null and b/2311/topics/vc/assets/3_best_practise.png differ diff --git a/2311/topics/vc/lab_vc.html b/2311/topics/vc/lab_vc.html new file mode 100644 index 00000000..fc3ce869 --- /dev/null +++ b/2311/topics/vc/lab_vc.html @@ -0,0 +1,1396 @@ + + + + + + + + + + +Variant Calling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Variant Calling

    +

    From reads to short variants

    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Malin Larsson

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +

    Introduction

    +

    Whole genome sequencing (WGS) is a comprehensive method for analyzing entire genomes. This workshop will take you through the process of calling germline short variants (SNVs and INDELs) in WGS data from three human samples.

    +
      +
    1. The first part of the workshop will guide you through a basic variant calling workflow in one sample. The goals are that you should get familiar with the bam and vcf file formats, and be able to interpret vcf files in Integrative Genomics Viewer (IGV).
    2. +
    3. If you have time, the next part of the workshop will show you how to perform joint variant calling in three samples. The goals here are that you should be able to interpret multi-sample vcf files and explain the differences between the g.vcf and vcf file formats.
    4. +
    5. If you have time, the last part of the workshop will take you through the GATK best practices for germline short variant detection in three samples. The goal here is that you should learn how to use GATK’s documentation so that you can analyze your own samples in the future.
    6. +
    +
    +
    +
    + +
    +
    +General guide +
    +
    +
    +
      +
    • You will work on the computing cluster Rackham at UPPMAX
    • +
    • If you change the node you are working on you will need to reload the tool modules.
    • +
    • Please type commands in the terminal instead of copying and pasting them which often result in formatting errors.
    • +
    • Use tab completion.
    • +
    • In paths, please replace username with your actual UPPMAX username.
    • +
    • In commands, please replace parameter with the correct parameter, for example your input file name, output file name, directory name, etc.
    • +
    • A line starting with # is a comment
    • +
    • Running a command without parameters will often return a help message on how to run the command.
    • +
    • After a command is completed, please check that the desired output file was generated and that it has a reasonable size (use ls -l).
    • +
    • Google errors, someone in the world has run into EXACTLY the same problem you had and asked about it on a forum somewhere.
    • +
    +
    +
    +
    +
    +

    Data description

    +
    +

    Samples

    +

    The 1000 Genomes Project ran between 2008 and 2015, creating the largest public catalogue of human variation and genotype data. In this workshop we will use low coverage whole genome sequence data from three individuals, generated in the first phase of the 1000 Genomes Project.

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    SamplePopulationSequencing technology
    HG00097British in England and ScotlandLow coverage WGS
    HG00100British in England and ScotlandLow coverage WGS
    HG00101British in England and ScotlandLow coverage WGS
    +
    +
    +

    Genomic region

    +

    The LCT gene on chromosome 2 encodes the enzyme lactase, which is responsible for the metabolism of lactose in mammals. Most mammals can not digest lactose as adults, but some humans can. Genetic variants upstream of the LCT gene causes lactase persistence, which means that lactase is expressed also in adulthood and the carrier can continue to digest lactose. The variant rs4988235, located at position chr2:136608646 in the GRCh37 reference genome, has been shown to lead to lactose persistence. The alternative allele (A on the forward strand and T on the reverse strand) creates a new transcription factor binding site that enables continued expression of the gene after weaning.

    +

    In this workshop we will detect genetic variants in the region chr2:136545000-136617000 in the three samples listed above, and check if they carry the allele for lactase persistence.

    +

    For those interested in the details of the genetic bases for lactose tolerance, please read the first three pages of Lactose intolerance: diagnosis, genetic, and clinical factors by Mattar et al. The variant rs4988235 is here referred to as LCT-13910C>T.

    +
    +
    +

    Data folder on UPPMAX

    +

    All input data for this exercise is located in this folder on Rackham:

    +
    +
    +
    /sw/courses/ngsintro/reseq/data
    +
    +
    +

    The fastq files are located in this folder:

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/fastq
    +
    +
    +

    Reference files, such as the reference genome in fasta format, are located in this folder:

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/ref
    +
    +
    +
    +
    +
    +

    Preparations

    +
    +

    Laptop

    +

    This lab will be done completely on UPPMAX and the instructions assume that you connect via ThinLinc. However, if you prefer to connect to UPPMAX via ssh you can instead copy some of the resulting files to your laptop and work on them there. , install IGV, and run all the IGV steps on your laptop. If so, please create a local workspace on your laptop, for example a folder called ngsworkflow on your desktop. You need to have write permission in this folder. If you connect to UPPMAX via ThinLinc you don’t have to crete a local workspace.

    +
    +
    +

    UPPMAX

    +
    +

    Connect to UPPMAX

    +

    During this lab it is best to connect to UPPMAX with ThinLinc, which gives you a graphical remote desktop. Instructions for this is available at Connecting to UPPMAX. Please follow the instructions in section 1.2 Remote desktop connection.

    +
    +
    +

    Logon to a node

    +

    This lab should be done on a compute node (not the login node). First check if you already have an active job allocation using this command:

    +
    squeue -u username
    +

    Where username should be replaced with your username.
    If no jobs are listed you should allocate a job for this lab. If you already have an active job allocation please proceed to Connect to the node below.

    +

    Use this code to allocate a job on day 1 of variant-calling:

    +
    +
    +
    salloc -A naiss2023-22-862 -t 04:00:00 -p core -n 1 --no-shell
    +
    +
    +

    Use this code to allocate a job on day 2 of variant-calling:

    +
    +
    +
    salloc -A naiss2023-22-862 -t 04:00:00 -p core -n 1 --no-shell
    +
    +
    +

    Once your job allocation has been granted (should not take long) please check the allocation again using:

    +
    squeue -u username
    +

    You should now see that you have an active job allocation. The node name for your job is listed under the nodelist header.

    +

    Connect to the node:

    +
    ssh -Y nodename
    +
    +
    +

    Workspace on UPPMAX

    +

    You should work in your folder under the course’s nobackup folder, just like you have done during the previous labs.

    +

    Start by going there using this command:

    +
    +
    +
    cd /proj/naiss2023-22-862/nobackup/username
    +
    +
    +

    Where username should be replaced with your real username. Create a folder for this exercise and move into it:

    +
    mkdir ngsworkflow
    +cd ngsworkflow
    +

    Make sure you are located in

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/ngsworkflow
    +
    +
    +

    for the rest of this lab.

    +
    + +
    +

    Accessing programs

    +

    Load the modules that are needed during this workshop. Remember that these modules must be loaded every time you login to Rackham, or when you connect to a new compute node.
    +First load the bioinfo-tools module:

    +
    module load bioinfo-tools
    +

    This makes it possible to load the individual programs:

    +
    module load FastQC/0.11.8
    +module load bwa/0.7.17
    +module load samtools/1.10
    +module load GATK/4.1.4.1
    +

    Although you don’t have to specify which versions of the tools to use, it is recommended to do so for reproducibility if you want to rerun the exact same analyses later. When loading the module GATK/4.1.4.1 you will get a warning message about the fact that GATK commands have been updated since the previous version of GATK. This is fine and you don’t have to do anything about it.

    +
    +
    +
    +

    Index the genome

    +

    Tools that compare short reads with a large reference genome needs indexes of the reference genome to work efficiently. You therefore need to create index files for each tool.

    +

    First check if you are standing in the correct directory:

    +
    pwd
    +

    Should return

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/ngsworkflow
    +
    +
    +

    Generate BWA index files:

    +
    bwa index -a bwtsw human_g1k_v37_chr2.fasta
    +

    Check that several new files have been created using ls -l. Then Generate a samtools index:

    +
    samtools faidx human_g1k_v37_chr2.fasta
    +

    Check to see what file(s) were created using ls -lrt. Then Generate a GATK sequence dictionary:

    +
    gatk --java-options -Xmx7g CreateSequenceDictionary -R human_g1k_v37_chr2.fasta -O human_g1k_v37_chr2.dict
    +

    Again, check what file(s) were created using ls -lrt.

    +
    +
    +
    +

    1 Variant calling in one sample

    +

    Now let’s start the main part of the workshop, which is variant calling in one sample. The workflow consists of aligning the reads with BWA and detecting variants with HaplotypeCaller as illustrated below.

    +
    +
    +

    +
    +
    +
    +

    1.1 Aligning reads

    +
    +

    1.1.1 BWA mem

    +

    You should use BWA mem to align the reads to the reference genome.

    +

    In the call to BWA mem you need to add something called a read group, which contains information about how the reads were generated. This is required by HaplotypeCaller. Since we don’t know exactly how the reads in the 1000 Genomes Project were generated we will assume that each pair of fastq files was generated from one library preparation (libraryx), derived from one biological sample (HG00097), and run on one lane (lanex) of a flowcell (flowcellx) on the Illumina machine, and define a toy read group with this information. The code for adding this read group is

    +

    -R “(RG?)\tID:HG00097\tPU:lanex_flowcellx\tSM:HG00097\tLB:libraryx\tPL:illumina”.

    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    When running BWA for another sample later on you have to replace HG00097 in the read group with the new sample name. To learn more about read groups please read this article at GATK forum.

    +
    +
    +

    You also need to specify how many threads the program should use (should be the same as the number of cores you have access to and is defined by the code -t 1 below) and what reference genome file to use. The output from BWA should be parsed to samtools sort, which sorts the sam file according to chromosome position and then converts the sam file to the binary bam format. Finally, use a file redirect > so that the output ends up in a file and not on your screen.

    +

    First make sure that you are standing in the workspace you created on UPPMAX for this lab:

    +
    pwd
    +

    Should return

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/ngsworkflow
    +
    +
    +

    Then use this command to align the reads, add the read group, sort the reads and write them to a bam file:

    +
    bwa mem \
    +-R "@RG\tID:readgroup_HG00097\tPU:lanex_flowcellx\tSM:HG00097\tLB:libraryx\tPL:illumina" \
    +-t 1 human_g1k_v37_chr2.fasta HG00097_1.fq HG00097_2.fq | samtools sort > HG00097.bam
    +

    Please check that the expected output file was generated and that it has content using ls -lrt.

    +

    Next you need to index the generated bam file so that programs can randomly access the sorted data without reading the whole file. This command creates an index file with the same name as the input bam file, except with a .bai extension:

    +
    samtools index HG00097.bam
    +

    Please check what output file was generated this time.

    +
    +
    +

    1.1.2 Check bam with samtools

    +

    The bam file is binary so we cannot read it directly, but we can view it with the program samtools view. The header section of the bam file can be viewed separately with the -H flag:

    +
    samtools view -H HG00097.bam
    +
    +

    Question

    +
      +
    1. The (SQ?) tag of the bam header contains information about reference sequence. What do you think SN:2 and LN:243199373 in this tag means?
    2. +
    +

    The aligned reads can be viewed with samtools view without the -H. This will display the entire bam file which is quite large, so if you just want to look at the first 5 lines (for example) you can combine samtools view with head:

    +
    samtools view HG00097.bam | head -n 5
    +
    +
    +

    Question

    +
      +
    1. What is the leftmost mapping position of the first read in the bamfile?
    2. +
    +

    Please have a look at the Sequence Alignment/Map Format Specification for more information about bam files.

    +
    +
    +
    +

    1.1.3 Check bam in IGV

    +

    To use IGV on UPPMAX we recommend that you are connected via ThinLinc. Alternatively you can install IGV on your local computer, download the files using scp, and look at them locally. The instructions below assume that you have logged in to UPPMAX via ThinLinc.
    +First use pwd to check if you are standing in the correct directory:

    +
    pwd
    +

    Should return

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/ngsworkflow
    +
    +
    +

    To start IGV please type this in the terminal:

    +
    module load IGV/2.8.13
    +igv.sh &
    +

    In IGV:
    +In the upper left dropdown menu choose Human hg19 (which is the same as GRCh37).
    +In the File menu, select Load from File and select HG00097.bam, which should then appear in the tracks window.
    +Zoom in to see the reads. You can either select a region by click and drag, or by typing a region or a gene name in the text box at the top. Remember that we have data for the region chr2:136545000-136617000.
    +IGV can be closed by selecting exit in the File menu or by clicking x in the upper right corner of the IGV window, but you can keep it open for the rest of the lab.

    +
    +

    Questions

    +
      +
    1. What is the read length?
    2. +
    3. Approximately how many reads cover an arbitrary position in the genomic region we are looking at?
    4. +
    5. Which RefSeq Genes are located within the region chr2:136545000-136617000?
    6. +
    +
    +
    +
    +
    +

    1.2 Variant Calling

    +
    +

    1.2.1 HaplotypeCaller

    +

    Now we will detect short variants in the bam file using GATK’s HaplotypeCaller. First use pwd to check if you are standing in the correct directory:

    +
    pwd
    +

    Should return

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/ngsworkflow
    +
    +
    +

    Then run:

    +
    gatk --java-options -Xmx7g HaplotypeCaller \
    +-R human_g1k_v37_chr2.fasta \
    +-I HG00097.bam \
    +-O HG00097.vcf
    +

    Check what new files were generated with ls -lrt.

    +
    +
    +

    1.2.2 Explore the vcf file

    +

    Now you have your first vcf file containing the raw variants in the region chr2:136545000-136617000 in sample HG00097. Please look at the vcf file with less and try to understand its structure.

    +

    Vcf files contains meta-information lines starting with ##, a header line starting with #CHROM, and then data lines each containing information about one variant position in the genome. The header line defines the columns of the data lines, and to view the header line you can type this command:

    +
    grep '#CHROM' HG00097.vcf
    +
    +

    Question

    +
      +
    1. What column of the VCF file contains genotype information for the sample HG00097?
    2. +
    +

    The meta-information lines starting with ##INFO defines how the data in the INFO column is encoded, and the meta-information lines starting with ##FORMAT defines how the data in the FORMAT column is encoded.
    +To view the meta-information lines describing the INFO column use:

    +
    grep '##INFO' HG00097.vcf
    +

    To view the meta-information lines describing the FORMAT column use:

    +
    grep '##FORMAT' HG00097.vcf
    +
    +
    +

    Question

    +
      +
    1. What does GT in the FORMAT column of the data lines mean?
    2. +
    3. What does AD in the FORMAT column of the data lines mean?
    4. +
    +

    To look at the details of one specific genetic variant at position 2:136545844 use:

    +
    grep '136545844' HG00097.vcf
    +
    +
    +

    Questions

    +
      +
    1. What genotype does the sample HG00097 have at position 2:136545844?
    2. +
    3. What are the allelic depths for the reference and alternative alles in sample HG00097 at position 2:136545844?
    4. +
    +

    The following command can be used to count the data lines (i.e. number of lines that don’t start with “#”) in the vcf file:

    +
    grep -v "#" HG00097.vcf | wc -l
    +
    +
    +

    Question

    +
      +
    1. How many genetic variants was detected in HG00097?
    2. +
    +

    For more detailed information about vcf files please have a look at The Variant Call Format specification.

    +
    +
    +
    +

    1.2.3 Check vcf in IGV

    +

    We assume that you have logged in to UPPMAX via ThinLinc.
    +If you have closed IGV please open it again as described above.
    +Load the file HG00097.vcf into tracks window of IGV as you did with the HG00097.bam file earlier (load the bam file as well if it is not already loaded). You will now see all the variants called in HG00097.
    +You can view variants in the LCT gene by typing the gene name in the search box, and you can look specifically at the variant at position chr2:136545844 by typing that position in the search box.
    +Please use IGV to answer the questions below.

    +
    +

    Questions

    +
      +
    1. Hover the mouse over the upper row of the vcf track. What is the reference and alternative alleles of the variant at position chr2:136545844?
    2. +
    3. Hover the mouse over the lower row of the vcf track and look under “Genotype Information”. What genotype does HG00097 have at position chr2:136545844? Is this the same as you found by looking directly in the vcf file in question 10?
    4. +
    5. Look in the bam track and count the number of reads that have “G” and “C”, respectively, at position chr2:136545844. How is this information captured under “Genotype Attributes”? (Again, hoover the mouse over the lower row of the vcf track.)
    6. +
    +
    +
    +
    +
    +
    +

    2 Variant calling in cohort

    +

    If you have time, you can now try joint variant calling in all three samples. Each sample has to be processed with BWA mem as above, and then with HaplotypeCaller with the flag -ERC to generate one g.vcf file per sample. The individual g.vcf files should subsequently be combined with GATK’s CombineGVCFs, and translated into vcf format with GATK’s GenotypeGVCFs. The workflow below shows how the three samples should be processed and combined.

    +
    +
    +

    +
    +
    +

    If you don’t have time to complete all steps we have made precomputed intermediary file available. Please see links under each analysis step.

    +
    +

    2.1 BWA mem

    +

    Run BWA mem for all three samples in the data set. BWA mem should be run exactly as above, but with the new sample names. You also need to adjust the read group information so that it matches each new sample name.

    +

    First use pwd to check if you are standing in the correct directory:

    +
    pwd
    +

    Should return

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/ngsworkflow
    +
    +
    +

    Then use this command for every sample to align the reads, add the read group, sort the reads and write them to a bam file:

    +
    bwa mem -R "@RG\tID:readgroup_<sample>\tPU:lanex_flowcellx\tSM:<sample>\tLB:libraryx\tPL:illumina" \
    +-t 1 human_g1k_v37_chr2.fasta sample_1.fq sample_2.fq | samtools sort > sample.bam
    +

    Where sample should be replaced with the real samples name, i.e. HG00097, HG00100 and HG00101. Please check that the expected output files were generated and have content using ls -lrt. You also need to index each output bam file:

    +
    samtools index <sample>.bam
    +

    Please check what output file was generated this time. If you run out of time you can click below to get paths to precomputed bam files.

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/bam/HG00097.bam
    +/sw/courses/ngsintro/reseq/data/bam/HG00100.bam
    +/sw/courses/ngsintro/reseq/data/bam/HG00101.bam
    +
    +
    +
    +
    +

    2.2 Generate g.vcf files

    +

    HaplotypeCaller should also be run for all three samples, but this time the output for each sample needs to be in g.vcf format. This is accomplished with a small change in the HaploteypCaller command.
    First use pwd to check if you are standing in the correct directory:

    +
    pwd
    +

    Should return

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/ngsworkflow
    +
    +
    +

    Then:

    +
    gatk --java-options -Xmx7g HaplotypeCaller \
    +-R human_g1k_v37_chr2.fasta \
    +-ERC GVCF \
    +-I sample.bam \
    +-O sample.g.vcf
    +

    Please replace sample with the real sample names.

    +

    If you run out of time you can click below to get paths to the precomputed g.vcf files.

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/vcf/HG00097.g.vcf
    +/sw/courses/ngsintro/reseq/data/vcf/HG00100.g.vcf
    +/sw/courses/ngsintro/reseq/data/vcf/HG00101.g.vcf
    +
    +
    +
    +
    +

    2.3 Joint genotyping

    +

    Once you have the g.vcf files for all samples you should perform joint genotype calling. To do this you first need to combine all individual .g.vcf files to one file using CombineGVCFs.

    +

    First use pwd to check if you are standing in the correct directory:

    +
    pwd
    +

    Should return

    +
    +
    +
    /proj/naiss2023-22-862/nobackup/username/ngsworkflow
    +
    +
    +

    Then:

    +
    gatk --java-options -Xmx7g CombineGVCFs \
    +-R human_g1k_v37_chr2.fasta \
    +-V sample1.g.vcf \
    +-V sample2.g.vcf \
    +-V sample3.g.vcf \
    +-O cohort.g.vcf
    +

    Please replace sample1, sample2, sample3 with the real sample names. Then run GATK’s GenoteypeGVC to generate a vcf file:

    +
    gatk --java-options -Xmx7g GenotypeGVCFs \
    +-R human_g1k_v37_chr2.fasta \
    +-V cohort.g.vcf \
    +-O cohort.vcf
    +

    If you run out of time you can click below to get paths to the precomputed cohort.g.vcf and cohort.vcf files.

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/vcf/cohort.g.vcf
    +/sw/courses/ngsintro/reseq/data/vcf/cohort.vcf
    +
    +
    +
    +

    Questions

    +
      +
    1. How many data lines do the cohort.g.vcf file have? You can use the Linux command grep -v "#" cohort.g.vcf to extract all lines in “cohort.g.vcf” that don’t start with “#”, then |, and then wc -l to count those lines.
    2. +
    3. How many data lines do the cohort.vcf file have?
    4. +
    5. Explain the difference in number of data lines.
    6. +
    7. Look at the header line of the cohort.vcf file. What columns does it have?
    8. +
    9. What is encoded in the last three columns of the data lines?
    10. +
    +
    +
    +
    +

    2.4 Check combined vcf file in IGV

    +

    Again we assume that you have logged in to UPPMAX via ThinLinc.
    +If you have closed IGV please open it again as described above.
    +Load the files cohort.vcf, HG00097.bam, HG00100.bam and HG00101.bam into IGV as described earlier.
    +This time lets look closer at the variant rs4988235, located at position chr2:136608646 in the HG19 reference genome. This is the variant that has been shown to lead to lactase persistence.
    +Please use IGV to answer the questions below.

    +
    +

    Questions

    +
      +
    1. What is the reference and alternative alleles at chr2:136608646?
    2. +
    3. What genotype do the three samples have at chr2:136608646? Note how genotypes are color coded in IGV.
    4. +
    5. Should any of the individuals avoid drinking milk?
    6. +
    7. Now compare the data shown in IGV with the data in the VCF file. Extract the row for the chr2:136608646 variant in the cohort.vcf file, for example using grep '136608646' cohort.vcf. What columns of the vcf file contain the information shown in the upper part of the vcf track in IGV?
    8. +
    9. What columns of the vcf file contain the information shown in the lower part of the vcf track?
    10. +
    11. Zoom out so that you can see the MCM6 and LCT genes. Is the variant at chr2:136608646 locate within the LCT gene?
    12. +
    +

    If you are interested in how this variant affects lactose tolerance please read the article by Mattar et al presented above, or in OMIM.

    +
    +
    +
    +
    +

    3 GATK’s best practices

    +

    The third part of this workshop will take you through additional refinement steps that are recommended in GATKs best practices for germline short variant discovery, illustrated in the flowchart below. The additional steps in the best practice workflow was not covered in the variant-calling lecture on Wednesday afternoon. There will be a short lecture about this on Thursday morning at 9 am. However, if you reach this step earlier you can have a look at this prerecorded video of the same lecture.

    +
    +
    +

    +
    +
    +
    +

    3.1 BWA mem

    +

    The first step in GATK’s best pracice variant calling workflow is to run BWA mem for each sample exactly as you did in Variant calling in cohort. You have already done this step, so please use the bam files that you generated in step 2.1 for the steps below.

    +
    +
    +

    3.2 Mark Duplicates

    +

    Sometimes the same DNA fragment is sequenced multiple times, which leads to multiple reads from the same fragment in the fastq file. This can occur due to PCR amplification in the library preparation, or if one read cluster is incorrectly detected as multiple clusters by the sequencing instrument. If a duplicated read contains a genetic variant, the ratio of the two alleles might be obscured, which can lead to incorrect genotyping. It is therefore recommended (in most cases) to mark duplicate reads so that they are counted as one during genotyping.

    +

    Please read about Picard’s MarkDuplicates here. Picard’s MarkDuplicates has recently been incorporated into the GATK suite, but the usage example in GATKs documentation describes how to call it via the stand alone Picard program. To learn how to use it as part of the GATK module, please call MarkDuplicates without input parameters like this:

    +
    gatk --java-options -Xmx7g MarkDuplicates
    +

    Please run MarkDuplicates on all three bam files generated in step 2.1. Here is the code for running MarkDuplicates on the sample HG00097:

    +
    gatk --java-options -Xmx7g MarkDuplicates \
    +    -I HG00097.bam \
    +    -O HG00097.md.bam \
    +    -M HG00097_mdmetrics.txt
    +
    +
    +

    3.3 Recalibrate Base Quality Scores

    +

    Another source of error is systematic biases in the assignment of base quality scores by the sequencing instrument. This can be corrected by GATK’s Base Quality Score Recalibration. In short, you first use BaseRecalibrator to build a recalibration model, and then ApplyBQSR to recalibrate the base qualities in your bam file.
    +BaseRecalibrator requires a file with known SNPs as input. This file is available in the data folder on UPPMAX:

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/ref/1000G_phase1.snps.high_confidence.b37.chr2.vcf
    +
    +
    +

    Please recalibrate the base quality scores in all the bam files generated in the previous step. Below is our example solution for sample HG00097. First run BaseRecalibrator:

    +
    +
    +
    gatk --java-options -Xmx7g BaseRecalibrator \
    +    -R human_g1k_v37_chr2.fasta \
    +    -I HG00097.md.bam \
    +    --known-sites /sw/courses/ngsintro/reseq/data/ref/1000G_phase1.snps.high_confidence.b37.chr2.vcf \
    +    -O HG00097.recal.table
    +
    +
    +

    Then run ApplyBQSR:

    +
    gatk --java-options -Xmx7g ApplyBQSR \
    +    -R human_g1k_v37_chr2.fasta \
    +    -I HG00097.md.bam \
    +    --bqsr-recal-file HG00097.recal.table \
    +    -O   HG00097.recal.bam
    +
    +
    +

    3.4 Generate g.vcf files

    +

    HaplotypeCaller should also be run for all three samples, and the output should be in g.vcf exactly as described above. This time use recalibrated bam files as input.

    +
    +
    +

    3.5 Joint genotyping

    +

    Once you have the g.vcf files for all samples you should perform joint genotype calling. This should be done with the commands CombineGVCFs and GenotypeGVCFs exactly as described above, but you should use the g.vcf files generated from the recalibrated bam files as input.

    +
    +
    +

    3.6 Variant Filtering

    +

    HaplotypeCaller is designed to be very sensitive, which is good because it minimizes the chance of missing real variants. However, it means that the number of false positives can be quite large, so we need to filter the raw callset. GATK offers two ways to filter variants:

    +
      +
    1. The variant quality score recalibration (VQSR) method uses machine learning to identify variants that are likely to be real. This is the best method if you have a lot of data, for example one whole genome sequence sample or several whole exome samples.
      +
    2. +
    3. If you have less data you can use hard filters as described here.
    4. +
    +

    Since we have very little data we will use hard filters. The parameters are slightly different for SNVs and INDELs, so you need to first select all SNVs using SelectVariants and filter them using VariantFiltration with the parameters suggested for SNVs. Then select all INDELs and filter them with the parameters suggested for INDELs. Finally merge the SNVs and INDELs to get all variants in one file using MergeVCFs.
    +An explanation of what the hard filters do can be found here.

    +

    Example solution for filtering SNVs:

    +
    gatk --java-options -Xmx7g SelectVariants \
    +  -R human_g1k_v37_chr2.fasta \
    +  -V cohort.vcf \
    +  --select-type-to-include SNP \
    +  -O cohort.snvs.vcf
    +
    +gatk --java-options -Xmx7g VariantFiltration \
    +  -R human_g1k_v37_chr2.fasta \
    +  -V cohort.snvs.vcf \
    +  -O cohort.snvs.filtered.vcf \
    +  --filter-name QDfilter --filter-expression "QD < 2.0"  \
    +  --filter-name MQfilter --filter-expression "MQ < 40.0"  \
    +  --filter-name FSfilter --filter-expression "FS > 60.0"
    +

    Example solution for filtering INDELs:

    +
    gatk --java-options -Xmx7g SelectVariants \
    +  -R human_g1k_v37_chr2.fasta \
    +  -V cohort.vcf \
    +  --select-type-to-include INDEL \
    +  -O cohort.indels.vcf
    +
    +gatk --java-options -Xmx7g VariantFiltration \
    +  -R human_g1k_v37_chr2.fasta \
    +  -V cohort.indels.vcf \
    +  -O cohort.indels.filtered.vcf \
    +  --filter-name QDfilter --filter-expression "QD < 2.0" \
    +  --filter-name FSfilter --filter-expression "FS > 200.0"
    +

    Example solution for merging filtered SNVs and INDELs:

    +
    gatk --java-options -Xmx7g MergeVcfs \
    +    -I cohort.snvs.filtered.vcf \
    +    -I cohort.indels.filtered.vcf \
    +    -O cohort.filtered.vcf
    +

    Open your filtered vcf with less and page through it. It still has all the variant lines, but the FILTER column that was blank before is now filled in, with PASS or a list of the filters it failed. Note also that the filters that were run are described in the header section.

    +
    +

    Precomputed files

    +

    If you run out of time, please click below to get the path to precomputed bam and vcf files for the GATK’s best practices section.

    +
    +
    +
    Path to intermediary and final bam files: /sw/courses/ngsintro/reseq/data/best_practise_bam
    +Path to intermediary and final vcf files: /sw/courses/ngsintro/reseq/data/best_practise_vcf
    +
    +
    +
    +
    +

    Questions

    +
      +
    1. Check how many variants in total that are present in the cohort.filtered.vcf file and how many that have passed the filters. Is the difference big?
    2. +
    3. Look at the variants that did not pass the filters using grep -v 'PASS' cohort.filtered.vcf. Try to understand why these variants didn’t pass the filter.
    4. +
    +
    +
    +
    +
    +

    Clean up

    +

    When the analysis is done and you are sure that you have the desired output, it is a good practice to remove intermediary files that are no longer needed. This will save disk space, and will be a crucial part of the routines when you work with your own data. Please think about which files you need to keep if you would like to go back and look at this lab later on. Remove the other files.

    +
    +
    +

    Answers

    +

    When you have finished the exercise, please have a look at this document with answers to all questions, and compare them with your answers.

    +
    +
    +

    SBATCH scripts

    +

    This section is supplementary material intended only for those of you who want to learn how to run all steps automatically in bash scripts. Please make sure that you have understood how all the individual steps work before you start with this. To learn more about SLURM and SBATCH scripts please look the SLURM user guide on UPPMAX website.

    +
    +

    Variant calling in cohort

    +

    Below is a skeleton script that can be used as a template for running variant calling in a cohort. Please modify it to run all the steps in part two of this workshop.

    +
    #!/bin/bash
    +#SBATCH -A sens2022-22-123
    +#SBATCH -p core
    +#SBATCH -n 1
    +#SBATCH -t 1:00:00
    +#SBATCH -J jointGenotyping
    +
    +module load bioinfo-tools
    +module load bwa/0.7.17
    +module load samtools/1.10
    +module load GATK/4.1.4.1
    +
    +## loop through the samples:
    +for sample in HG00097 HG00100 HG00101;
    +do
    +  echo "Now analyzing: "${sample}
    +  #Fill in the code for running bwa-mem for each sample here
    +  #Fill in the code for samtools index for each sample here
    +  #Fill in the code for HaplotypeCaller for each sample here
    +done
    +#Fill in the code for CombineGVCFs for all samples here
    +#Fill in the code for GenotypeGVCFs here
    +

    Please save the sbatch script in your UPPMAX folder and call it “joint_genotyping.sbatch” or similar. Make the script executable by this command:

    +
    chmod u+x joint_genotyping.sbatch
    +

    To run the sbatch script in the SLURM queue, use this command:

    +
    sbatch joint_genotyping.sbatch
    +

    If you have an active node reservation you can run the script as a normal bash script:

    +
    ./joint_genotyping.sbatch
    +

    If you would like more help with creating the sbatch script, please look at our example solution:

    +
    +
    +
    #!/bin/bash
    +#SBATCH -A naiss2023-22-862
    +#SBATCH -p core
    +#SBATCH -n 1
    +#SBATCH -t 2:00:00
    +#SBATCH -J jointGenotyping
    +
    +module load bioinfo-tools
    +module load bwa/0.7.17
    +module load samtools/1.10
    +module load GATK/4.1.4.1
    +
    +for sample in HG00097 HG00100 HG00101;
    +do
    +  echo "Now analyzing: "${sample}
    +  bwa mem -R \
    +  "@RG\tID:${sample}\tPU:flowcellx_lanex\tSM:${sample}\tLB:libraryx\tPL:illumina" \
    +  -t 1 human_g1k_v37_chr2.fasta "${sample}_1.fq" "${sample}_2.fq" | samtools sort > "${sample}.bam"
    +
    +  samtools index "${sample}.bam"
    +
    +  gatk --java-options -Xmx7g HaplotypeCaller \
    +  -R human_g1k_v37_chr2.fasta \
    +  -ERC GVCF -I "${sample}.bam" \
    +  -O "${sample}.g.vcf"
    +
    +done
    +
    +gatk --java-options -Xmx7g CombineGVCFs \
    +-R human_g1k_v37_chr2.fasta \
    +-V HG00097.g.vcf \
    +-V HG00100.g.vcf \
    +-V HG00101.g.vcf \
    +-O cohort.g.vcf
    +
    +gatk --java-options -Xmx7g GenotypeGVCFs \
    +-R human_g1k_v37_chr2.fasta \
    +-V cohort.g.vcf \
    +-O cohort.vcf
    +
    +
    +
    +
    +

    GATK best practices

    +

    Now please try to incorporate the additional steps from GATK’s best practices into the workflow. If you run out of time you can sneak peek at our example solution below.

    +
    +
    +
    #!/bin/bash
    +#SBATCH -A naiss2023-22-862
    +#SBATCH -p core
    +#SBATCH -n 1
    +#SBATCH -t 2:00:00
    +#SBATCH -J BestPractise
    +
    +## load modules
    +module load bioinfo-tools
    +module load bwa/0.7.17
    +module load samtools/1.10
    +module load GATK/4.1.4.1
    +
    +# define path to reference genome
    +ref="/sw/courses/ngsintro/reseq/data/ref"
    +
    +# make symbolic links
    +ln -s /sw/courses/ngsintro/reseq/data/ref/human_g1k_v37_chr2.fasta
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_1.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_2.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_1.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_2.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_1.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_2.fq
    +
    +# index reference genome
    +bwa index -a bwtsw human_g1k_v37_chr2.fasta
    +samtools faidx human_g1k_v37_chr2.fasta
    +gatk --java-options -Xmx7g CreateSequenceDictionary \
    +-R human_g1k_v37_chr2.fasta \
    +-O human_g1k_v37_chr2.dict
    +
    +## loop through the samples:
    +for sample in HG00097 HG00100 HG00101;
    +do
    +  echo "Now analyzing: ${sample}"
    +  # map the reads
    +  bwa mem \
    +  -R "@RG   ID:${sample}    PU:flowcellx_lanex  SM:${sample}    LB:libraryx PL:illumina" \
    +  -t 1 human_g1k_v37_chr2.fasta \
    +  "${sample}_1.fq" "${sample}_2.fq" | samtools sort > "${sample}.bam"
    +
    +  samtools index $sample".bam"
    +  # mark duplicates
    +  gatk --java-options -Xmx7g MarkDuplicates \
    +  -I "${sample}.bam" \
    +  -O "${sample}.md.bam" \
    +  -M "${sample}_mdmetrics.txt"
    +
    +  # base quality score recalibration
    +  gatk --java-options -Xmx7g BaseRecalibrator \
    +  -R human_g1k_v37_chr2.fasta \
    +  -I "${sample}.md.bam" \
    +  --known-sites "${ref}/1000G_phase1.snps.high_confidence.b37.chr2.vcf" \
    +  -O "${sample}.recal.table"
    +
    +  gatk --java-options -Xmx7g ApplyBQSR \
    +  -R human_g1k_v37_chr2.fasta \
    +  -I "${sample}.md.bam" \
    +  --bqsr-recal-file "${sample}.recal.table" \
    +  -O "${sample}.recal.bam"
    +
    +  # haplotypeCaller in -ERC mode
    +  gatk --java-options -Xmx7g HaplotypeCaller \
    +  -R human_g1k_v37_chr2.fasta \
    +  -ERC GVCF \
    +  -I "${sample}.bam" \
    +  -O "${sample}.g.vcf"
    +done
    +
    +# joint genotyping
    +gatk --java-options -Xmx7g CombineGVCFs \
    +-R human_g1k_v37_chr2.fasta \
    +-V HG00097.g.vcf \
    +-V HG00100.g.vcf \
    +-V HG00101.g.vcf \
    +-O cohort.g.vcf
    +
    +gatk --java-options -Xmx7g GenotypeGVCFs \
    +-R human_g1k_v37_chr2.fasta \
    +-V cohort.g.vcf \
    +-O cohort.vcf
    +
    +# variant filtration SNPs
    +gatk --java-options -Xmx7g SelectVariants \
    +-R human_g1k_v37_chr2.fasta \
    +-V cohort.vcf \
    +--select-type-to-include SNP \
    +-O cohort.snvs.vcf
    +
    +gatk --java-options -Xmx7g VariantFiltration \
    +-R human_g1k_v37_chr2.fasta \
    +-V cohort.snvs.vcf \
    +--filter-name QDfilter --filter-expression "QD < 2.0" \
    +--filter-name MQfilter --filter-expression "MQ < 40.0" \
    +--filter-name FSfilter --filter-expression "FS > 60.0" \
    +-O cohort.snvs.filtered.vcf
    +
    +# variant filtration indels
    +gatk --java-options -Xmx7g SelectVariants \
    +-R human_g1k_v37_chr2.fasta \
    +-V cohort.vcf \
    +--select-type-to-include INDEL \
    +-O cohort.indels.vcf
    +
    +gatk --java-options -Xmx7g VariantFiltration \
    +-R human_g1k_v37_chr2.fasta \
    +-V cohort.indels.vcf \
    +--filter-name QDfilter --filter-expression "QD < 2.0" \
    +--filter-name FSfilter --filter-expression "FS > 200.0" \
    +-O cohort.indels.filtered.vcf
    +
    +# merge filtered SNPs and indels
    +gatk --java-options -Xmx7g MergeVcfs \
    +-I cohort.snvs.filtered.vcf \
    +-I cohort.indels.filtered.vcf \
    +-O cohort.filtered.vcf
    +
    +
    +
    +
    +
    +

    Additional information

    + + +

    Thanks for today!

    + + +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/2311/topics/vc/lab_vc_answers.html b/2311/topics/vc/lab_vc_answers.html new file mode 100644 index 00000000..4ccf14a7 --- /dev/null +++ b/2311/topics/vc/lab_vc_answers.html @@ -0,0 +1,412 @@ + + + + + + + + + +Variant Calling Answers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Variant Calling Answers

    +

    Answers for the variant-calling lab

    +
    +
    + + +
    + + + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/2311/topics/vc/lab_vc_answers.pdf b/2311/topics/vc/lab_vc_answers.pdf new file mode 100644 index 00000000..a44a8933 Binary files /dev/null and b/2311/topics/vc/lab_vc_answers.pdf differ diff --git a/2311/topics/vc/lab_vc_tetralith.html b/2311/topics/vc/lab_vc_tetralith.html new file mode 100644 index 00000000..8762c5be --- /dev/null +++ b/2311/topics/vc/lab_vc_tetralith.html @@ -0,0 +1,1291 @@ + + + + + + + + + + + +Variant Calling Workflow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Variant Calling Workflow

    +

    From reads to short variants

    +
    +
    + On Tetralith at NSC +
    +
    +
    +
    + + +
    + +
    +
    Author
    +
    +

    Malin Larsson

    +
    +
    + +
    +
    Published
    +
    +

    13-Nov-2023

    +
    +
    + + +
    + + +
    + + + + +
    + + + + +
    +

    Introduction

    +

    Whole genome sequencing (WGS) is a comprehensive method for analyzing entire genomes. This workshop will take you through the process of calling germline short variants (SNVs and INDELs) in WGS data from three human samples.

    +
      +
    1. The first part of the workshop will guide you through a basic variant calling workflow in one sample. The goals are that you should get familiar with the bam and vcf file formats, and learn how to interpret the results of variant calling in Integrative Genomics Viewer (IGV).
    2. +
    3. If you have time, the next part of the workshop will show you how to perform joint variant calling in three samples. The goals here is that you should be able to interpret multi-sample vcf files and explain the differences between the g.vcf and vcf file formats. Also, if you are interested in programming, another goal is that you should learn to combine individual Linux commands into an SBATCH script.
      +
    4. +
    5. If you have time, the last part of the workshop will take you through the GATK best practices for germline short variant detection in three samples. The goal here is that you should learn how to use GATK’s documentation so that you can analyze your own samples in the future.
    6. +
    +

    General guide

    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +
      +
    • In this workshop you will work on the computing cluster Tetralith at NSC.
    • +
    • You will use a singularity container (a virtual computer) that mimics the UPPMAX environment.
    • +
    • In paths, please replace <nsc_username> with your NSC username.
    • +
    • In commands, please replace <parameter> with the correct parameter, for example your input file name, output file name, directory name, etc.
    • +
    • Do not copy and paste commands from the exercise to terminal, as this can result in formatting errors.
    • +
    • Use tab completion.
    • +
    • A line starting with # is a comment
    • +
    • Running a command without parameters will often return a help message on how to run the command.
    • +
    • After a command is completed, please check that the desired output file was generated and that it has a reasonable size (use ls -l).
    • +
    • A common mistake is to attempt to load input files that do not exist, or create output files where you don’t have permission to write.
    • +
    • Use output file names that describes what was done in the command.
    • +
    • If you change the node you are working on you will need to reload the tool modules.
    • +
    • Google errors, someone in the world has run into EXACTLY the same problem you had and asked about it on a forum somewhere.
    • +
    +
    +
    +
    +
    +

    Data description

    +
    +

    Samples

    +

    The 1000 Genomes Project ran between 2008 and 2015, creating the largest public catalogue of human variation and genotype data. In this workshop we will use low coverage whole genome sequence data from three individuals, generated in the first phase of the 1000 Genomes Project.

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    SamplePopulationSequencing technology
    HG00097British in England and ScotlandLow coverage WGS
    HG00100British in England and ScotlandLow coverage WGS
    HG00101British in England and ScotlandLow coverage WGS
    +
    +
    +

    Genomic region

    +

    The LCT gene on chromosome 2 encodes the enzyme lactase, which is responsible for the metabolism of lactose in mammals. Most mammals can not digest lactose as adults, but some humans can. Genetic variants upstream of the LCT gene lead to lactase persistence, which means that lactase is expressed also in adulthood and the carrier can continue to digest lactose. The variant rs4988235, located at position chr2:136608646 in the HG19 reference genome, has been shown to lead to lactose persistence. The alternative allele (A on the forward strand and T on the reverse strand) creates a new transcription factor binding site that enables continued expression of the gene after weaning.

    +

    In this workshop we will use sequencing data for the region chr2:136545000-136617000 chr2:136,039,147-136,662,073 in the 3 samples listed above to illustrate variant calling in NGS data. We will use chromosome 2 from hg19 as reference genome.

    +

    For those interested in the details of the genetic bases for lactose tolerance, please read the first three pages of Lactose intolerance: diagnosis, genetic, and clinical factors by Mattar et al. The variant rs4988235 is here referred to as LCT-13910C>T.

    +
    +
    +

    Data folder on UPPMAX

    +

    All input data for this exercise is located in this folder:

    +
    +
    +
    /sw/courses/ngsintro/reseq/data
    +
    +
    +

    The fastq files are located in this folder:

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/fastq
    +
    +
    +

    Reference files, such as the reference genome in fasta format, are located in this folder:

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/ref
    +
    +
    +
    +
    +
    +

    Preparations

    +
    +

    Local workspace

    +

    The majority of the analyses in this workshop will be done on the computing cluster, but you will copy some of the resulting files to your laptop. Therefore, please start by creating a folder for this workshop on your laptop. It is up to you where you want to put this, but it can for example be a folder called ngsworkflow on Desktop. You need to have write permission in this folder. The folder you create here will be referred to as local workspace throughout this workshop.

    +
    +
    +

    The NSC cluster

    +

    Please connect to the Tetralith cluster at NSC using ssh:

    +
    $ ssh -Y nsc_username@tetralith.nsc.liu.se
    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    Note that your terminal prompt changed to something like nsc_username@tetralith1 $ which means that you have entered Tetralith.

    +
    +
    +
    +

    Interactive session

    +

    On Tetralith you enter the login node, which is not intended for compute intensive tasks. You should therefore book a compute node, or in this case three cores:

    +
    +
    +
    tetralith1$ interactive -A naiss2023-22-862 -t 04:00:00 -n 3
    +
    +
    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    Your terminal prompt changed to something like <nsc_username>@n424 $ (or another node name), which means that you are now running on one of the compute nodes.

    +
    +
    +
    +
    +

    UPPMAX singularity container

    +

    We will use a singularity container (a virtual computer) that mimics the UPPMAX computing environment. Once you have started the singularity container your environment will look exactly as on UPPMAX, and the software used in this workshop will be available through the module system.

    +

    Use this command to start the singularity container:

    +
    +
    +
    n424$ singularity shell -B /proj/naiss2023-22-862/users:/proj/naiss2023-22-862/nobackup /proj/naiss2023-22-862/ngsintro.sif
    +
    +
    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    Note that your terminal prompt changed to something like <nsc_username>@offline-uppmax$. This means that you have moved into a “virtual computer” that mimics the UPPMAX environment.

    +
    +
    +

    In the singularity container type this to make modules based on Java to load properly:

    +
    +
    +
    source /uppmax_init
    +
    +
    +

    To close the singularity container later on just type exit in the terminal, but don’t do that now.

    +
    +
    +

    Cluster workspace

    +

    While running the UPPMAX singularity container, create a workspace folder for this exercise and move into it:

    +
    +
    +
    offline-uppmax$ mkdir /proj/naiss2023-22-862/nobackup/<nsc_username>/ngsworkflow
    +offline-uppmax$ cd /proj/naiss2023-22-862/nobackup/<nsc_username>/ngsworkflow
    +
    +
    +

    The folder you just created will be referred to as your cluster workspace throughout this workshop.

    +

    The cluster workspace can be reached also from outside of the UPPMAX singularity container, in this folder on Tetralith:

    +
    +
    +
    tetralith$ /proj/naiss2023-22-862/users/<nsc_username>/ngsworkflow
    +
    +
    +

    This is the path you must use when downloading files to your local workspace later on.

    +
    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    Note: The rest of the instructions assumes that you are running the UPPMAX singularity container from an interactive session on Tetralith, and that you are located in your cluster workspace, unless noted otherwise.

    +
    +
    +
    + +
    +

    Accessing programs

    +

    We will use several programs that are installed in the module system on UPPMAX. These modules must be loaded every time you start the singularity container.

    +

    First load the bioinfo-tools module:

    +
    offline-uppmax$ module load bioinfo-tools
    +

    This makes it possible to load the individual programs:

    +
    offline-uppmax$ module load FastQC/0.11.8
    +offline-uppmax$ module load bwa/0.7.17
    +offline-uppmax$ module load samtools/1.10
    +offline-uppmax$ module load GATK/4.1.4.1
    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    You don’t have to specify which versions of the tools to use, but is recommended to do so for reproducibility if you want to rerun the exact same analyses later.

    +
    +
    +

    When loading the module GATK/4.1.4.1 you may get a warning message about the fact that GATK commands have been updated since the previous version of GATK. This is fine and you don’t have to do anything about it.

    +
    +
    +
    +

    Index the genome

    +

    Tools that compare short reads with a large reference genome needs indexes of the reference genome to work efficiently. You therefore need to create index files for each tool.

    +

    Generate BWA index files:

    +
    offline-uppmax$ bwa index -a bwtsw human_g1k_v37_chr2.fasta
    +

    Check to see that several new files have been created using ls -l.

    +

    Generate a samtools index:

    +
    offline-uppmax$ samtools faidx human_g1k_v37_chr2.fasta
    +

    Check to see what file(s) were created using ls -lrt.

    +

    Generate a GATK sequence dictionary:

    +
    offline-uppmax$ gatk --java-options -Xmx7g CreateSequenceDictionary -R human_g1k_v37_chr2.fasta -O human_g1k_v37_chr2.dict
    +

    Again, check what file(s) were created using ls -lrt.

    +
    +
    +
    +

    1 Variant calling in one sample

    +

    Now let’s start the main part of the workshop, which will guide you through a basic variant calling workflow in one sample. The workflow consists of aligning the reads with BWA and detecting variants with HaplotypeCaller as illustrated below.

    +
    +
    +

    +
    +
    +
    +

    1.1 Aligning reads

    +
    +

    1.1.1 BWA mem

    +

    In the Cluster workspace you should now use BWA mem to align the reads to the reference genome.

    +

    At the same time, you should add something called read groups to the reads in the fastq files. Read groups allow us to trace various technical features, such as which flow cell was used to generate the reads, and this is needed in order to perform variant calling with HaplotypeCaller. You are not expected to learn all the details of read groups here, but if you are interested in more information please read this article at GATK-forum. The samples in this workshop come from the 1000 Genomes project, and we don’t know how these reads were generated. Let’s assume that each fastq file was generated from one library preparation (called libraryx), derived from one biological sample (called HG00097), that was run on one lane of a flow cell (called lanex_flowcellx) in the Illumina machine, and create a read group with id readgroupx that contains this information.

    +

    The output from BWA should be parsed to samtools sort, which sorts the sam file according to chromosome position and then converts the sam file to the binary bam format. This saves space since no intermediary sam file is created.

    +

    Please use this command for all of this:

    +
    offline-uppmax$ bwa mem -R "@RG\\tID:readgroupx\\tPU:lanex_flowcellx\\tSM:HG00097\\tLB:libraryx\\tPL:illumina" -t 1 human_g1k_v37_chr2.fasta HG00097_1.fq HG00097_2.fq | samtools sort > HG00097.bam
    +

    Where -t 1 is the number of threads, which should be equal to the number of cores you booked. If you would have analysed the entire genome more threads would have been necessary.

    +

    You have to use a file redirect > for the output, otherwise it will be written to stdout (your screen).

    +

    Please check that the expected output file was generated and that it has content using ls -lrt.

    +

    Next you need to index the output bam file so that programs can randomly access the sorted data without reading the whole file. This command creates an index file with the same name as the input bam file, except with a .bai extension:

    +
    offline-uppmax$ samtools index HG00097.bam
    +

    Please check what output file was generated this time.

    +
    +
    +

    1.1.2 Check bam with samtools

    +

    The bam file is binary so we cannot read it, but we can view it with samtools view. The header section of the bam file can be viewed separately with the -H flag:

    +
    offline-uppmax$ samtools view -H HG00097.bam 
    +

    To look at the reads in the bam file just use samtools view without the -H. This will display the entire bam file which is quite large, so if you just want to look at the first 5 lines (for example) you can combine samtools view with head:

    +
    offline-uppmax$ samtools view HG00097.bam | head -n 5 
    +

    For help with interpreting the bam file, please look at the sam/bam format definition at Sequence Alignment/Map Format Specification.

    +
    +
    +

    1.1.3 Questions

    +
      +
    1. What does “SO:coordinate” in the “(HD?)” tag on the first line of the bam file mean?
      +
    2. +
    3. What does “SN:2” and “LN:243199373” in the “(SQ?) tag mean?
    4. +
    5. What is encoded in the (RG?) tag?
      +
    6. +
    7. What is the leftmost mapping position of the first read in the bamfile?
    8. +
    +
    +
    +

    1.1.4 Check bam in IGV

    +

    Install IGV

    +

    Integrated Genomics Viewer (IGV) provides an interactive visualisation of the reads in a bam file. Here we will show you how to run IGV on your laptop. If you have not used IGV on your laptop before, then go to the IGV download page, and follow the instructions to download it. It will prompt you to fill in some information and agree to license. Launch the viewer through web start. The 1.2 Gb version should be sufficient for our data.

    +

    Download the bam file

    +

    Open a new terminal window on your laptop and navigate to your local workspace, but do not log in to NSC. Download the .bam and .bam.bai files you just generated with this command:

    +
    +
    +
    scp <nsc_username>@tetralith.nsc.uu.se:/proj/naiss2023-22-862/users/<nsc_username>/ngsworkflow/HG00097.bam* .
    +
    +
    +

    Check that the files are now present in your local workspace using ls -lrt.

    +

    Look at the bam file in IGV

    +
      +
    • In IGV, go to the popup menu in the upper left and set it to Human hg19.
      +
    • +
    • In the Tools menu, select Run igvtools. Choose the command Count and then use the Browse button next to the Input File line to select the bam file (not the bai) that you just downloaded. It will autofill the output file. Hit the Run button. This generates a .tdf file that allows you to see the coverage value for our bam file even at zoomed out views. Close the igvtools window.
      +
    • +
    • In the File menu, select Load from File and select your BAMs (not the .bai or the .tdf), which should appear in the tracks window. You will have to zoom in before you can see any reads. You can either select a region by click and drag, or by typing a region or a gene name in the text box at the top. Remember that we have data for the region chr2:136545000-136617000.
    • +
    +
    +
    +

    1.1.5 Questions

    +
      +
    1. What is the read length?
      +
    2. +
    3. How can you estimate the coverage at a specific position in IGV?
    4. +
    5. Which RefSeq Genes are located within the region chr2:136545000-136617000?
    6. +
    +
    +
    +
    +

    1.2 Variant Calling

    +
    +

    1.2.1 HaplotypeCaller

    +

    Now we will detect short variants in the bam file using GATK’s HaplotypeCaller. Go to your Cluster workspace and run:

    +
    offline-uppmax$ gatk --java-options -Xmx7g HaplotypeCaller -R human_g1k_v37_chr2.fasta -I HG00097.bam -O HG00097.vcf 
    +

    Check what new files were generated with ls -lrt.

    +
    +
    +

    1.2.2 Explore the vcf file

    +

    Now you have your first vcf file containing the raw variants in the region chr2:136545000-136617000 in sample HG00097. Please look at the vcf file with less and try to understand its structure.

    +

    VCF files contains meta-information lines starting with ##, a header line starting with #CHROM, and then data lines each containing information about one variant position in the genome. The header line defines the columns of the data lines, and to view the header line you can type this command:

    +
    offline-uppmax$ grep '#CHROM' HG00097.vcf
    +

    The meta-information lines starting with ##INFO defines how the data in the INFO column is encoded, and the meta-information lines starting with ##FORMAT defines how the data in the FORMAT column is encoded. To view the meta-information lines describing the INFO column use:

    +
    offline-uppmax$ grep '##INFO' HG00097.vcf
    +

    To view the meta-information lines describing the FORMAT column use:

    +
    offline-uppmax$ grep '##FORMAT' HG00097.vcf
    +

    Now lets look at the details of one specific genetic variant at position 2:136545844:

    +
    offline-uppmax$ grep '136545844' HG00097.vcf
    +

    For more detailed information about vcf files please have a look at The Variant Call Format specification.

    +
    +
    +

    1.2.3 Questions

    +
      +
    1. What column of the VCF file contains genotype information for the sample HG00097?
    2. +
    3. What does GT in the FORMAT column of the data lines mean?
    4. +
    5. What genotype does the sample HG00097 have at position 2:136545844?
    6. +
    7. What does AD in the FORMAT column of the data lines mean?
    8. +
    9. What are the allelic depths for the reference and alternative alles in sample HG00097 at position 2:136545844?
    10. +
    11. How many genetic variants was detected in the sample? The linux command grep -v "#" HG00097.vcf | wc -l extracts all lines in HG00097.vcf that don’t start with “#”, and counts these lines.
    12. +
    +
    +
    +

    1.2.4 Check vcf in IGV

    +

    Download the vcf file and its index to the local workspace on your laptop, just like you did with the bam file and its index earlier. Open a new terminal window on your laptop and navigate to your local workspace, but do not log in to NSC. Download the files that you just generated with:

    +
    +
    +
    scp <nsc_username>@tetralith.nsc.uu.se:/proj/naiss2023-22-862/users/<nsc_username>/ngsworkflow/HG00097.vcf* .
    +
    +
    +

    Please replace <nsc_nsc_username> with your NSC user name.
    +Note that the * in the end of the file name means that you will download all files that start with HG00097.vcf, so you will also download the vcf index.
    +Check that the files were properly downloaded to your local workspace using ls -lrt.

    +

    In IGV, in the File menu, select Load from File and select your vcf file (not the .idx file) and the bam file (not the .bai file) that you downloaded earlier. The vcf and bam files should appear in the tracks window. You will now see all the variants called in HG00097. You can view all variants in the LCT gene by typing the gene name in the search box, and you can look specifically at the variant at position chr2:136545844 by typing that position in the search box.

    +
    +
    +

    1.2.5 Questions

    +
      +
    1. Hover the mouse over the upper row of the vcf track. What is the reference and alternative alleles of the variant at position chr2:136545844?
    2. +
    3. Hover the mouse over the lower row of the vcf track and look under “Genotype Information”. What genotype does HG00097 have at position chr2:136545844? Is this the same as you found by looking directly in the vcf file in question 10?
    4. +
    5. Look in the bam track and count the number of reads that have “T” and “C”, respectively, at position chr2:136545844. How is this information captured under “Genotype Attributes”? (Again, hoover the mouse over the lower row of the vcf track.)
    6. +
    +
    +
    +
    +
    +

    2 Variant calling in cohort

    +

    If you have time, you can now try joint variant calling in all three samples. Each sample has to be processed with BWA mem as above, and then with HaplotypeCaller with the flag -ERC to generate one g.vcf file per sample. The individual g.vcf files should subsequently be combined with GATK’s CombineGVCFs, and translated into vcf format with GATK’s GenotypeGVCFs. The workflow below shows how the three samples should be processed and combined.

    +
    +
    +

    +
    +
    +

    You can run the commands one by one in the terminal as you did before. We have also made intermediary files available in case you don’t have time to complete all steps, please see links under each analysis step.

    +
    +
    +
    + +
    +
    +Note +
    +
    +
    +

    Optional: If you are interested in programming and have time, you can also try to write a simple SBATCH script and run all steps automatically. Please check out the SBATCH script section below if you would like to try this.

    +
    +
    +
    +

    2.1 BWA mem

    +

    Run BWA mem for all three samples in the data set. BWA mem should be run exactly as above but with the new sample names. Please note that you also need to adjust the SM field in the read group so that it matches the new sample name, otherwise the joint genotyping step will not work properly.

    +

    If you run out of time, please click below to get paths to precomputed bam files.

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/bam/HG00097.bam
    +/sw/courses/ngsintro/reseq/data/bam/HG00100.bam
    +/sw/courses/ngsintro/reseq/data/bam/HG00101.bam
    +
    +
    +
    +
    +

    2.2 Generate g.vcf files

    +

    HaplotypeCaller should also be run for all three samples, but this time the output for each sample needs to be in g.vcf format. This is accomplished with a small change in the HaploteypCaller command:

    +
    offline-uppmax$ gatk --java-options -Xmx7g HaplotypeCaller -R human_g1k_v37_chr2.fasta -ERC GVCF -I <sample.bam> -O <sample>.g.vcf 
    +

    Please replace with the real sample names.

    +

    If you run out of time, please click below to get paths to the precomputed g.vcf files.

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/vcf/HG00097.g.vcf
    +/sw/courses/ngsintro/reseq/data/vcf/HG00100.g.vcf
    +/sw/courses/ngsintro/reseq/data/vcf/HG00101.g.vcf
    +
    +
    +
    +
    +

    2.3 Joint genotyping

    +

    Once you have the g.vcf files for all samples you should perform joint genotype calling. To do this you first need to combine all individual .g.vcf files to one file using CombineGVCFs:

    +
    offline-uppmax$ gatk --java-options -Xmx7g CombineGVCFs -R human_g1k_v37_chr2.fasta -V <sample1>.g.vcf -V <sample2>.g.vcf -V <sample3>.g.vcf -O cohort.g.vcf
    +

    Please replace <sample1>, <sample2>, <sample3> with the real sample names.

    +

    Then run GATK’s GenoteypeGVC to generate a vcf file:

    +
    offline-uppmax$ gatk --java-options -Xmx7g GenotypeGVCFs -R human_g1k_v37_chr2.fasta -V cohort.g.vcf -O cohort.vcf
    +

    If you run out of time, please click below to get paths to the precomputed cohort.g.vcf and cohort.vcf files.

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/vcf/cohort.g.vcf
    +/sw/courses/ngsintro/reseq/data/vcf/cohort.vcf
    +
    +
    +
    +

    2.3.1 Questions

    +
      +
    1. How many data lines do the cohort.g.vcf file have? You can use the Linux command grep -v "#" cohort.g.vcf to extract all lines in “cohort.g.vcf” that don’t start with “#”, then |, and then wc -l to count those lines.
      +
    2. +
    3. How many data lines do the cohort.vcf file have?
      +
    4. +
    5. Explain the difference in number of data lines.
      +
    6. +
    7. Look at the header line of the cohort.vcf file. What columns does it have?
    8. +
    9. What is encoded in the last three columns of the data lines?
    10. +
    +
    +
    +
    +

    2.4 SBATCH script

    +
    +
    +
    + +
    +
    +Optional +
    +
    +
    +

    This section is only for those of you who want to try to run all steps automatically in bash scripts. Below is a skeleton script that can be used as a template. Please modify it to run all the steps in part two of this workshop. You might find it helpful to try each step for one sample in the interactive terminal, so that you know that a particular command is working, before you incorporate it in the script.

    +
    #!/bin/bash
    +module load bioinfo-tools
    +module load bwa/0.7.17
    +module load samtools/1.10
    +module load GATK/4.1.4.1
    +## loop through the samples:
    +for sample in HG00097 HG00100 HG00101;
    +do
    +  echo "Now analyzing: "$sample
    +  #Fill in the code for running bwa-mem for each sample here
    +  #Fill in the code for samtools index for each sample here 
    +  #Fill in the code for HaplotypeCaller for each sample here
    +done
    +#Fill in the code for CombineGVCFs for all samples here
    +#Fill in the code for GenotypeGVCFs here
    +

    Please save the sbatch script in your cluster folder and call it “joint_genotyping.sh” or similar. Make the script executable by this command:

    +
    chmod u+x joint_genotyping.sh
    +

    Use this command to run the script in the singularity container:

    +
    ./joint_genotyping.sh
    +

    If you would like more help with creating the bash script, please look at our example solution:

    +
    +
    +
    #!/bin/bash
    +
    +module load bioinfo-tools
    +module load bwa/0.7.17
    +module load samtools/1.10
    +module load GATK/4.1.4.1
    +
    +for sample in HG00097 HG00100 HG00101;
    +do
    +  echo "Now analyzing: "$sample
    +  bwa mem -R "@RG\tID:readgroupx\tPU:flowcellx_lanex\tSM:"$sample"\tLB:libraryx\tPL:illumina" -t 1 human_g1k_v37_chr2.fasta $sample"_1.fq" $sample"_2.fq" | samtools sort > $sample".bam"
    +  samtools index $sample".bam"
    +  gatk --java-options -Xmx7g HaplotypeCaller -R human_g1k_v37_chr2.fasta -ERC GVCF -I $sample".bam" -O $sample".g.vcf"
    +done
    +gatk --java-options -Xmx7g CombineGVCFs -R human_g1k_v37_chr2.fasta -V HG00097.g.vcf -V HG00100.g.vcf -V HG00101.g.vcf -O cohort.g.vcf
    +gatk --java-options -Xmx7g GenotypeGVCFs -R human_g1k_v37_chr2.fasta -V cohort.g.vcf -O cohort.vcf
    +
    +
    +

    Please answer the questions above.

    +
    +
    +
    +
    +

    2.5 Check combined vcf file in IGV

    +

    Download the file cohort.vcf and its index, as well as HG00100.bam and HG00101.bam and their indexes to your local workspace as described above. Then open cohort.vcf, HG00097.bam, HG00100.bam and HG00101.bam in IGV as described above. This time lets look at the variant rs4988235, located at position chr2:136608646 in the HG19 reference genome, that has been shown to lead to lactose persistence.

    +
    +

    2.5.1 Questions

    +
      +
    1. What is the reference and alternative alleles at chr2:136608646?
    2. +
    3. What genotype do the three samples have at chr2:136608646? Note how genotypes are color coded in IGV.
    4. +
    5. Should any of the individuals avoid drinking milk?
      +
    6. +
    7. Now compare the data shown in IGV with the data in the VCF file. Extract the row for the chr2:136608646 variant in the cohort.vcf file, for example using grep '136608646' cohort.vcf. What columns of the vcf file contain the information shown in the upper part of the vcf track in IGV?
    8. +
    9. What columns of the vcf file contain the information shown in the lower part of the vcf track?
    10. +
    11. Zoom out so that you can see the MCM6 and LCT genes. Is the variant at chr2:136608646 locate within the LCT gene?
      +If you are interested in how this variant affects lactose tolerance please read the article by Mattar et al presented above, or in OMIM.
    12. +
    +
    +
    +
    +
    +

    3 GATK’s best practices

    +

    The third part of this workshop will take you through additional refinement steps that are recommended in GATKs best practices for germline short variant discovery, illustrated in the flowchart below. You can either run the steps command by command in your reserved node, or using a similar script as described above.

    +
    +
    +

    +
    +
    +
    +

    3.1 BWA mem

    +

    Run BWA mem for all three samples in the data set. BWA mem should be run exactly as above but with the new sample names. Please note that you also need to adjust the SM field in the read group so that it matches the new sample name.

    +
    +
    +

    3.2 Mark Duplicates

    +

    Sometimes the same DNA fragment is sequenced multiple times, which leads to multiple reads from the same fragment in the fastq file. This can occur due to PCR amplification in the library preparation, or if one read cluster is incorrectly detected as multiple clusters by the sequencing instrument. If a duplicated read contains a genetic variant, the ratio of the two alleles might be obscured, which can lead to incorrect genotyping. It is therefore recommended (in most cases) to mark duplicate reads so that they are counted as one during genotyping.

    +

    Please read about Picard’s MarkDuplicates here. Picard’s MarkDuplicates has recently been incorporated into the GATK suite, but the usage example in GATKs documentation still describes how to call it via the stand alone Picard program. A usage example for the version of MarkDuplicates that is incorporated in GATK is (with this you don’t have to load the Picard module):

    +
    offline-uppmax$ gatk --java-options -Xmx7g MarkDuplicates \
    +      -I input.bam \
    +      -O marked_duplicates.bam \
    +      -M marked_dup_metrics.txt
    +

    If you would like more help you can sneak peek at our example solution for HG00097 below.

    +
    +
    +
    offline-uppmax$ gatk --java-options -Xmx7g MarkDuplicates -I HG00097.bam -O HG00097.md.bam -M HG00097_mdmetrics.txt
    +
    +
    +
    +
    +

    3.3 Recalibrate Base Quality Scores

    +

    Another source of error is systematic biases in the assignment of base quality scores by the sequencing instrument. This can be corrected by GATK’s Base Quality Score Recalibration. In short, you first use BaseRecalibrator to build a recalibration model, and then ApplyBQSR to recalibrate the base qualities in your bam file.
    +BaseRecalibrator requires a file with known SNPs as input. This file is available in the data folder on UPPMAX:

    +
    +
    +
    /sw/courses/ngsintro/reseq/data/ref/1000G_phase1.snps.high_confidence.b37.chr2.vcf
    +
    +
    +

    Please use GATK’s documentation to recalibrate the base quality scores in your data. If you would like more help you can sneak peek at our example solution for HG00097 below.

    +
    +
    +
    offline-uppmax$ gatk --java-options -Xmx7g BaseRecalibrator -R human_g1k_v37_chr2.fasta -I HG00097.md.bam> --known-sites /sw/courses/ngsintro/reseq/data/ref/1000G_phase1.snps.high_confidence.b37.chr2.vcf -O HG00097.recal.table
    +offline-uppmax$ gatk --java-options -Xmx7g ApplyBQSR -R human_g1k_v37_chr2.fasta -I HG00097.md.bam --bqsr-recal-file HG00097.recal.table -O HG00097.recal.bam
    +
    +
    +
    +
    +

    3.4 Generate g.vcf files

    +

    HaplotypeCaller should also be run for all three samples, and the output should be in g.vcf exactly as described above. This time use recalibrated bam files as input.

    +
    +
    +

    3.5 Joint genotyping

    +

    Once you have the g.vcf files for all samples you should perform joint genotype calling. This should be done with the commands CombineGVCFs and GenotypeGVCFs exactly as described above, but you should use the g.vcf files generated from the recalibrated bam files as input.

    +
    +
    +

    3.6 Variant Filtering

    +

    HaplotypeCaller is designed to be very sensitive, which is good because it minimises the chance of missing real variants. However, it means that the number of false positives can be quite large, so we need to filter the raw callset. GATK offers two ways to filter variants:

    +
      +
    1. The variant quality score recalibration (VQSR) method uses machine learning to identify variants that are likely to be real. This is the best method if you have a lot of data, for example one whole genome sequence sample or several whole exome samples.
    2. +
    3. If you have less data you can use hard filters as described here.
    4. +
    +

    Since we have very little data we will use hard filters. The parameters are slightly different for SNVs and INDELs, so you need to first select all SNVs using SelectVariants and filter them using VariantFiltration with the parameters suggested for SNVs. Then select all INDELs and filter them with the parameters suggested for INDELs. Finally merge the SNVs and INDELs to get all variants in one file using MergeVCFs. If you would like more help you can sneak peek at our example solution for HG00097 below.

    +

    Filter SNVs:

    +
    +
    +
    offline-uppmax$ gatk --java-options -Xmx7g SelectVariants 
    +  -R human_g1k_v37_chr2.fasta 
    +  -V cohort.vcf 
    +  --select-type-to-include SNP 
    +  -O cohort.snvs.vcf
    +  
    +offline-uppmax$ gatk --java-options -Xmx7g VariantFiltration 
    +  -R human_g1k_v37_chr2.fasta 
    +  -V cohort.snvs.vcf 
    +  -O cohort.snvs.filtered.vcf 
    +  --filter-name QDfilter --filter-expression "QD < 2.0"  
    +  --filter-name MQfilter --filter-expression "MQ < 40.0"  
    +  --filter-name FSfilter --filter-expression "FS > 60.0"
    +
    +
    +

    Filter INDELs:

    +
    +
    +
    offline-uppmax$ gatk --java-options -Xmx7g SelectVariants 
    +  -R human_g1k_v37_chr2.fasta 
    +  -V cohort.vcf 
    +  --select-type-to-include INDEL 
    +  -o cohort.indels.vcf
    +
    +offline-uppmax$ gatk --java-options -Xmx7g VariantFiltration 
    +  -R human_g1k_v37_chr2.fasta 
    +  -V cohort.indels.vcf 
    +  -O cohort.indels.filtered.vcf 
    +  --filter-name QDfilter --filter-expression "QD < 2.0" 
    +  --filter-name FSfilter --filter-expression "FS > 200.0"
    +
    +
    +

    Merge filtered SNVs and INDELs:

    +
    +
    +
    offline-uppmax$ gatk --java-options -Xmx7g MergeVcfs -I cohort.snvs.filtered.vcf -I cohort.indels.filtered.vcf -O cohort.filtered.vcf
    +
    +
    +

    Open your filtered vcf with less and page through it. It still has all the variant lines, but the FILTER column that was blank before is now filled in, with PASS or a list of the filters it failed. Note also that the filters that were run are described in the header section.

    +
    +
    +

    3.7 Precomputed files

    +

    If you run out of time, please click below to get the path to precomputed bam and vcf files for the GATK’s best practices section.

    +
    +
    +
    Path to intermediary and final bam files: /sw/courses/ngsintro/reseq/data/best_practise_bam
    +Path to intermediary and final vcf files: /sw/courses/ngsintro/reseq/data/best_practise_vcf
    +
    +
    +
    +
    +

    3.8 SBATCH script

    +

    We recommend you to incorporate the new steps into an SBATCH script similar to the one you created above for joint variant calling. Please try to complete the script for GATK’s best practices workflow. If you run out of time you can sneak peek at our example solution below.

    +
    +
    +
    #!/bin/bash
    +
    +## load modules
    +module load bioinfo-tools
    +module load bwa/0.7.17
    +module load samtools/1.10
    +module load GATK/4.1.4.1
    +
    +# define path to reference genome
    +ref="/sw/courses/ngsintro/reseq/data/ref"
    +
    +# make symbolic links
    +ln -s /sw/courses/ngsintro/reseq/data/ref/human_g1k_v37_chr2.fasta
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_1.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00097_2.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_1.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00100_2.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_1.fq
    +ln -s /sw/courses/ngsintro/reseq/data/fastq/HG00101_2.fq
    +
    +# index reference genome
    +bwa index -a bwtsw human_g1k_v37_chr2.fasta
    +samtools faidx human_g1k_v37_chr2.fasta
    +gatk --java-options -Xmx7g CreateSequenceDictionary -R human_g1k_v37_chr2.fasta -O human_g1k_v37_chr2.dict
    +
    +## loop through the samples:
    +for sample in HG00097 HG00100 HG00101;
    +do
    +  echo "Now analyzing: ${sample}"
    +  # map the reads
    +  bwa mem -R "@RG\tID:readgroupx\tPU:flowcellx_lanex\tSM:"$sample"\tLB:libraryx\tPL:illumina" -t 1 human_g1k_v37_chr2.fasta $sample"_1.fq" $sample"_2.fq" | samtools sort > $sample".bam"
    +  samtools index $sample".bam"
    +  # mark duplicates
    +  gatk --java-options -Xmx7g MarkDuplicates -I $sample".bam" -O $sample".md.bam" -M $sample"_mdmetrics.txt"
    +  # base quality score recalibration
    +  gatk --java-options -Xmx7g BaseRecalibrator -R human_g1k_v37_chr2.fasta -I $sample".md.bam" --known-sites $ref"/1000G_phase1.snps.high_confidence.b37.chr2.vcf" -O $sample".recal.table"
    +  gatk --java-options -Xmx7g ApplyBQSR -R human_g1k_v37_chr2.fasta -I $sample".md.bam" --bqsr-recal-file $sample".recal.table" -O $sample".recal.bam"
    +  # haplotypeCaller in -ERC mode
    +  gatk --java-options -Xmx7g HaplotypeCaller -R human_g1k_v37_chr2.fasta -ERC GVCF -I $sample".bam" -O $sample".g.vcf" 
    +done
    +
    +# joint genotyping
    +gatk --java-options -Xmx7g CombineGVCFs -R human_g1k_v37_chr2.fasta -V HG00097.g.vcf -V HG00100.g.vcf -V HG00101.g.vcf -O cohort.g.vcf
    +gatk --java-options -Xmx7g GenotypeGVCFs -R human_g1k_v37_chr2.fasta -V cohort.g.vcf -O cohort.vcf
    +# variant filtration SNPs
    +gatk --java-options -Xmx7g SelectVariants -R human_g1k_v37_chr2.fasta -V cohort.vcf --select-type-to-include SNP -O cohort.snvs.vcf
    +gatk --java-options -Xmx7g VariantFiltration -R human_g1k_v37_chr2.fasta -V cohort.snvs.vcf -O cohort.snvs.filtered.vcf --filter-name QDfilter --filter-expression "QD < 2.0" --filter-name MQfilter --filter-expression "MQ < 40.0"  --filter-name FSfilter --filter-expression "FS > 60.0"
    +# variant filtration indels
    +gatk --java-options -Xmx7g SelectVariants -R human_g1k_v37_chr2.fasta -V cohort.vcf --select-type-to-include INDEL -O cohort.indels.vcf
    +gatk --java-options -Xmx7g VariantFiltration -R human_g1k_v37_chr2.fasta -V cohort.indels.vcf -O cohort.indels.filtered.vcf --filter-name QDfilter --filter-expression "QD < 2.0" --filter-name FSfilter --filter-expression "FS > 200.0"
    +# merge filtered SNPs and indels
    +gatk --java-options -Xmx7g MergeVcfs -I cohort.snvs.filtered.vcf -I cohort.indels.filtered.vcf -O cohort.filtered.vcf
    +
    +
    +
    +
    +

    3.9 Questions

    +
      +
    1. How many variants are present in the cohort.filtered.vcf file?
      +
    2. +
    3. How many variants have passed the filters?
      +
    4. +
    5. Look at the variants that did not pass the filters using grep -v 'PASS' cohort.filtered.vcf. Try to understand why these variants didn’t pass the filter.
    6. +
    +
    +
    +
    +

    Clean up

    +

    When the analysis is done and you are sure that you have the desired output, it is a good practice to remove intermediary files that are no longer needed. This will save disk space, and will be a crucial part of the routines when you work with your own data. Please think about which files you need to keep if you would like to go back and look at this lab later on. Remove the other files.

    +
    +
    +

    Answers

    +

    When you have finished the exercise, please have a look at this document with answers to all questions, and compare them with your answers.

    +
    +
    +

    Additional information

    + +

    Thanks for today!

    + + +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/2311/topics/vc/slide_vc.pdf b/2311/topics/vc/slide_vc.pdf new file mode 100644 index 00000000..ca9a0ffd Binary files /dev/null and b/2311/topics/vc/slide_vc.pdf differ diff --git a/2311/topics/vc/slide_vc.pptx b/2311/topics/vc/slide_vc.pptx new file mode 100644 index 00000000..fd96a6c2 Binary files /dev/null and b/2311/topics/vc/slide_vc.pptx differ diff --git a/2311/troubleshooting.html b/2311/troubleshooting.html new file mode 100644 index 00000000..a217cb44 --- /dev/null +++ b/2311/troubleshooting.html @@ -0,0 +1,686 @@ + + + + + + + + + + +Status & Troubleshooting + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +

    Status & Troubleshooting

    +
    +
    + Utility commands/scripts, troubleshooting, tips and suggestions. +
    +
    +
    +
    + + +
    + + + + +
    + + +
    + + + + +
    + + + + +
    +

    1 Status

    +

    Useful commands for monitoring status and user activity on UPPMAX.

    +
    +

    1.1 List jobs

    +

    List all jobs running an a project

    +
    +
    +
    squeue -A naiss2023-22-862 | sort -k 4
    +
    +
    +

    Sample output

    +
      23186770      core _interac analopez  R    2:15:00      1 r55
    +  23175660      core   (null)   anitav  R    6:52:28      1 r480
    +  23188713      core   (null)    annha  R    1:42:59      1 r480
    +  23185442      core   (null)    annha  R    2:47:11      1 r480
    +  23185433      core   (null) inene424  R    2:47:42      1 r479
    +  23185391      core   (null) inene424  R    2:50:04      1 r479
    +  23185540      core   (null)  shengyz  R    2:46:20      1 r480
    +     JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
    +  23185119      core   (null)    wingf  R    2:53:40      1 r479
    +
    +
    +

    1.2 Jobs per user

    +

    Sorted list of jobs per user

    +
    +
    +
    squeue -A naiss2023-22-862 | tr -s ' ' | cut -d' ' -f5 | sort | uniq -c | sort -k1
    +
    +
    +

    Sample output

    +
          1 tami
    +      1 tommal
    +      1 USER
    +      1 valeriia
    +      1 vioww
    +      1 vishnupk
    +      1 ylvafr
    +      2 mehran96
    +      2 miika
    +      3 mariasve
    +
    +
    +
    +

    1.3 Core usage

    +

    Total number of cores used on a project

    +
    +
    +
    squeue -A naiss2023-22-862 -o %C | awk '{total += $0} END{print total}'
    +
    +
    +
    +
    +

    1.4 Space usage

    +

    Amount of storage space used per project

    +
    +
    +
    uquota | grep naiss2023-22-862
    +
    +
    +

    Sample output

    +
    Your project     Your File Area         Unit       Usage  Quota Limit  Over Quota
    +---------------  ---------------------  --------  ------  -----------  ----------
    +snic2022-22-123  /proj/snic2022-22-123  GBytes       4.6          128
    +
    +
    +

    1.5 Reservation use

    +

    List users by reservation ID

    +
    +
    +
    squeue -R naiss2023-22-862_1 | sort -k 4
    +squeue -R naiss2023-22-862_2 | sort -k 4
    +squeue -R naiss2023-22-862_3 | sort -k 4
    +squeue -R naiss2023-22-862_4 | sort -k 4
    +squeue -R naiss2023-22-862_5 | sort -k 4
    +
    +
    +

    Sample output

    +
    23188713      core   (null)    annha  R    2:01:15      1 r480
    +23185442      core   (null)    annha  R    3:05:27      1 r480
    +23187840      core   (null)   evangc  R    2:11:02      1 r479
    +23186811      core   (null)  shengyz  R    2:34:45      1 r479
    +23185540      core   (null)  shengyz  R    3:04:36      1 r480
    +   JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
    +23185119      core   (null)    wingf  R    3:11:56      1 r479
    +
    +
    +
    +

    1.6 User activity

    +

    List last activity in a directory for all users

    +
    +
    +
    bash /sw/courses/utils/list_modification_times.sh /proj/naiss2023-22-862/nobackup/
    +
    +
    +

    Sample output

    +
    hkyle           2021-11-22 13:59:59     (/proj/snic2021-22-644/nobackup/hkyle/uppmax_tutorial/job_template)
    +malinh          2021-11-22 14:12:10     (/proj/snic2021-22-644/nobackup/malinh/slurm-23182638.out)
    +aliraz          2021-11-22 14:23:16     (/proj/snic2021-22-644/nobackup/aliraz/slurm-23184022.out)
    +kristaps        2021-11-22 14:25:08     (/proj/snic2021-22-644/nobackup/kristaps/uppmax_tutorial/jobData.sam)
    +anapin          2021-11-22 14:56:14     (/proj/snic2021-22-644/nobackup/anapin/uppmax_tutorial/uppmax_tutorial/jobData.sam)
    +analopez        2021-11-22 14:56:16     (/proj/snic2021-22-644/nobackup/analopez/uppmax_tutorial/jobData.sam)
    +private         Not available     ()
    +
    +
    +

    1.7 List reservations for a project

    +
    +
    +
    scontrol show res | grep naiss2023-22-862
    +
    +
    +

    Sample output

    +
    ReservationName=snic2021-22-644_wed StartTime=2021-11-24T12:00:00 EndTime=2021-11-24T18:00:00 Duration=06:00:00
    +   Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a
    +ReservationName=snic2021-22-644_thu StartTime=2021-11-25T08:30:00 EndTime=2021-11-25T17:30:00 Duration=09:00:00
    +   Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a
    +ReservationName=snic2021-22-644_fri StartTime=2021-11-26T08:30:00 EndTime=2021-11-26T13:30:00 Duration=05:00:00
    +   Users=(null) Accounts=snic2021-22-644 Licenses=(null) State=INACTIVE BurstBuffer=(null) Watts=n/a
    +
    +
    +

    1.8 List project members

    +
    +
    +
    projmembers naiss2023-22-862
    +
    +
    +

    Sample output

    +
    snic2022-22-123 abusiddi   Abu Bakar Siddique
    +snic2022-22-123 afifac     Afifa Enam Chowdhury
    +snic2022-22-123 asve0014   Ashish Verma
    +snic2022-22-123 berka      Berkay Paylar
    +snic2022-22-123 btleren    Betül Eren Keskin
    +
    +
    +

    1.9 User identity

    +

    Fetch user information from username

    +
    +
    finger username
    +
    +
    +
    +
    +

    2 Troubleshooting

    +
    +

    2.1 X-forwarding

    +
    +

    2.1.1 Setup

    +

    Mac users

    +
      +
    • Install Xquartz and restart computer
    • +
    • Open the Xquartz terminal and connect to Uppmax
    • +
    • In my recent macos (10.xxx) , x-forwarding only works if I explicitly run the Xquartz terminal
    • +
    +

    ssh -XY username@rackham.uppmax.uu.se

    +

    Also use this when logging in to the compute node!

    +

    ssh -XY username@node

    +

    Windows users

    +

    In MobaXTerm, go to settings and make sure that X-forwarding is checked.

    +
    +
    +

    2.1.2 Testing X-forwarding

    +

    Type xeyes in the terminal.

    +
    +
    +
    +

    2.2 Open .html documents on Rackham

    +

    First ensure X-forwarding works, then run firefox --no-remote filename.html

    +
    +
    +

    2.3 SCP fails with *

    +

    Sometimes students have problems to download files with SCP when there is a * in the end of the line. For example; scp user@rackham.uppmax.uu.se:/proj/bla/HG00097.bam* .. It needs to be changed to scp user@rackham.uppmax.uu.se:/proj/bla/HG00097.bam\* ..

    +
    +
    +

    2.4 Thinlinc

    +
    +

    2.4.1 Login

    +

    When logging in through an installed client, username/password seems to work. When logging in through the browser, username/password+2FA may be required.

    +
    +
    +

    2.4.2 Minimize the ThinLinc window

    +

    On a Mac, press Fn + F8, then select: Minimize window.

    +
    +
    +

    2.4.3 Gedit opening issues

    +

    When opening it from the terminal (gedit &), it was not able to connect to a display to show the graphics. The DISPLAY variable was empty. This was when using ThinLinc, so it should have worked. The issue was solved by opening gedit from the menu. Gedit could be labelled Text Editor.

    +
    +
    +
    +

    2.5 Set persistent home directory in MobaXTerm

    +

    This is to specify where the home directory in MobaXTerm is located in the computer’s file system. In Settings > Configuration, set the persistent home directory to a suitable folder. Restart MobaXTerm.

    +
    +
    +

    2.6 Typing $ on a Swedish keyboard

    +

    Press AltGr + 4.

    +
    +
    +

    2.7 Black background for XQuartz windows on M1 Mac

    +

    As documented here, run:

    +
    +
    defaults write org.xquartz.X11 enable_render_extension 0
    +
    +
    + + +
    +
    + +
    + +
    + + + + + + \ No newline at end of file