diff --git a/docs/devel/Orchestrating-Hi-C-analysis-with-Bioconductor.pdf b/docs/devel/Orchestrating-Hi-C-analysis-with-Bioconductor.pdf new file mode 100644 index 0000000..78e0b04 Binary files /dev/null and b/docs/devel/Orchestrating-Hi-C-analysis-with-Bioconductor.pdf differ diff --git a/docs/devel/assets/cover.jpg b/docs/devel/assets/cover.jpg new file mode 100644 index 0000000..752fb86 Binary files /dev/null and b/docs/devel/assets/cover.jpg differ diff --git a/docs/devel/index.html b/docs/devel/index.html new file mode 100644 index 0000000..8f40d3e --- /dev/null +++ b/docs/devel/index.html @@ -0,0 +1,1066 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

Orchestrating Hi-C analysis with Bioconductor

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

+

Package: OHCA
Authors: Jacques Serizay [aut, cre]
Compiled: 2023-11-07
Package version: 0.98.1
R version: R Under development (unstable) (2023-11-02 r85465)
BioC version: 3.19
License: MIT + file LICENSE

+

Welcome

+

This is the landing page of the β€œOrchestrating Hi-C analysis with Bioconductor” book. The primary aim of this book is to introduce the R user to Hi-C analysis. This book starts with key concepts important for the analysis of chromatin conformation capture and then presents Bioconductor tools that can be leveraged to process, analyze, explore and visualize Hi-C data.

+

Table of contents

+

This book is divided in three parts:

+

Part I: Introduction to Hi-C analysis

+ +

Part II: In-depth Hi-C analysis

+ +

Part III: Hi-C analysis workflows

+

Installation & requirements

+

General audience

+

This books aims to demonstrate how to pre-process, parse and investigate Hi-C data in R. For this reason, a significant portion of this book consists of executable R code chunks. To be able to reproduce the examples demonstrated in this book and go further in the analysis of your real datasets, you will need to rely on several dependencies.

+
    +
  • +R >= 4.3 is required. You can check R version by typing version in an R console or in RStudio. If you do not have R >= 4.3 installed, you will need to update your R version, as most extra dependencies will require R >= 4.3.
  • +
+
+ +
+
+

Detailed instructions are available here to install R 4.3 on a Linux machine (Ubuntu 22.04).

+

Briefly, to install pre-compiled version of R 4.3.0:

+
+
# This is adapted from Posit (https://docs.posit.co/resources/install-r/)
+export R_VERSION=4.3.0
+
+# Install curl and gdebi-core
+sudo apt update -qq
+sudo apt install curl gdebi-core -y
+
+# Fetching the `.deb` install file from Posit repository
+curl -O https://cdn.rstudio.com/r/ubuntu-2204/pkgs/r-${R_VERSION}_1_amd64.deb
+
+# Install R
+sudo gdebi r-${R_VERSION}_1_amd64.deb --non-interactive -q
+
+# Optional: create a symlink to add R to your PATH
+sudo ln -s /opt/R/${R_VERSION}/bin/R /usr/local/bin/R
+
+

If you have some issues when installing the Hi-C packages listed below, you may need to install the following system libraries:

+
+
sudo apt update -qq
+sudo apt install -y \
+    automake make cmake fort77 gfortran \
+    bzip2 unzip ftp build-essential \
+    libc6 libreadline-dev \
+    libpng-dev libjpeg-dev libtiff-dev \
+    libx11-dev libxt-dev x11-common \
+    libharfbuzz-dev libfribidi-dev \
+    libfreetype6-dev libfontconfig1-dev \
+    libbz2-dev liblzma-dev libtool \
+    libxml2 libxml2-dev \
+    libzstd-dev zlib1g-dev \
+    libdb-dev libglu1-mesa-dev \
+    libncurses5-dev libghc-zlib-dev libncurses-dev \
+    libpcre3-dev libxml2-dev libblas-dev libzmq3-dev \
+    libssl-dev libcurl4-openssl-dev \
+    libgsl-dev libeigen3-dev libboost-all-dev \
+    libgtk2.0-dev xvfb xauth xfonts-base apt-transport-https \
+    libhdf5-dev libudunits2-dev libgdal-dev libgeos-dev \
+    libproj-dev libnode-dev libmagick++-dev
+
+
+
+
+
    +
  • +Bioconductor >= 3.18 is also required. You can check whether Bioconductor is available and its version in R by typing BiocManager::version(). If you do not have BiocManager >= 3.18 installed, you will need to update it as follows:
  • +
+
+
if (!require("BiocManager", quietly = TRUE))
+    install.packages("BiocManager")
+BiocManager::install(version = "3.18")
+
+
    +
  • You will also need important packages, which will be described in length in this book. The following R code will set up most of the extra dependencies:
  • +
+
+
BiocManager::install("HiCExperiment", ask = FALSE)
+BiocManager::install("HiCool", ask = FALSE)
+BiocManager::install("HiContacts", ask = FALSE)
+BiocManager::install("HiContactsData", ask = FALSE)
+BiocManager::install("fourDNData", ask = FALSE)
+BiocManager::install("DNAZooData", ask = FALSE)
+
+

Developers

+

For developers or advanced R users, the devel versions of these packages can be installed along with their dependencies:

+
+
install.packages("pak", repos = "https://r-lib.github.io/p/pak/devel/")
+pak::pkg_install("js2264/HiCExperiment", ask = FALSE, dependencies = c("Depends", "Imports", "Suggests"))
+pak::pkg_install("js2264/HiCool", ask = FALSE, dependencies = c("Depends", "Imports", "Suggests"))
+pak::pkg_install("js2264/HiContacts", ask = FALSE, dependencies = c("Depends", "Imports", "Suggests"))
+pak::pkg_install("js2264/HiContactsData", ask = FALSE, dependencies = c("Depends", "Imports", "Suggests"))
+pak::pkg_install("js2264/fourDNData", ask = FALSE, dependencies = c("Depends", "Imports", "Suggests"))
+pak::pkg_install("js2264/DNAZooData", ask = FALSE, dependencies = c("Depends", "Imports", "Suggests"))
+
+

Docker image

+

If you have docker installed, the easiest approach would be to run the following command in a shell terminal:

+
+
docker run -it ghcr.io/js2264/ohca:latest R
+
+

This will fetch a docker image with the latest development versions of the aforementioned packages pre-installed, and initiate an interactive R session.

+

Reproducibility

+

Building book

+

The OHCA book has been rendered in R thanks to a number of packages, including but not only:

+
    +
  • devtools
  • +
  • quarto
  • +
  • rebook
  • +
+

To build this book locally, you can run:

+
+
+
+
bash
+
+
git clone git@github.com:js2264/OHCA.git && cd OHCA
+quarto render
+
+
+
+
+
+ +
+
+Warning +
+
+
+

All dependencies listed above will be required!

+
+
+

The actual rendering of this book is done by GitHub Actions, and the rendered static website is hosted by GitHub Pages.

+

Session info

+
+ +
+
+
+
sessioninfo::session_info(
+    installed.packages()[,"Package"], 
+    include_base = TRUE
+)
+##  ─ Session info ────────────────────────────────────────────────────────────
+##   setting  value
+##   version  R Under development (unstable) (2023-11-02 r85465)
+##   os       Ubuntu 22.04.3 LTS
+##   system   x86_64, linux-gnu
+##   ui       X11
+##   language (EN)
+##   collate  C
+##   ctype    en_US.UTF-8
+##   tz       Etc/UTC
+##   date     2023-11-07
+##   pandoc   3.1.1 @ /usr/local/bin/ (via rmarkdown)
+##  
+##  ─ Packages ────────────────────────────────────────────────────────────────
+##   package                     * version    date (UTC) lib source
+##   abind                         1.4-5      2016-07-21 [2] CRAN (R 4.4.0)
+##   aggregation                   1.0.1      2018-01-25 [2] CRAN (R 4.4.0)
+##   AnnotationDbi                 1.65.2     2023-11-03 [2] Bioconductor
+##   AnnotationFilter              1.27.0     2023-10-24 [2] Bioconductor
+##   AnnotationHub                 3.11.0     2023-10-25 [2] Bioconductor
+##   askpass                       1.2.0      2023-09-03 [2] CRAN (R 4.4.0)
+##   backports                     1.4.1      2021-12-13 [2] CRAN (R 4.4.0)
+##   base                        * 4.4.0      2023-11-05 [3] local
+##   base64enc                     0.1-3      2015-07-28 [2] CRAN (R 4.4.0)
+##   basilisk                      1.15.0     2023-10-24 [2] Bioconductor
+##   basilisk.utils                1.15.0     2023-10-24 [2] Bioconductor
+##   beeswarm                      0.4.0      2021-06-01 [2] CRAN (R 4.4.0)
+##   BH                            1.81.0-1   2023-01-22 [2] CRAN (R 4.4.0)
+##   Biobase                       2.63.0     2023-10-24 [2] Bioconductor
+##   BiocFileCache                 2.11.1     2023-10-26 [2] Bioconductor
+##   BiocGenerics                  0.49.1     2023-11-01 [2] Bioconductor
+##   BiocIO                        1.13.0     2023-10-24 [2] Bioconductor
+##   BiocManager                   1.30.22    2023-08-08 [2] CRAN (R 4.4.0)
+##   BiocParallel                  1.37.0     2023-10-24 [2] Bioconductor
+##   BiocStyle                     2.31.0     2023-10-24 [2] Bioconductor
+##   BiocVersion                   3.19.1     2023-10-26 [2] Bioconductor
+##   biomaRt                       2.59.0     2023-10-25 [2] Bioconductor
+##   Biostrings                    2.71.1     2023-10-25 [2] Bioconductor
+##   biovizBase                    1.51.0     2023-10-25 [2] Bioconductor
+##   bit                           4.0.5      2022-11-15 [2] CRAN (R 4.4.0)
+##   bit64                         4.0.5      2020-08-30 [2] CRAN (R 4.4.0)
+##   bitops                        1.0-7      2021-04-24 [2] CRAN (R 4.4.0)
+##   blob                          1.2.4      2023-03-17 [2] CRAN (R 4.4.0)
+##   bookdown                      0.36       2023-10-16 [2] CRAN (R 4.4.0)
+##   boot                          1.3-28.1   2022-11-22 [3] CRAN (R 4.4.0)
+##   brew                          1.0-8      2022-09-29 [2] CRAN (R 4.4.0)
+##   brio                          1.1.3      2021-11-30 [2] CRAN (R 4.4.0)
+##   BSgenome                      1.71.1     2023-11-01 [2] Bioconductor
+##   BSgenome.Hsapiens.UCSC.hg38   1.4.5      2023-11-07 [2] Bioconductor
+##   bslib                         0.5.1      2023-08-11 [2] CRAN (R 4.4.0)
+##   cachem                        1.0.8      2023-05-01 [2] CRAN (R 4.4.0)
+##   Cairo                         1.6-1      2023-08-18 [2] CRAN (R 4.4.0)
+##   calibrate                     1.7.7      2020-06-19 [2] CRAN (R 4.4.0)
+##   callr                         3.7.3      2022-11-02 [2] CRAN (R 4.4.0)
+##   checkmate                     2.3.0      2023-10-25 [2] CRAN (R 4.4.0)
+##   class                         7.3-22     2023-05-03 [3] CRAN (R 4.4.0)
+##   cli                           3.6.1      2023-03-23 [2] CRAN (R 4.4.0)
+##   clipr                         0.8.0      2022-02-22 [2] CRAN (R 4.4.0)
+##   cluster                       2.1.4      2022-08-22 [3] CRAN (R 4.4.0)
+##   CodeDepends                   0.6.5      2018-07-17 [2] CRAN (R 4.4.0)
+##   codetools                     0.2-19     2023-02-01 [3] CRAN (R 4.4.0)
+##   colorspace                    2.1-0      2023-01-23 [2] CRAN (R 4.4.0)
+##   commonmark                    1.9.0      2023-03-17 [2] CRAN (R 4.4.0)
+##   compiler                      4.4.0      2023-11-05 [3] local
+##   cowplot                       1.1.1      2020-12-30 [2] CRAN (R 4.4.0)
+##   cpp11                         0.4.6      2023-08-10 [2] CRAN (R 4.4.0)
+##   crayon                        1.5.2      2022-09-29 [2] CRAN (R 4.4.0)
+##   credentials                   2.0.1      2023-09-06 [2] CRAN (R 4.4.0)
+##   crosstalk                     1.2.0      2021-11-04 [2] CRAN (R 4.4.0)
+##   csaw                          1.37.0     2023-10-24 [2] Bioconductor
+##   curl                          5.1.0      2023-10-02 [2] CRAN (R 4.4.0)
+##   data.table                    1.14.8     2023-02-17 [2] CRAN (R 4.4.0)
+##   datasets                    * 4.4.0      2023-11-05 [3] local
+##   DBI                           1.1.3      2022-06-18 [2] CRAN (R 4.4.0)
+##   dbplyr                        2.4.0      2023-10-26 [2] CRAN (R 4.4.0)
+##   DelayedArray                  0.29.0     2023-10-24 [2] Bioconductor
+##   deldir                        1.0-9      2023-05-17 [2] CRAN (R 4.4.0)
+##   desc                          1.4.2      2022-09-08 [2] CRAN (R 4.4.0)
+##   devtools                      2.4.5      2022-10-11 [2] CRAN (R 4.4.0)
+##   dichromat                     2.0-0.1    2022-05-02 [2] CRAN (R 4.4.0)
+##   diffHic                       1.35.0     2023-10-24 [2] Bioconductor
+##   diffobj                       0.3.5      2021-10-05 [2] CRAN (R 4.4.0)
+##   digest                        0.6.33     2023-07-07 [2] CRAN (R 4.4.0)
+##   dir.expiry                    1.11.0     2023-10-24 [2] Bioconductor
+##   DNAZooData                    1.3.0      2023-10-31 [2] Bioconductor
+##   docopt                        0.7.1      2020-06-24 [2] CRAN (R 4.4.0)
+##   doParallel                    1.0.17     2022-02-07 [2] CRAN (R 4.4.0)
+##   downlit                       0.4.3      2023-06-29 [2] CRAN (R 4.4.0)
+##   dplyr                         1.1.3      2023-09-03 [2] CRAN (R 4.4.0)
+##   DT                            0.30       2023-10-05 [2] CRAN (R 4.4.0)
+##   dynamicTreeCut                1.63-1     2016-03-11 [2] CRAN (R 4.4.0)
+##   edgeR                         4.1.1      2023-10-29 [2] Bioconductor
+##   ellipsis                      0.3.2      2021-04-29 [2] CRAN (R 4.4.0)
+##   ensembldb                     2.27.0     2023-10-25 [2] Bioconductor
+##   evaluate                      0.23       2023-11-01 [2] CRAN (R 4.4.0)
+##   ExperimentHub                 2.11.0     2023-10-25 [2] Bioconductor
+##   fansi                         1.0.5      2023-10-08 [2] CRAN (R 4.4.0)
+##   farver                        2.1.1      2022-07-06 [2] CRAN (R 4.4.0)
+##   fastcluster                   1.2.3      2021-05-24 [2] CRAN (R 4.4.0)
+##   fastmap                       1.1.1      2023-02-24 [2] CRAN (R 4.4.0)
+##   filelock                      1.0.2      2018-10-05 [2] CRAN (R 4.4.0)
+##   fontawesome                   0.5.2      2023-08-19 [2] CRAN (R 4.4.0)
+##   forcats                       1.0.0      2023-01-29 [2] CRAN (R 4.4.0)
+##   foreach                       1.5.2      2022-02-02 [2] CRAN (R 4.4.0)
+##   foreign                       0.8-85     2023-09-09 [3] CRAN (R 4.4.0)
+##   formatR                       1.14       2023-01-17 [2] CRAN (R 4.4.0)
+##   Formula                       1.2-5      2023-02-24 [2] CRAN (R 4.4.0)
+##   fourDNData                    1.3.0      2023-10-31 [2] Bioconductor
+##   fs                            1.6.3      2023-07-20 [2] CRAN (R 4.4.0)
+##   futile.logger                 1.4.3      2016-07-10 [2] CRAN (R 4.4.0)
+##   futile.options                1.0.1      2018-04-20 [2] CRAN (R 4.4.0)
+##   generics                      0.1.3      2022-07-05 [2] CRAN (R 4.4.0)
+##   GenomeInfoDb                  1.39.0     2023-10-24 [2] Bioconductor
+##   GenomeInfoDbData              1.2.11     2023-11-07 [2] Bioconductor
+##   GenomicAlignments             1.39.0     2023-10-24 [2] Bioconductor
+##   GenomicFeatures               1.55.1     2023-10-29 [2] Bioconductor
+##   GenomicRanges                 1.55.1     2023-10-29 [2] Bioconductor
+##   gert                          2.0.0      2023-09-26 [2] CRAN (R 4.4.0)
+##   GGally                        2.1.2      2021-06-21 [2] CRAN (R 4.4.0)
+##   ggbeeswarm                    0.7.2      2023-04-29 [2] CRAN (R 4.4.0)
+##   ggbio                         1.51.0     2023-10-25 [2] Bioconductor
+##   ggplot2                       3.4.4      2023-10-12 [2] CRAN (R 4.4.0)
+##   ggrastr                       1.0.2      2023-06-01 [2] CRAN (R 4.4.0)
+##   gh                            1.4.0      2023-02-22 [2] CRAN (R 4.4.0)
+##   gitcreds                      0.1.2      2022-09-08 [2] CRAN (R 4.4.0)
+##   glue                          1.6.2      2022-02-24 [2] CRAN (R 4.4.0)
+##   GO.db                         3.18.0     2023-11-07 [2] Bioconductor
+##   GOTHiC                        1.39.0     2023-10-24 [2] Bioconductor
+##   graph                         1.81.0     2023-10-24 [2] Bioconductor
+##   graphics                    * 4.4.0      2023-11-05 [3] local
+##   grDevices                   * 4.4.0      2023-11-05 [3] local
+##   grid                          4.4.0      2023-11-05 [3] local
+##   gridExtra                     2.3        2017-09-09 [2] CRAN (R 4.4.0)
+##   gtable                        0.3.4      2023-08-21 [2] CRAN (R 4.4.0)
+##   gtools                        3.9.4      2022-11-27 [2] CRAN (R 4.4.0)
+##   here                          1.0.1      2020-12-13 [2] CRAN (R 4.4.0)
+##   HiCcompare                    1.25.0     2023-10-24 [2] Bioconductor
+##   HiCExperiment                 1.3.0      2023-10-24 [2] Bioconductor
+##   HiContacts                    1.5.0      2023-10-24 [2] Bioconductor
+##   HiContactsData                1.5.0      2023-10-31 [2] Bioconductor
+##   HiCool                        1.3.0      2023-10-24 [2] Bioconductor
+##   hicrep                        1.12.2     2023-11-07 [2] Github (TaoYang-dev/hicrep@e485dfa)
+##   highr                         0.10       2022-12-22 [2] CRAN (R 4.4.0)
+##   Hmisc                         5.1-1      2023-09-12 [2] CRAN (R 4.4.0)
+##   hms                           1.1.3      2023-03-21 [2] CRAN (R 4.4.0)
+##   htmlTable                     2.4.2      2023-10-29 [2] CRAN (R 4.4.0)
+##   htmltools                     0.5.7      2023-11-03 [2] CRAN (R 4.4.0)
+##   htmlwidgets                   1.6.2      2023-03-17 [2] CRAN (R 4.4.0)
+##   httpuv                        1.6.12     2023-10-23 [2] CRAN (R 4.4.0)
+##   httr                          1.4.7      2023-08-15 [2] CRAN (R 4.4.0)
+##   httr2                         0.2.3      2023-05-08 [2] CRAN (R 4.4.0)
+##   hwriter                       1.3.2.1    2022-04-08 [2] CRAN (R 4.4.0)
+##   impute                        1.77.0     2023-10-24 [2] Bioconductor
+##   ini                           0.3.1      2018-05-20 [2] CRAN (R 4.4.0)
+##   InteractionSet                1.31.0     2023-10-24 [2] Bioconductor
+##   interactiveDisplayBase        1.41.0     2023-10-24 [2] Bioconductor
+##   interp                        1.1-4      2023-03-31 [2] CRAN (R 4.4.0)
+##   IRanges                       2.37.0     2023-10-24 [2] Bioconductor
+##   isoband                       0.2.7      2022-12-20 [2] CRAN (R 4.4.0)
+##   iterators                     1.0.14     2022-02-05 [2] CRAN (R 4.4.0)
+##   jpeg                          0.1-10     2022-11-29 [2] CRAN (R 4.4.0)
+##   jquerylib                     0.1.4      2021-04-26 [2] CRAN (R 4.4.0)
+##   jsonlite                      1.8.7      2023-06-29 [2] CRAN (R 4.4.0)
+##   KEGGREST                      1.43.0     2023-10-24 [2] Bioconductor
+##   KernSmooth                    2.23-22    2023-07-10 [3] CRAN (R 4.4.0)
+##   knitr                         1.45       2023-10-30 [2] CRAN (R 4.4.0)
+##   labeling                      0.4.3      2023-08-29 [2] CRAN (R 4.4.0)
+##   lambda.r                      1.2.4      2019-09-18 [2] CRAN (R 4.4.0)
+##   later                         1.3.1      2023-05-02 [2] CRAN (R 4.4.0)
+##   lattice                       0.22-5     2023-10-24 [3] CRAN (R 4.4.0)
+##   latticeExtra                  0.6-30     2022-07-04 [2] CRAN (R 4.4.0)
+##   lazyeval                      0.2.2      2019-03-15 [2] CRAN (R 4.4.0)
+##   lifecycle                     1.0.4      2023-11-07 [2] CRAN (R 4.4.0)
+##   limma                         3.59.1     2023-10-30 [2] Bioconductor
+##   littler                       0.3.18     2023-03-26 [2] CRAN (R 4.4.0)
+##   locfit                        1.5-9.8    2023-06-11 [2] CRAN (R 4.4.0)
+##   magrittr                      2.0.3      2022-03-30 [2] CRAN (R 4.4.0)
+##   MASS                          7.3-60.1   2023-11-05 [3] local
+##   Matrix                        1.6-1.1    2023-09-18 [3] CRAN (R 4.4.0)
+##   MatrixGenerics                1.15.0     2023-10-24 [2] Bioconductor
+##   matrixStats                   1.1.0      2023-11-07 [2] CRAN (R 4.4.0)
+##   memoise                       2.0.1      2021-11-26 [2] CRAN (R 4.4.0)
+##   metapod                       1.11.0     2023-10-24 [2] Bioconductor
+##   methods                     * 4.4.0      2023-11-05 [3] local
+##   mgcv                          1.9-0      2023-07-11 [3] CRAN (R 4.4.0)
+##   mime                          0.12       2021-09-28 [2] CRAN (R 4.4.0)
+##   miniUI                        0.1.1.1    2018-05-18 [2] CRAN (R 4.4.0)
+##   multiHiCcompare               1.21.0     2023-10-24 [2] Bioconductor
+##   munsell                       0.5.0      2018-06-12 [2] CRAN (R 4.4.0)
+##   nlme                          3.1-163    2023-08-09 [3] CRAN (R 4.4.0)
+##   nnet                          7.3-19     2023-05-03 [3] CRAN (R 4.4.0)
+##   OHCA                          0.98.1     2023-11-07 [1] Bioconductor
+##   openssl                       2.1.1      2023-09-25 [2] CRAN (R 4.4.0)
+##   OrganismDbi                   1.45.0     2023-10-25 [2] Bioconductor
+##   packrat                       0.9.2      2023-09-05 [2] CRAN (R 4.4.0)
+##   parallel                      4.4.0      2023-11-05 [3] local
+##   patchwork                     1.1.3      2023-08-14 [2] CRAN (R 4.4.0)
+##   pbapply                       1.7-2      2023-06-27 [2] CRAN (R 4.4.0)
+##   pheatmap                      1.0.12     2019-01-04 [2] CRAN (R 4.4.0)
+##   pillar                        1.9.0      2023-03-22 [2] CRAN (R 4.4.0)
+##   pkgbuild                      1.4.2      2023-06-26 [2] CRAN (R 4.4.0)
+##   pkgconfig                     2.0.3      2019-09-22 [2] CRAN (R 4.4.0)
+##   pkgdown                       2.0.7      2022-12-14 [2] CRAN (R 4.4.0)
+##   pkgload                       1.3.3      2023-09-22 [2] CRAN (R 4.4.0)
+##   plogr                         0.2.0      2018-03-25 [2] CRAN (R 4.4.0)
+##   plotly                        4.10.3     2023-10-21 [2] CRAN (R 4.4.0)
+##   plyinteractions               1.1.0      2023-10-24 [2] Bioconductor
+##   plyr                          1.8.9      2023-10-02 [2] CRAN (R 4.4.0)
+##   plyranges                     1.23.0     2023-10-24 [2] Bioconductor
+##   png                           0.1-8      2022-11-29 [2] CRAN (R 4.4.0)
+##   praise                        1.0.0      2015-08-11 [2] CRAN (R 4.4.0)
+##   preprocessCore                1.65.0     2023-10-24 [2] Bioconductor
+##   prettyunits                   1.2.0      2023-09-24 [2] CRAN (R 4.4.0)
+##   processx                      3.8.2      2023-06-30 [2] CRAN (R 4.4.0)
+##   profvis                       0.3.8      2023-05-02 [2] CRAN (R 4.4.0)
+##   progress                      1.2.2      2019-05-16 [2] CRAN (R 4.4.0)
+##   promises                      1.2.1      2023-08-10 [2] CRAN (R 4.4.0)
+##   ProtGenerics                  1.35.0     2023-10-24 [2] Bioconductor
+##   ps                            1.7.5      2023-04-18 [2] CRAN (R 4.4.0)
+##   purrr                         1.0.2      2023-08-10 [2] CRAN (R 4.4.0)
+##   qqman                         0.1.9      2023-08-23 [2] CRAN (R 4.4.0)
+##   quarto                        1.3        2023-09-19 [2] CRAN (R 4.4.0)
+##   R6                            2.5.1      2021-08-19 [2] CRAN (R 4.4.0)
+##   ragg                          1.2.6      2023-10-10 [2] CRAN (R 4.4.0)
+##   rappdirs                      0.3.3      2021-01-31 [2] CRAN (R 4.4.0)
+##   RBGL                          1.79.0     2023-10-24 [2] Bioconductor
+##   rcmdcheck                     1.4.0      2021-09-27 [2] CRAN (R 4.4.0)
+##   RColorBrewer                  1.1-3      2022-04-03 [2] CRAN (R 4.4.0)
+##   Rcpp                          1.0.11     2023-07-06 [2] CRAN (R 4.4.0)
+##   RcppArmadillo                 0.12.6.6.0 2023-11-01 [2] CRAN (R 4.4.0)
+##   RcppEigen                     0.3.3.9.4  2023-11-02 [2] CRAN (R 4.4.0)
+##   RcppGSL                       0.3.13     2023-01-13 [2] CRAN (R 4.4.0)
+##   RcppParallel                  5.1.7      2023-02-27 [2] CRAN (R 4.4.0)
+##   RcppTOML                      0.2.2      2023-01-29 [2] CRAN (R 4.4.0)
+##   RcppZiggurat                  0.1.6      2020-10-20 [2] CRAN (R 4.4.0)
+##   RCurl                         1.98-1.13  2023-11-02 [2] CRAN (R 4.4.0)
+##   readr                         2.1.4      2023-02-10 [2] CRAN (R 4.4.0)
+##   rebook                        1.13.0     2023-10-24 [2] Bioconductor
+##   rematch2                      2.1.2      2020-05-01 [2] CRAN (R 4.4.0)
+##   remotes                       2.4.2.1    2023-07-18 [2] CRAN (R 4.4.0)
+##   renv                          1.0.3      2023-09-19 [2] CRAN (R 4.4.0)
+##   reshape                       0.8.9      2022-04-12 [2] CRAN (R 4.4.0)
+##   reshape2                      1.4.4      2020-04-09 [2] CRAN (R 4.4.0)
+##   restfulr                      0.0.15     2022-06-16 [2] CRAN (R 4.4.0)
+##   reticulate                    1.34.0     2023-10-12 [2] CRAN (R 4.4.0)
+##   Rfast                         2.0.9      2023-10-30 [2] CRAN (R 4.4.0)
+##   rhdf5                         2.47.0     2023-10-24 [2] Bioconductor
+##   rhdf5filters                  1.15.0     2023-10-24 [2] Bioconductor
+##   Rhdf5lib                      1.25.0     2023-10-24 [2] Bioconductor
+##   Rhtslib                       2.99.1     2023-11-02 [2] Bioconductor
+##   rjson                         0.2.21     2022-01-09 [2] CRAN (R 4.4.0)
+##   rlang                         1.1.2      2023-11-04 [2] CRAN (R 4.4.0)
+##   rmarkdown                     2.25       2023-09-18 [2] CRAN (R 4.4.0)
+##   rmdformats                    1.0.4      2022-05-17 [2] CRAN (R 4.4.0)
+##   roxygen2                      7.2.3      2022-12-08 [2] CRAN (R 4.4.0)
+##   rpart                         4.1.21     2023-10-09 [3] CRAN (R 4.4.0)
+##   rprojroot                     2.0.4      2023-11-05 [2] CRAN (R 4.4.0)
+##   Rsamtools                     2.19.2     2023-11-05 [2] Bioconductor
+##   rsconnect                     1.1.1      2023-10-04 [2] CRAN (R 4.4.0)
+##   RSpectra                      0.16-1     2022-04-24 [2] CRAN (R 4.4.0)
+##   RSQLite                       2.3.3      2023-11-04 [2] CRAN (R 4.4.0)
+##   rstudioapi                    0.15.0     2023-07-07 [2] CRAN (R 4.4.0)
+##   rtracklayer                   1.63.0     2023-10-24 [2] Bioconductor
+##   rversions                     2.1.2      2022-08-31 [2] CRAN (R 4.4.0)
+##   S4Arrays                      1.3.0      2023-10-24 [2] Bioconductor
+##   S4Vectors                     0.41.1     2023-10-26 [2] Bioconductor
+##   sass                          0.4.7      2023-07-15 [2] CRAN (R 4.4.0)
+##   scales                        1.2.1      2022-08-20 [2] CRAN (R 4.4.0)
+##   sessioninfo                   1.2.2      2021-12-06 [2] CRAN (R 4.4.0)
+##   shiny                         1.7.5.1    2023-10-14 [2] CRAN (R 4.4.0)
+##   ShortRead                     1.61.0     2023-10-24 [2] Bioconductor
+##   snow                          0.4-4      2021-10-27 [2] CRAN (R 4.4.0)
+##   sourcetools                   0.1.7-1    2023-02-01 [2] CRAN (R 4.4.0)
+##   SparseArray                   1.3.0      2023-10-24 [2] Bioconductor
+##   spatial                       7.3-17     2023-07-20 [3] CRAN (R 4.4.0)
+##   splines                       4.4.0      2023-11-05 [3] local
+##   statmod                       1.5.0      2023-01-06 [2] CRAN (R 4.4.0)
+##   stats                       * 4.4.0      2023-11-05 [3] local
+##   stats4                        4.4.0      2023-11-05 [3] local
+##   strawr                        0.0.91     2023-03-29 [2] CRAN (R 4.4.0)
+##   stringi                       1.7.12     2023-01-11 [2] CRAN (R 4.4.0)
+##   stringr                       1.5.0      2022-12-02 [2] CRAN (R 4.4.0)
+##   SummarizedExperiment          1.33.0     2023-10-24 [2] Bioconductor
+##   survival                      3.5-7      2023-08-14 [3] CRAN (R 4.4.0)
+##   sys                           3.4.2      2023-05-23 [2] CRAN (R 4.4.0)
+##   systemfonts                   1.0.5      2023-10-09 [2] CRAN (R 4.4.0)
+##   tcltk                         4.4.0      2023-11-05 [3] local
+##   terra                         1.7-55     2023-10-13 [2] CRAN (R 4.4.0)
+##   testthat                      3.2.0      2023-10-06 [2] CRAN (R 4.4.0)
+##   textshaping                   0.3.7      2023-10-09 [2] CRAN (R 4.4.0)
+##   tibble                        3.2.1      2023-03-20 [2] CRAN (R 4.4.0)
+##   tidyr                         1.3.0      2023-01-24 [2] CRAN (R 4.4.0)
+##   tidyselect                    1.2.0      2022-10-10 [2] CRAN (R 4.4.0)
+##   tinytex                       0.48       2023-10-13 [2] CRAN (R 4.4.0)
+##   tools                         4.4.0      2023-11-05 [3] local
+##   TopDom                        0.10.1     2021-05-06 [2] CRAN (R 4.4.0)
+##   tzdb                          0.4.0      2023-05-12 [2] CRAN (R 4.4.0)
+##   urlchecker                    1.0.1      2021-11-30 [2] CRAN (R 4.4.0)
+##   usethis                       2.2.2      2023-07-06 [2] CRAN (R 4.4.0)
+##   utf8                          1.2.4      2023-10-22 [2] CRAN (R 4.4.0)
+##   utils                       * 4.4.0      2023-11-05 [3] local
+##   VariantAnnotation             1.49.1     2023-10-31 [2] Bioconductor
+##   vctrs                         0.6.4      2023-10-12 [2] CRAN (R 4.4.0)
+##   vipor                         0.4.5      2017-03-22 [2] CRAN (R 4.4.0)
+##   viridis                       0.6.4      2023-07-22 [2] CRAN (R 4.4.0)
+##   viridisLite                   0.4.2      2023-05-02 [2] CRAN (R 4.4.0)
+##   vroom                         1.6.4      2023-10-02 [2] CRAN (R 4.4.0)
+##   waldo                         0.5.2      2023-11-02 [2] CRAN (R 4.4.0)
+##   WGCNA                         1.72-1     2023-01-18 [2] CRAN (R 4.4.0)
+##   whisker                       0.4.1      2022-12-05 [2] CRAN (R 4.4.0)
+##   withr                         2.5.2      2023-10-30 [2] CRAN (R 4.4.0)
+##   xfun                          0.41       2023-11-01 [2] CRAN (R 4.4.0)
+##   XML                           3.99-0.15  2023-11-02 [2] CRAN (R 4.4.0)
+##   xml2                          1.3.5      2023-07-06 [2] CRAN (R 4.4.0)
+##   xopen                         1.0.0      2018-09-17 [2] CRAN (R 4.4.0)
+##   xtable                        1.8-4      2019-04-21 [2] CRAN (R 4.4.0)
+##   XVector                       0.43.0     2023-10-24 [2] Bioconductor
+##   yaml                          2.3.7      2023-01-23 [2] CRAN (R 4.4.0)
+##   zip                           2.3.0      2023-04-17 [2] CRAN (R 4.4.0)
+##   zlibbioc                      1.49.0     2023-10-24 [2] Bioconductor
+##  
+##   [1] /tmp/RtmpixmP1F/Rinst529f91dd
+##   [2] /usr/local/lib/R/site-library
+##   [3] /usr/local/lib/R/library
+##  
+##  ─ Python configuration ────────────────────────────────────────────────────
+##   Python is not available
+##  
+##  ───────────────────────────────────────────────────────────────────────────
+
+
+
+
+ + +
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/data-representation.html b/docs/devel/pages/data-representation.html new file mode 100644 index 0000000..58e5bea --- /dev/null +++ b/docs/devel/pages/data-representation.html @@ -0,0 +1,2960 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 2  Hi-C data structures in R + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+2  Hi-C data structures in R +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter introduces the four main classes offered by Bioconductor leveraged to perform Hi-C analysis, describes their structure and how to interact with them:

+ +
+
+
+
+
+ +
+
+TL;DR +
+
+
+

Directly jump to the last section of this chapter to get a visual representation of these data structures.

+
+
+

+2.1 GRanges class

+

GRanges is a shorthand for GenomicRanges, a core class in Bioconductor. This class is primarily used to describe genomic ranges of any nature, e.g.  sets of promoters, SNPs, chromatin loop anchors, ….
+The data structure has been published in the seminal 2015 publication by the Bioconductor team (Huber et al. (2015)).

+

+2.1.1 GRanges fundamentals

+

The easiest way to generate a GRanges object is to coerce it from a vector of genomic coordinates in the UCSC format (e.g. "chr2:2004-4853"):

+
+
library(GenomicRanges)
+gr <- GRanges(c(
+    "chr2:2004-7853:+", 
+    "chr4:4482-9873:-", 
+    "chr5:1943-4203:+", 
+    "chr5:4103-5004:+"  
+))
+gr
+##  GRanges object with 4 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr2 2004-7853      +
+##    [2]     chr4 4482-9873      -
+##    [3]     chr5 1943-4203      +
+##    [4]     chr5 4103-5004      +
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+

A single GRanges object can contain one or several β€œranges”, or genomic intervals. To navigate between these ranges, GRanges can be subset using the standard R single bracket notation [:

+
+
gr[1]
+##  GRanges object with 1 range and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr2 2004-7853      +
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+gr[1:3]
+##  GRanges object with 3 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr2 2004-7853      +
+##    [2]     chr4 4482-9873      -
+##    [3]     chr5 1943-4203      +
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+

GenomicRanges objects aim to provide a natural description of genomic intervals (ranges) and are incredibly versatile. They extend the data.frame object and have four required pieces of information:

+
    +
  • +seqnames (i.e. chromosome names) (accessible with seqnames())
  • +
  • +start (accessible with start())
  • +
  • +end (accessible with end())
  • +
  • +strand (accessible with strand())
  • +
+
+
seqnames(gr)
+##  factor-Rle of length 4 with 3 runs
+##    Lengths:    1    1    2
+##    Values : chr2 chr4 chr5
+##  Levels(3): chr2 chr4 chr5
+
+start(gr)
+##  [1] 2004 4482 1943 4103
+
+end(gr)
+##  [1] 7853 9873 4203 5004
+
+strand(gr)
+##  factor-Rle of length 4 with 3 runs
+##    Lengths: 1 1 2
+##    Values : + - +
+##  Levels(3): + - *
+
+

Here is a graphical representation of a GRanges object, taken from Bioconductor course material:

+

+

We will now delve into the detailed structure and operability of GRanges objects.

+

+2.1.2 GRanges metadata

+

An important aspect of GRanges objects is that each entry (range) can have extra optional metadata. This metadata is stored in a rectangular DataFrame. Each column can contain a different type of information, e.g. a numerical vector, a factor, a list, …

+

One can directly access this DataFrame using the mcols() function, and individual columns of metadata using the $ notation:

+
+
mcols(gr)
+##  DataFrame with 4 rows and 0 columns
+mcols(gr)$GC <- c(0.45, 0.43, 0.44, 0.42)
+mcols(gr)$annotation <- factor(c(NA, 'promoter', 'enhancer', 'centromere'))
+mcols(gr)$extended.info <- c(
+    list(c(NA)), 
+    list(c(date = 2023, source = 'manual')), 
+    list(c(date = 2021, source = 'manual')), 
+    list(c(date = 2019, source = 'homology'))
+)
+mcols(gr)
+##  DataFrame with 4 rows and 3 columns
+##           GC annotation extended.info
+##    <numeric>   <factor>        <list>
+##  1      0.45 NA                    NA
+##  2      0.43 promoter     2023,manual
+##  3      0.44 enhancer     2021,manual
+##  4      0.42 centromere 2019,homology
+
+

When metadata columns are defined for a GRanges object, they are pasted next to the minimal 4 required GRanges fields, separated by a | character.

+
+
gr
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2004-7853      + |      0.45 NA                  <NA>
+##    [2]     chr4 4482-9873      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1943-4203      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4103-5004      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+

+2.1.3 Genomic arithmetics on individual GRanges objects

+

A GRanges object primarily describes a set of genomic ranges (it is in the name!). Useful genomic-oriented methods have been implemented to investigate individual GRanges object from a genomic perspective.

+

+2.1.3.1 Intra-range methods

+

Standard genomic arithmetics are possible with GRanges, e.g.  shifting ranges, resizing, trimming, … These methods are referred to as β€œintra-range” methods as they work β€œone-region-at-a-time”.

+
+
+
+ +
+
+Note +
+
+
+
    +
  • Each range of the input GRanges object is modified independently from the other ranges in the following code chunks.
  • +
  • Intra-range operations are endomorphisms: they all take GRanges inputs and always return GRanges objects.
  • +
+
+
+
    +
  • Shifting each genomic range in a GRanges object by a certain number of bases:
  • +
+
+
gr
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2004-7853      + |      0.45 NA                  <NA>
+##    [2]     chr4 4482-9873      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1943-4203      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4103-5004      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+# ----- Shift all genomic ranges towards the "right" (downstream in `+` strand), by 1000bp:
+shift(gr, 1000)
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames     ranges strand |        GC annotation extended.info
+##           <Rle>  <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2  3004-8853      + |      0.45 NA                  <NA>
+##    [2]     chr4 5482-10873      - |      0.43 promoter     2023,manual
+##    [3]     chr5  2943-5203      + |      0.44 enhancer     2021,manual
+##    [4]     chr5  5103-6004      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+# ----- Shift all genomic ranges towards the "left" (upstream in `+` strand), by 1000bp:
+shift(gr, -1000)
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 1004-6853      + |      0.45 NA                  <NA>
+##    [2]     chr4 3482-8873      - |      0.43 promoter     2023,manual
+##    [3]     chr5  943-3203      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 3103-4004      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+
    +
  • Narrowing each genomic range in a GRanges object by a certain number of bases:
  • +
+
+
gr
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2004-7853      + |      0.45 NA                  <NA>
+##    [2]     chr4 4482-9873      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1943-4203      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4103-5004      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+# ----- Extract 21st-40th subrange for each range in `gr`:
+narrow(gr, start = 21, end = 40)
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2024-2043      + |      0.45 NA                  <NA>
+##    [2]     chr4 4502-4521      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1963-1982      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4123-4142      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+width(narrow(gr, start = 21, end = 40))
+##  [1] 20 20 20 20
+
+
    +
  • Resizing each genomic range in a GRanges object to a certain number of bases:
  • +
+
+
gr
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2004-7853      + |      0.45 NA                  <NA>
+##    [2]     chr4 4482-9873      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1943-4203      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4103-5004      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+# ----- Resize `gr` entries to 100, fixed at the start of each range:
+resize(gr, 100, fix = "start")
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2004-2103      + |      0.45 NA                  <NA>
+##    [2]     chr4 9774-9873      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1943-2042      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4103-4202      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+# ----- Resize `gr` entries to 100, fixed at the start of each range, disregarding strand information:
+resize(gr, 100, fix = "start", ignore.strand = TRUE)
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2004-2103      + |      0.45 NA                  <NA>
+##    [2]     chr4 4482-4581      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1943-2042      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4103-4202      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+# ----- Resize `gr` entries to 1 bp, fixed at the center of each range:
+resize(gr, 1, fix = "center")
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2      4928      + |      0.45 NA                  <NA>
+##    [2]     chr4      7177      - |      0.43 promoter     2023,manual
+##    [3]     chr5      3073      + |      0.44 enhancer     2021,manual
+##    [4]     chr5      4553      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+
    +
  • Extracting flanking coordinates for each entry in gr:
  • +
+
+
gr
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2004-7853      + |      0.45 NA                  <NA>
+##    [2]     chr4 4482-9873      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1943-4203      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4103-5004      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+# ----- Extract 100bp UPSTREAM of each genomic range, according to range strandness:
+flank(gr, 100, start = TRUE)
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 1904-2003      + |      0.45 NA                  <NA>
+##    [2]     chr4 9874-9973      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1843-1942      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4003-4102      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+# ----- Extract 1bp DOWNSTREAM of each genomic range, according to range strandness:
+flank(gr, 1, start = FALSE)
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2      7854      + |      0.45 NA                  <NA>
+##    [2]     chr4      4481      - |      0.43 promoter     2023,manual
+##    [3]     chr5      4204      + |      0.44 enhancer     2021,manual
+##    [4]     chr5      5005      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+

Note how here again, strand information is crucial and correctly leveraged to extract β€œupstream” or β€œdownstream” flanking regions in agreement with genomic range orientation.

+
    +
  • Several arithmetics operators can also directly work with GRanges:
  • +
+
+
gr
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2004-7853      + |      0.45 NA                  <NA>
+##    [2]     chr4 4482-9873      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1943-4203      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4103-5004      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+gr + 100 # ----- Extend each side of the `GRanges` by a given number of bases
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 1904-7953      + |      0.45 NA                  <NA>
+##    [2]     chr4 4382-9973      - |      0.43 promoter     2023,manual
+##    [3]     chr5 1843-4303      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4003-5104      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+gr - 200 # ----- Shrink each side of the `GRanges` by a given number of bases 
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 2204-7653      + |      0.45 NA                  <NA>
+##    [2]     chr4 4682-9673      - |      0.43 promoter     2023,manual
+##    [3]     chr5 2143-4003      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4303-4804      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+gr * 1000 # ----- Zoom in by a given factor (effectively decreasing the `GRanges` width by the same factor)
+##  GRanges object with 4 ranges and 3 metadata columns:
+##        seqnames    ranges strand |        GC annotation extended.info
+##           <Rle> <IRanges>  <Rle> | <numeric>   <factor>        <list>
+##    [1]     chr2 4926-4930      + |      0.45 NA                  <NA>
+##    [2]     chr4 7175-7179      - |      0.43 promoter     2023,manual
+##    [3]     chr5 3072-3073      + |      0.44 enhancer     2021,manual
+##    [4]     chr5 4554-4553      + |      0.42 centromere 2019,homology
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+
+
+
+ +
+
+Going further +
+
+
+

To fully grasp how to operate GRanges objects, we highly recommend reading the detailed documentation for this class by typing ?GenomicRanges and ?GenomicRanges::`intra-range-methods`.

+
+
+

+2.1.3.2 Inter-range methods

+

Compared to β€œintra-range” methods described above, inter-range methods involve comparisons between ranges in a single GRanges object.

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

Compared to previous section, the result of each function described below depends on the entire set of ranges in the input GRanges object.

+
+
+
    +
  • Computing the β€œinverse” genomic ranges, i.e. ranges in-between the input ranges:
  • +
+
+
gaps(gr)
+##  GRanges object with 3 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr2    1-2003      +
+##    [2]     chr4    1-4481      -
+##    [3]     chr5    1-1942      +
+##    -------
+##    seqinfo: 3 sequences from an unspecified genome; no seqlengths
+
+
    +
  • For each entry in a GRanges, finding the index of the preceding/following/nearest genomic range:
  • +
+
+
precede(gr)
+##  [1] NA NA NA NA
+
+follow(gr)
+##  [1] NA NA NA NA
+
+nearest(gr)
+##  [1] NA NA  4  3
+
+
    +
  • Computing a coverage over a genome, optionally indicated a β€œscore” column from metadata:
  • +
+
+
coverage(gr, weight = 'GC')
+##  RleList of length 3
+##  $chr2
+##  numeric-Rle of length 7853 with 2 runs
+##    Lengths: 2003 5850
+##    Values : 0.00 0.45
+##  
+##  $chr4
+##  numeric-Rle of length 9873 with 2 runs
+##    Lengths: 4481 5392
+##    Values : 0.00 0.43
+##  
+##  $chr5
+##  numeric-Rle of length 5004 with 4 runs
+##    Lengths: 1942 2160  101  801
+##    Values : 0.00 0.44 0.86 0.42
+
+
+
+
+ +
+
+Going further +
+
+
+

To fully grasp how to operate GRanges objects, we highly recommend reading the detailed documentation for this class by typing ?GenomicRanges::`inter-range-methods`.

+
+
+

+2.1.4 Comparing multiple GRanges objects

+

Genomic analysis typically requires intersection of two sets of genomic ranges, e.g. to find which ranges from one set overlap with those from another set.

+

In the next examples, we will use two GRanges:

+
    +
  • +peaks represents dummy 8 ChIP-seq peaks
  • +
+
+
peaks <- GRanges(c(
+    'chr1:320-418',
+    'chr1:512-567',
+    'chr1:843-892',
+    'chr1:1221-1317', 
+    'chr1:1329-1372', 
+    'chr1:1852-1909', 
+    'chr1:2489-2532', 
+    'chr1:2746-2790'
+))
+peaks
+##  GRanges object with 8 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr1   320-418      *
+##    [2]     chr1   512-567      *
+##    [3]     chr1   843-892      *
+##    [4]     chr1 1221-1317      *
+##    [5]     chr1 1329-1372      *
+##    [6]     chr1 1852-1909      *
+##    [7]     chr1 2489-2532      *
+##    [8]     chr1 2746-2790      *
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+
    +
  • +TSSs represents dummy 3 gene promoters (Β± 10bp around the TSS)
  • +
+
+
genes <- GRanges(c(
+    'chr1:358-1292:+',
+    'chr1:1324-2343:+', 
+    'chr1:2732-2751:+'
+))
+TSSs <- resize(genes, width = 1, fix = 'start') + 10
+TSSs
+##  GRanges object with 3 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr1   348-368      +
+##    [2]     chr1 1314-1334      +
+##    [3]     chr1 2722-2742      +
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+

Let’s see how they overlap by plotting them:

+
+
library(ggplot2)
+peaks$type <- 'peaks'
+TSSs$type <- 'TSSs'
+ggplot() + 
+    ggbio::geom_rect(c(peaks, TSSs), aes(fill = type), facets = type~.) + 
+    ggbio::theme_alignment() + 
+    coord_fixed(ratio = 300)
+##  Registered S3 method overwritten by 'GGally':
+##    method from   
+##    +.gg   ggplot2
+##  Warning: The `facets` argument of `facet_grid()` is deprecated as of ggplot2 2.2.0.
+##  β„Ή Please use the `rows` argument instead.
+##  β„Ή The deprecated feature was likely used in the ggbio package.
+##    Please report the issue at <https://github.com/lawremi/ggbio/issues>.
+##  Scale for y is already present.
+##  Adding another scale for y, which will replace the existing scale.
+
+
+

+
+
+
+
+

+2.1.4.1 Finding overlaps between two GRanges sets

+
    +
  • Finding overlaps between a query and a subject
  • +
+

In our case, we want to identify which ChIP-seq peaks overlap with a TSS: the query is the set of peaks and the subject is the set of TSSs.

+

findOverlaps returns a Hits object listing which query ranges overlap with which subject ranges.

+
+
ov <- findOverlaps(query = peaks, subject = TSSs)
+ov
+##  Hits object with 3 hits and 0 metadata columns:
+##        queryHits subjectHits
+##        <integer>   <integer>
+##    [1]         1           1
+##    [2]         4           2
+##    [3]         5           2
+##    -------
+##    queryLength: 8 / subjectLength: 3
+
+

The Hits output clearly describes what overlaps with what:

+
    +
  • The query (peak) #1 overlaps with subject (TSS) #1 +
  • +
  • The query (peak) #5 overlaps with subject (TSS) #2 +
  • +
+
+
+
+ +
+
+Note +
+
+
+

Because no other query index or subject index is listed in the ov output, none of the remaining ranges from query overlap with ranges from subject.

+
+
+
    +
  • Subsetting by overlaps between a query and a subject
  • +
+

To directly subset ranges from query overlapping with ranges from a subject (e.g. to only keep peaks overlapping a TSS), we can use the subsetByOverlaps function. The output of subsetByOverlaps is a subset of the original GRanges object provided as a query, with retained ranges being unmodified.

+
+
subsetByOverlaps(peaks, TSSs)
+##  GRanges object with 3 ranges and 1 metadata column:
+##        seqnames    ranges strand |        type
+##           <Rle> <IRanges>  <Rle> | <character>
+##    [1]     chr1   320-418      * |       peaks
+##    [2]     chr1 1221-1317      * |       peaks
+##    [3]     chr1 1329-1372      * |       peaks
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+
    +
  • Counting overlaps between a query and a subject
  • +
+

Finally, the countOverlaps is used to count, for each range in a query, how many ranges in the subject it overlaps with.

+
+
countOverlaps(query = peaks, subject = TSSs)
+##  [1] 1 0 0 1 1 0 0 0
+
+
+
+
+ +
+
+Note +
+
+
+

Note that which GRanges goes in query or subject is crucial! Counting for each peak, the number of TSSs it overlaps with is very different from for each TSS, how many peaks it overlaps with.

+

In our case example, it would also be informative to count how many peaks overlap with each TSS, so we’d need to swap query and subject:

+
+
countOverlaps(query = TSSs, subject = peaks)
+##  [1] 1 2 0
+
+

We can add these counts to the original query object:

+
+
TSSs$n_peaks <- countOverlaps(query = TSSs, subject = peaks)
+TSSs
+##  GRanges object with 3 ranges and 2 metadata columns:
+##        seqnames    ranges strand |        type   n_peaks
+##           <Rle> <IRanges>  <Rle> | <character> <integer>
+##    [1]     chr1   348-368      + |        TSSs         1
+##    [2]     chr1 1314-1334      + |        TSSs         2
+##    [3]     chr1 2722-2742      + |        TSSs         0
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+
+
+
    +
  • +%over%, %within%, %outside% : handy operators
  • +
+

Handy operators exist that return logical vectors (same length as the query). They essentially are short-hands for specific findOverlaps() cases.

+

<query> %over% <subject>:

+
+
peaks %over% TSSs
+##  [1]  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE
+
+peaks[peaks %over% TSSs] # ----- Equivalent to `subsetByOverlaps(peaks, TSSs)`
+##  GRanges object with 3 ranges and 1 metadata column:
+##        seqnames    ranges strand |        type
+##           <Rle> <IRanges>  <Rle> | <character>
+##    [1]     chr1   320-418      * |       peaks
+##    [2]     chr1 1221-1317      * |       peaks
+##    [3]     chr1 1329-1372      * |       peaks
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+

<query> %within% <subject>:

+
+
peaks %within% TSSs
+##  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
+
+TSSs %within% peaks
+##  [1]  TRUE FALSE FALSE
+
+

<query> %outside% <subject>:

+
+
peaks %outside% TSSs
+##  [1] FALSE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE
+
+
+
+
+ +
+
+Going further +
+
+
+

To fully grasp how to find overlaps between GRanges objects, we highly recommend reading the detailed documentation by typing ?IRanges::`findOverlaps-methods`.

+
+
+

+2.1.4.2 Find nearest range from a subject for each range in a query

+

*Overlaps methods are not always enough to match a query to a subject. For instance, some peaks in the query might be very near to some TSSs in the subject, but not quite overlapping.

+
+
peaks[8]
+##  GRanges object with 1 range and 1 metadata column:
+##        seqnames    ranges strand |        type
+##           <Rle> <IRanges>  <Rle> | <character>
+##    [1]     chr1 2746-2790      * |       peaks
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+TSSs[3]
+##  GRanges object with 1 range and 2 metadata columns:
+##        seqnames    ranges strand |        type   n_peaks
+##           <Rle> <IRanges>  <Rle> | <character> <integer>
+##    [1]     chr1 2722-2742      + |        TSSs         0
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+ +

Rather than finding the overlapping range in a subject for each range in a query, we can find the nearest range.

+

For each range in the query, this returns the index of the range in the subject to which the query is the nearest.

+
+
nearest(peaks, TSSs)
+##  [1] 1 1 2 2 2 2 3 3
+
+TSSs[nearest(peaks, TSSs)]
+##  GRanges object with 8 ranges and 2 metadata columns:
+##        seqnames    ranges strand |        type   n_peaks
+##           <Rle> <IRanges>  <Rle> | <character> <integer>
+##    [1]     chr1   348-368      + |        TSSs         1
+##    [2]     chr1   348-368      + |        TSSs         1
+##    [3]     chr1 1314-1334      + |        TSSs         2
+##    [4]     chr1 1314-1334      + |        TSSs         2
+##    [5]     chr1 1314-1334      + |        TSSs         2
+##    [6]     chr1 1314-1334      + |        TSSs         2
+##    [7]     chr1 2722-2742      + |        TSSs         0
+##    [8]     chr1 2722-2742      + |        TSSs         0
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+ +

Alternatively, one can simply ask to calculate the distanceToNearest between ranges in a query and ranges in a subject.

+
+
distanceToNearest(peaks, TSSs)
+##  Hits object with 8 hits and 1 metadata column:
+##        queryHits subjectHits |  distance
+##        <integer>   <integer> | <integer>
+##    [1]         1           1 |         0
+##    [2]         2           1 |       143
+##    [3]         3           2 |       421
+##    [4]         4           2 |         0
+##    [5]         5           2 |         0
+##    [6]         6           2 |       517
+##    [7]         7           3 |       189
+##    [8]         8           3 |         3
+##    -------
+##    queryLength: 8 / subjectLength: 3
+
+peaks$distance_to_nearest_TSS <- mcols(distanceToNearest(peaks, TSSs))$distance
+
+

Note how close from a TSS the 8th peak was. It could be worth considering this as an overlap!

+

+2.2 GInteractions class

+

GRanges describe genomic ranges and hence are of general use to study 1D genome organization. To study chromatin interactions, we need a way to link pairs of GRanges. This is exactly what the GInteractions class does. This data structure is defined in the InteractionSet package and has been published in the 2016 paper by Lun et al. (Lun et al. (2016)).

+

+

+2.2.1 Building a GInteractions object from scratch

+

Let’s first define two parallel GRanges objects (i.e. two GRanges of same length). Each GRanges will contain 5 ranges.

+
+
gr_first <- GRanges(c(
+    'chr1:1-100', 
+    'chr1:1001-2000', 
+    'chr1:5001-6000', 
+    'chr1:8001-9000', 
+    'chr1:7001-8000'  
+))
+gr_second <- GRanges(c(
+    'chr1:1-100', 
+    'chr1:3001-4000', 
+    'chr1:8001-9000', 
+    'chr1:7001-8000', 
+    'chr2:13000-14000'  
+))
+
+

Because these two GRanges objects are of same length (5), one can β€œbind” them together by using the GInteractionsfunction. This effectively associate each entry from one GRanges to the entry aligned in the other GRanges object.

+
+
library(InteractionSet)
+gi <- GInteractions(gr_first, gr_second)
+gi
+##  GInteractions object with 5 interactions and 0 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2
+##            <Rle> <IRanges>         <Rle>   <IRanges>
+##    [1]      chr1     1-100 ---      chr1       1-100
+##    [2]      chr1 1001-2000 ---      chr1   3001-4000
+##    [3]      chr1 5001-6000 ---      chr1   8001-9000
+##    [4]      chr1 8001-9000 ---      chr1   7001-8000
+##    [5]      chr1 7001-8000 ---      chr2 13000-14000
+##    -------
+##    regions: 7 ranges and 0 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+

The way GInteractions objects are printed in an R console mimics that of GRanges, but pairs two β€œends” (a.k.a. anchors) of an interaction together, each end being represented as a separate GRanges range.

+
    +
  • Note that it is possible to have interactions joining two identical anchors.
  • +
+
+
gi[1]
+##  GInteractions object with 1 interaction and 0 metadata columns:
+##        seqnames1   ranges1     seqnames2   ranges2
+##            <Rle> <IRanges>         <Rle> <IRanges>
+##    [1]      chr1     1-100 ---      chr1     1-100
+##    -------
+##    regions: 7 ranges and 0 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+
    +
  • It is also technically possible (though not advised) to have interactions for which the β€œfirst” end is located after the β€œsecond” end along the chromosome.
  • +
+
+
gi[4]
+##  GInteractions object with 1 interaction and 0 metadata columns:
+##        seqnames1   ranges1     seqnames2   ranges2
+##            <Rle> <IRanges>         <Rle> <IRanges>
+##    [1]      chr1 8001-9000 ---      chr1 7001-8000
+##    -------
+##    regions: 7 ranges and 0 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+
    +
  • Finally, it is possible to define inter-chromosomal interactions (a.k.a. trans interactions).
  • +
+
+
gi[5]
+##  GInteractions object with 1 interaction and 0 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2
+##            <Rle> <IRanges>         <Rle>   <IRanges>
+##    [1]      chr1 7001-8000 ---      chr2 13000-14000
+##    -------
+##    regions: 7 ranges and 0 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+

+2.2.2 GInteractions specific slots

+

Compared to GRanges, extra slots are available for GInteractions objects, e.g. anchors and regions.

+

+2.2.2.1 Anchors

+

β€œAnchors” of a single genomic interaction refer to the two ends of this interaction. These anchors can be extracted from a GInteractions object using the anchors() function. This outputs a list of two GRanges, the first corresponding to the β€œleft” end of interactions (when printed to the console) and the second corresponding to the β€œright” end of interactions (when printed to the console).

+
+
# ----- This extracts the two sets of anchors ("first" and "second") from a GInteractions object
+anchors(gi)
+##  $first
+##  GRanges object with 5 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr1     1-100      *
+##    [2]     chr1 1001-2000      *
+##    [3]     chr1 5001-6000      *
+##    [4]     chr1 8001-9000      *
+##    [5]     chr1 7001-8000      *
+##    -------
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+##  
+##  $second
+##  GRanges object with 5 ranges and 0 metadata columns:
+##        seqnames      ranges strand
+##           <Rle>   <IRanges>  <Rle>
+##    [1]     chr1       1-100      *
+##    [2]     chr1   3001-4000      *
+##    [3]     chr1   8001-9000      *
+##    [4]     chr1   7001-8000      *
+##    [5]     chr2 13000-14000      *
+##    -------
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+# ----- We can query for the "first" or "second" set of anchors directly
+anchors(gi, "first")
+##  GRanges object with 5 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr1     1-100      *
+##    [2]     chr1 1001-2000      *
+##    [3]     chr1 5001-6000      *
+##    [4]     chr1 8001-9000      *
+##    [5]     chr1 7001-8000      *
+##    -------
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+anchors(gi, "second")
+##  GRanges object with 5 ranges and 0 metadata columns:
+##        seqnames      ranges strand
+##           <Rle>   <IRanges>  <Rle>
+##    [1]     chr1       1-100      *
+##    [2]     chr1   3001-4000      *
+##    [3]     chr1   8001-9000      *
+##    [4]     chr1   7001-8000      *
+##    [5]     chr2 13000-14000      *
+##    -------
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+

+2.2.2.2 Regions

+

β€œRegions” of a set of interactions refer to the universe of unique anchors represented in a set of interactions. Therefore, the length of the regions can only be equal to or strictly lower than twice the length of anchors.

+

The regions function returns the regions associated with a GInteractions object, stored as a GRanges object.

+
+
regions(gi)
+##  GRanges object with 7 ranges and 0 metadata columns:
+##        seqnames      ranges strand
+##           <Rle>   <IRanges>  <Rle>
+##    [1]     chr1       1-100      *
+##    [2]     chr1   1001-2000      *
+##    [3]     chr1   3001-4000      *
+##    [4]     chr1   5001-6000      *
+##    [5]     chr1   7001-8000      *
+##    [6]     chr1   8001-9000      *
+##    [7]     chr2 13000-14000      *
+##    -------
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+length(regions(gi))
+##  [1] 7
+
+length(anchors(gi, "first"))
+##  [1] 5
+
+

+2.2.3 GInteractions methods

+

GInteractions behave as an extension of GRanges. For this reason, many methods that work with GRanges will work seamlessly with GInteractions.

+

+2.2.3.1 Metadata

+

One can add metadata columns directly to a GInteractions object.

+
+
mcols(gi)
+##  DataFrame with 5 rows and 0 columns
+mcols(gi) <- data.frame(
+    idx = seq(1, length(gi)),
+    type = c("cis", "cis", "cis", "trans", "cis")
+)
+gi
+##  GInteractions object with 5 interactions and 2 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2 |       idx        type
+##            <Rle> <IRanges>         <Rle>   <IRanges> | <integer> <character>
+##    [1]      chr1     1-100 ---      chr1       1-100 |         1         cis
+##    [2]      chr1 1001-2000 ---      chr1   3001-4000 |         2         cis
+##    [3]      chr1 5001-6000 ---      chr1   8001-9000 |         3         cis
+##    [4]      chr1 8001-9000 ---      chr1   7001-8000 |         4       trans
+##    [5]      chr1 7001-8000 ---      chr2 13000-14000 |         5         cis
+##    -------
+##    regions: 7 ranges and 0 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+gi$type
+##  [1] "cis"   "cis"   "cis"   "trans" "cis"
+
+

Importantly, metadata columns can also be directly added to regions of a GInteractions object, since these regions are a GRanges object themselves!

+
+
regions(gi)
+##  GRanges object with 7 ranges and 0 metadata columns:
+##        seqnames      ranges strand
+##           <Rle>   <IRanges>  <Rle>
+##    [1]     chr1       1-100      *
+##    [2]     chr1   1001-2000      *
+##    [3]     chr1   3001-4000      *
+##    [4]     chr1   5001-6000      *
+##    [5]     chr1   7001-8000      *
+##    [6]     chr1   8001-9000      *
+##    [7]     chr2 13000-14000      *
+##    -------
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+regions(gi)$binID <- seq_along(regions(gi))
+regions(gi)$type <- c("P", "P", "P", "E", "E", "P", "P")
+regions(gi)
+##  GRanges object with 7 ranges and 2 metadata columns:
+##        seqnames      ranges strand |     binID        type
+##           <Rle>   <IRanges>  <Rle> | <integer> <character>
+##    [1]     chr1       1-100      * |         1           P
+##    [2]     chr1   1001-2000      * |         2           P
+##    [3]     chr1   3001-4000      * |         3           P
+##    [4]     chr1   5001-6000      * |         4           E
+##    [5]     chr1   7001-8000      * |         5           E
+##    [6]     chr1   8001-9000      * |         6           P
+##    [7]     chr2 13000-14000      * |         7           P
+##    -------
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+

+2.2.3.2 Sorting GInteractions +

+

The sort function works seamlessly with GInteractions objects. It sorts the interactions using a similar approach to that performed by pairtools sort ... for disk-stored .pairs files, sorting on the β€œfirst” anchor first, then for interactions with the same β€œfirst” anchors, sorting on the β€œsecond” anchor.

+
+
gi
+##  GInteractions object with 5 interactions and 2 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2 |       idx        type
+##            <Rle> <IRanges>         <Rle>   <IRanges> | <integer> <character>
+##    [1]      chr1     1-100 ---      chr1       1-100 |         1         cis
+##    [2]      chr1 1001-2000 ---      chr1   3001-4000 |         2         cis
+##    [3]      chr1 5001-6000 ---      chr1   8001-9000 |         3         cis
+##    [4]      chr1 8001-9000 ---      chr1   7001-8000 |         4       trans
+##    [5]      chr1 7001-8000 ---      chr2 13000-14000 |         5         cis
+##    -------
+##    regions: 7 ranges and 2 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+sort(gi)
+##  GInteractions object with 5 interactions and 2 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2 |       idx        type
+##            <Rle> <IRanges>         <Rle>   <IRanges> | <integer> <character>
+##    [1]      chr1     1-100 ---      chr1       1-100 |         1         cis
+##    [2]      chr1 1001-2000 ---      chr1   3001-4000 |         2         cis
+##    [3]      chr1 5001-6000 ---      chr1   8001-9000 |         3         cis
+##    [4]      chr1 7001-8000 ---      chr2 13000-14000 |         5         cis
+##    [5]      chr1 8001-9000 ---      chr1   7001-8000 |         4       trans
+##    -------
+##    regions: 7 ranges and 2 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+

+2.2.3.3 Swapping GInteractions anchors

+

For an individual interaction contained in a GInteractions object, the β€œfirst” and β€œsecond” anchors themselves can be sorted as well. This is called β€œpairs swapping”, and it is performed similarly to pairtools flip ... for disk-stored .pairs files. This ensures that interactions, when represented as a contact matrix, generate an upper-triangular matrix.

+
+
gi
+##  GInteractions object with 5 interactions and 2 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2 |       idx        type
+##            <Rle> <IRanges>         <Rle>   <IRanges> | <integer> <character>
+##    [1]      chr1     1-100 ---      chr1       1-100 |         1         cis
+##    [2]      chr1 1001-2000 ---      chr1   3001-4000 |         2         cis
+##    [3]      chr1 5001-6000 ---      chr1   8001-9000 |         3         cis
+##    [4]      chr1 8001-9000 ---      chr1   7001-8000 |         4       trans
+##    [5]      chr1 7001-8000 ---      chr2 13000-14000 |         5         cis
+##    -------
+##    regions: 7 ranges and 2 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+swapAnchors(gi)
+##  GInteractions object with 5 interactions and 2 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2 |       idx        type
+##            <Rle> <IRanges>         <Rle>   <IRanges> | <integer> <character>
+##    [1]      chr1     1-100 ---      chr1       1-100 |         1         cis
+##    [2]      chr1 1001-2000 ---      chr1   3001-4000 |         2         cis
+##    [3]      chr1 5001-6000 ---      chr1   8001-9000 |         3         cis
+##    [4]      chr1 7001-8000 ---      chr1   8001-9000 |         4       trans
+##    [5]      chr1 7001-8000 ---      chr2 13000-14000 |         5         cis
+##    -------
+##    regions: 7 ranges and 2 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+
+
+
+ +
+
+Note +
+
+
+

β€œSorting” and β€œswapping” a GInteractions object are two entirely different actions:

+
    +
  • β€œsorting” reorganizes all rows (interactions);
  • +
  • β€œswapping” anchors reorganizes β€œfirst” and β€œsecond” anchors for each interaction independently.
  • +
+
+
+

+2.2.3.4 GInteractions distance method

+

β€œDistance”, when applied to genomic interactions, typically refers to the genomic distance between the two anchors of a single interaction. For GInteractions, this is computed using the pairdist function.

+
+
gi
+##  GInteractions object with 5 interactions and 2 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2 |       idx        type
+##            <Rle> <IRanges>         <Rle>   <IRanges> | <integer> <character>
+##    [1]      chr1     1-100 ---      chr1       1-100 |         1         cis
+##    [2]      chr1 1001-2000 ---      chr1   3001-4000 |         2         cis
+##    [3]      chr1 5001-6000 ---      chr1   8001-9000 |         3         cis
+##    [4]      chr1 8001-9000 ---      chr1   7001-8000 |         4       trans
+##    [5]      chr1 7001-8000 ---      chr2 13000-14000 |         5         cis
+##    -------
+##    regions: 7 ranges and 2 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+pairdist(gi)
+##  [1]    0 2000 3000 1000   NA
+
+

Note that for β€œtrans” inter-chromosomal interactions, i.e. interactions with anchors on different chromosomes, the notion of genomic distance is meaningless and for this reason, pairdist returns a NA value.

+

The type argument of the pairdist() function can be tweaked to specify which type of β€œdistance” should be computed:

+
    +
  • +mid: The distance between the midpoints of the two regions (rounded down to the nearest integer) is returned (Default).
  • +
  • +gap: The length of the gap between the closest points of the two regions is computed - negative lengths are returned for overlapping regions, indicating the length of the overlap.
  • +
  • +span: The distance between the furthermost points of the two regions is computed.
  • +
  • +diag: The difference between the anchor indices is returned. This corresponds to a diagonal on the interaction space when bins are used in the β€˜regions’ slot of β€˜x’.
  • +

+2.2.3.5 GInteractions overlap methods

+

β€œOverlaps” for genomic interactions could be computed in different contexts:

+
    +
  • Case 1: Overlap between any of the two anchors of an interaction with a genomic range
  • +
  • Case 2: Overlap between anchors of an interaction with anchors of another interaction
  • +
  • Case 3: Spanning of the interaction β€œacross” a genomic range
  • +
+
+

Case 1: Overlap between any of the two anchors of an interaction with a genomic range

+
+

This is the default behavior of findOverlaps when providing a GInteractions object as query and a GRanges as a subject.

+
+
gr <- GRanges(c("chr1:7501-7600", "chr1:8501-8600"))
+findOverlaps(query = gi, subject = gr)
+##  Hits object with 4 hits and 0 metadata columns:
+##        queryHits subjectHits
+##        <integer>   <integer>
+##    [1]         3           2
+##    [2]         4           1
+##    [3]         4           2
+##    [4]         5           1
+##    -------
+##    queryLength: 5 / subjectLength: 2
+
+countOverlaps(gi, gr)
+##  [1] 0 0 1 2 1
+
+subsetByOverlaps(gi, gr)
+##  GInteractions object with 3 interactions and 2 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2 |       idx        type
+##            <Rle> <IRanges>         <Rle>   <IRanges> | <integer> <character>
+##    [1]      chr1 5001-6000 ---      chr1   8001-9000 |         3         cis
+##    [2]      chr1 8001-9000 ---      chr1   7001-8000 |         4       trans
+##    [3]      chr1 7001-8000 ---      chr2 13000-14000 |         5         cis
+##    -------
+##    regions: 7 ranges and 2 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+

Here again, the order matters!

+
+
countOverlaps(gr, gi)
+##  [1] 2 2
+
+

And again, the %over% operator can be used here:

+
+
gi %over% gr
+##  [1] FALSE FALSE  TRUE  TRUE  TRUE
+
+gi[gi %over% gr] # ----- Equivalent to `subsetByOverlaps(gi, gr)`
+##  GInteractions object with 3 interactions and 2 metadata columns:
+##        seqnames1   ranges1     seqnames2     ranges2 |       idx        type
+##            <Rle> <IRanges>         <Rle>   <IRanges> | <integer> <character>
+##    [1]      chr1 5001-6000 ---      chr1   8001-9000 |         3         cis
+##    [2]      chr1 8001-9000 ---      chr1   7001-8000 |         4       trans
+##    [3]      chr1 7001-8000 ---      chr2 13000-14000 |         5         cis
+##    -------
+##    regions: 7 ranges and 2 metadata columns
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+
+

Case 2: Overlap between anchors of an interaction with anchors of another interaction

+
+

This slightly different scenario involves overlapping two sets of interactions, to see whether any interaction in Set-1 has its two anchors overlapping anchors from an interaction in Set-2.

+
+
gi2 <- GInteractions(
+    GRanges("chr1:1081-1090"), 
+    GRanges("chr1:3401-3501")
+)
+gi %over% gi2
+##  [1] FALSE  TRUE FALSE FALSE FALSE
+
+

Note that both anchors of an interaction from a query have to overlap to a pair of anchors of a single interaction from a subject with this method!

+
+
gi3 <- GInteractions(
+    GRanges("chr1:1-1000"), 
+    GRanges("chr1:3401-3501")
+)
+gi %over% gi3
+##  [1] FALSE FALSE FALSE FALSE FALSE
+
+
+

Case 3 : Spanning of the interaction β€œaccross” a genomic range

+
+

This requires a bit of wrangling, to mimic an overlap between two GRanges objects:

+
+
gi <- swapAnchors(gi) # ----- Make sure anchors are correctly sorted
+gi <- sort(gi) # ----- Make sure interactions are correctly sorted
+gi <- gi[!is.na(pairdist(gi))] # ----- Remove inter-chromosomal interactions
+spanning_gi <- GRanges(
+    seqnames = seqnames(anchors(gi)[[1]]), 
+    ranges = IRanges(
+        start(anchors(gi)[[1]]), 
+        end(anchors(gi)[[2]])
+    )
+)
+spanning_gi 
+##  GRanges object with 4 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]     chr1     1-100      *
+##    [2]     chr1 1001-4000      *
+##    [3]     chr1 5001-9000      *
+##    [4]     chr1 7001-9000      *
+##    -------
+##    seqinfo: 2 sequences from an unspecified genome; no seqlengths
+
+spanning_gi %over% gr
+##  [1] FALSE FALSE  TRUE  TRUE
+
+
+
+
+ +
+
+Going further +
+
+
+

A detailed manual of overlap methods available for GInteractions object can be read by typing ?`Interaction-overlaps` in R.

+
+
+

+2.3 ContactFile class

+

Hi-C contacts can be stored in four different formats (see previous chapter):

+
    +
  • As a .(m)cool matrix (multi-scores, multi-resolution, indexed)
  • +
  • As a .hic matrix (multi-scores, multi-resolution, indexed)
  • +
  • As a HiC-pro derived matrix (single-score, single-resolution, non-indexed)
  • +
  • Unbinned, Hi-C contacts can be stored in .pairs files
  • +
+

+2.3.1 Accessing example Hi-C files

+

Example contact files can be downloaded using HiContactsData function.

+
+
library(HiContactsData)
+coolf <- HiContactsData('yeast_wt', 'mcool')
+
+

This fetches files from the cloud, download them locally and returns the path of the local file.

+
+
coolf
+##                                          EH7702 
+##  "/root/.cache/R/ExperimentHub/1701a09a86_7752"
+
+

Similarly, example files are available for other file formats:

+
+
hicf <- HiContactsData('yeast_wt', 'hic')
+hicpromatrixf <- HiContactsData('yeast_wt', 'hicpro_matrix')
+hicproregionsf <- HiContactsData('yeast_wt', 'hicpro_bed')
+pairsf <- HiContactsData('yeast_wt', 'pairs.gz')
+
+

We can even check the content of some of these files to make sure they are actually what they are:

+
+
# ---- HiC-Pro generates a tab-separated `regions.bed` file
+readLines(hicproregionsf, 25)
+##   [1] "I\t0\t1000"      "I\t1000\t2000"   "I\t2000\t3000"   "I\t3000\t4000"  
+##   [5] "I\t4000\t5000"   "I\t5000\t6000"   "I\t6000\t7000"   "I\t7000\t8000"  
+##   [9] "I\t8000\t9000"   "I\t9000\t10000"  "I\t10000\t11000" "I\t11000\t12000"
+##  [13] "I\t12000\t13000" "I\t13000\t14000" "I\t14000\t15000" "I\t15000\t16000"
+##  [17] "I\t16000\t17000" "I\t17000\t18000" "I\t18000\t19000" "I\t19000\t20000"
+##  [21] "I\t20000\t21000" "I\t21000\t22000" "I\t22000\t23000" "I\t23000\t24000"
+##  [25] "I\t24000\t25000"
+
+# ---- Pairs are also tab-separated 
+readLines(pairsf, 25)
+##   [1] "## pairs format v1.0"                                                             
+##   [2] "#sorted: chr1-pos1-chr2-pos2"                                                     
+##   [3] "#columns: readID chr1 pos1 chr2 pos2 strand1 strand2 frag1 frag2"                 
+##   [4] "#chromsize: I 230218"                                                             
+##   [5] "#chromsize: II 813184"                                                            
+##   [6] "#chromsize: III 316620"                                                           
+##   [7] "#chromsize: IV 1531933"                                                           
+##   [8] "#chromsize: V 576874"                                                             
+##   [9] "#chromsize: VI 270161"                                                            
+##  [10] "#chromsize: VII 1090940"                                                          
+##  [11] "#chromsize: VIII 562643"                                                          
+##  [12] "#chromsize: IX 439888"                                                            
+##  [13] "#chromsize: X 745751"                                                             
+##  [14] "#chromsize: XI 666816"                                                            
+##  [15] "#chromsize: XII 1078177"                                                          
+##  [16] "#chromsize: XIII 924431"                                                          
+##  [17] "#chromsize: XIV 784333"                                                           
+##  [18] "#chromsize: XV 1091291"                                                           
+##  [19] "#chromsize: XVI 948066"                                                           
+##  [20] "#chromsize: Mito 85779"                                                           
+##  [21] "NS500150:527:HHGYNBGXF:3:21611:19085:3986\tII\t105\tII\t48548\t+\t-\t1358\t1681"  
+##  [22] "NS500150:527:HHGYNBGXF:4:13604:19734:2406\tII\t113\tII\t45003\t-\t+\t1358\t1658"  
+##  [23] "NS500150:527:HHGYNBGXF:2:11108:25178:11036\tII\t119\tII\t687251\t-\t+\t1358\t5550"
+##  [24] "NS500150:527:HHGYNBGXF:1:22301:8468:1586\tII\t160\tII\t26124\t+\t-\t1358\t1510"   
+##  [25] "NS500150:527:HHGYNBGXF:4:23606:24037:2076\tII\t169\tII\t39052\t+\t+\t1358\t1613"
+
+

+2.3.2 ContactFile fundamentals

+

A ContactFile object establishes a connection with a disk-stored Hi-C file (e.g. a .cool file, or a .pairs file, …). ContactFile classes are defined in the HiCExperiment package.

+

ContactFiles come in four different flavors:

+
    +
  • +CoolFile: connection to a .(m)cool file
  • +
  • +HicFile: connection to a .hic file
  • +
  • +HicproFile: connection to output files generated by HiC-Pro
  • +
  • +PairsFile: connection to a .pairs file
  • +
+

To create each flavor of ContactFile, one can use the corresponding function:

+
+
library(HiCExperiment)
+
+# ----- This creates a connection to a `.(m)cool` file (path stored in `coolf`)
+CoolFile(coolf)
+##  CoolFile object
+##  .mcool file: /root/.cache/R/ExperimentHub/1701a09a86_7752 
+##  resolution: 1000 
+##  pairs file: 
+##  metadata(0):
+
+# ----- This creates a connection to a `.hic` file (path stored in `hicf`)
+HicFile(hicf)
+##  HicFile object
+##  .hic file: /root/.cache/R/ExperimentHub/1702b65c0b7_7836 
+##  resolution: 1000 
+##  pairs file: 
+##  metadata(0):
+
+# ----- This creates a connection to output files from HiC-Pro
+HicproFile(hicpromatrixf, hicproregionsf)
+##  HicproFile object
+##  HiC-Pro files:
+##    $ matrix:   /root/.cache/R/ExperimentHub/1707968a6f0_7837 
+##    $ regions:  /root/.cache/R/ExperimentHub/17073053091_7838 
+##  resolution: 1000 
+##  pairs file: 
+##  metadata(0):
+
+# ----- This creates a connection to a pairs file
+PairsFile(pairsf)
+##  PairsFile object
+##  resource: /root/.cache/R/ExperimentHub/1702dcdfa3b_7753
+
+

+2.3.3 ContactFile slots

+

Several β€œslots” (i.e. pieces of information) are attached to a ContactFile object:

+
    +
  • The path to the disk-stored contact matrix;
  • +
  • The active resolution (by default, the finest resolution available in a multi-resolution contact matrix);
  • +
  • Optionally, the path to a matching pairs file (see below);
  • +
  • Some metadata.
  • +
+

Slots of a CoolFile object can be accessed as follow:

+
+
cf <- CoolFile(coolf)
+cf
+##  CoolFile object
+##  .mcool file: /root/.cache/R/ExperimentHub/1701a09a86_7752 
+##  resolution: 1000 
+##  pairs file: 
+##  metadata(0):
+
+resolution(cf)
+##  [1] 1000
+
+pairsFile(cf)
+##  NULL
+
+metadata(cf)
+##  list()
+
+
+
+
+ +
+
+Important! +
+
+
+

ContactFile objects are only connections to a disk-stored HiC file. Although metadata is available, they do not contain actual data!

+
+
+

+2.3.4 ContactFile methods

+

Two useful methods are available for ContactFiles:

+
    +
  • +availableResolutions checks which resolutions are available in a ContactFile.
  • +
+
+
availableResolutions(cf)
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  
+
+
    +
  • +availableChromosomes checks which chromosomes are available in a ContactFile, along with their length.
  • +
+
+
availableChromosomes(cf)
+##  Seqinfo object with 16 sequences from an unspecified genome:
+##    seqnames seqlengths isCircular genome
+##    I            230218       <NA>   <NA>
+##    II           813184       <NA>   <NA>
+##    III          316620       <NA>   <NA>
+##    IV          1531933       <NA>   <NA>
+##    V            576874       <NA>   <NA>
+##    ...             ...        ...    ...
+##    XII         1078177       <NA>   <NA>
+##    XIII         924431       <NA>   <NA>
+##    XIV          784333       <NA>   <NA>
+##    XV          1091291       <NA>   <NA>
+##    XVI          948066       <NA>   <NA>
+
+

+2.4 HiCExperiment class

+

Based on the previous sections, we have different Bioconductor classes relevant for Hi-C:

+
    +
  • +GInteractions which can be used to represent genomic interactions in R
  • +
  • +ContactFiles which can be used to establish a connection with disk-stored Hi-C files
  • +
+

HiCExperiment objects are created when parsing a ContactFile in R. The HiCExperiment class reads a ContactFile in memory and store genomic interactions as GInteractions. The HiCExperiment class is, quite obviously, defined in the HiCExperiment package.

+

+2.4.1 Creating a HiCExperiment object

+

+2.4.1.1 Importing a ContactFile +

+

In practice, to create a HiCExperiment object from a ContactFile, one can use the import method.

+
+
+
+ +
+
+Caution +
+
+
+
    +
  • Creating a HiCExperiment object means importing data from a Hi-C matrix (e.g.  from a ContactFile) in memory in R.
    +
  • +
  • Creating a HiCExperiment object from large disk-stored contact matrices can potentially take a long time.
  • +
+
+
+
+
cf <- CoolFile(coolf)
+hic <- import(cf)
+hic
+##  `HiCExperiment` object with 8,757,906 contacts over 12,079 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "whole genome" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 1000 
+##  interactions: 2945692 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+

Printing a HiCExperiment to the console will not reveal the actual data stored in the object (it would most likely crash your R session!). Instead, it gives a summary of the data stored in the object:

+
    +
  • The fileName, i.e. the path to the disk-stored data file
  • +
  • The focus, i.e. the genomic location for which data has been imported (in the example above, "whole genome" implies that all the data has been imported in R)
  • +
  • +resolutions available in the disk-stored data file (this will be identical to availableResolutions(cf))
  • +
  • +active resolution indicates at which resolution the data is currently imported
  • +
  • +interactions refers to the actual GInteractions imported in R and β€œhidden” (for now!) in the HiCExperiment object
  • +
  • +scores refer to different interaction frequency estimates. These can be raw counts, balanced (if the contact matrix has been previously normalized), or whatever score the end-user want to attribute to each interaction (e.g. ratio of counts between two Hi-C maps, …)
  • +
  • +topologicalFeatures is a list of GRanges or GInteractions objects to describe important topological features.
  • +
  • +pairsFile is a pointer to an optional disk-stored .pairs file from which the contact matrix has been created. This is often useful to estimate some Hi-C metrics.
  • +
  • +metadata is a list to further describe the experiment.
  • +
+

These pieces of information are called slots. They can be directly accessed using getter functions, bearing the same name than the slot.

+
+
fileName(hic)
+##  [1] "/root/.cache/R/ExperimentHub/1701a09a86_7752"
+
+focus(hic)
+##  NULL
+
+resolutions(hic)
+##  [1]  1000  2000  4000  8000 16000
+
+resolution(hic)
+##  [1] 1000
+
+interactions(hic)
+##  GInteractions object with 2945692 interactions and 4 metadata columns:
+##              seqnames1       ranges1     seqnames2       ranges2 |   bin_id1
+##                  <Rle>     <IRanges>         <Rle>     <IRanges> | <numeric>
+##          [1]         I        1-1000 ---         I        1-1000 |         0
+##          [2]         I        1-1000 ---         I     1001-2000 |         0
+##          [3]         I        1-1000 ---         I     2001-3000 |         0
+##          [4]         I        1-1000 ---         I     3001-4000 |         0
+##          [5]         I        1-1000 ---         I     4001-5000 |         0
+##          ...       ...           ... ...       ...           ... .       ...
+##    [2945688]       XVI 940001-941000 ---       XVI 942001-943000 |     12070
+##    [2945689]       XVI 940001-941000 ---       XVI 943001-944000 |     12070
+##    [2945690]       XVI 941001-942000 ---       XVI 941001-942000 |     12071
+##    [2945691]       XVI 941001-942000 ---       XVI 942001-943000 |     12071
+##    [2945692]       XVI 941001-942000 ---       XVI 943001-944000 |     12071
+##                bin_id2     count  balanced
+##              <numeric> <numeric> <numeric>
+##          [1]         0        15 0.0663491
+##          [2]         1        21 0.1273505
+##          [3]         2        21 0.0738691
+##          [4]         3        38 0.0827051
+##          [5]         4        17 0.0591984
+##          ...       ...       ...       ...
+##    [2945688]     12072        11 0.0575550
+##    [2945689]     12073         1       NaN
+##    [2945690]     12071        74 0.0504615
+##    [2945691]     12072        39 0.1624599
+##    [2945692]     12073         1       NaN
+##    -------
+##    regions: 12079 ranges and 4 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome
+
+scores(hic)
+##  List of length 2
+##  names(2): count balanced
+
+topologicalFeatures(hic)
+##  List of length 4
+##  names(4): compartments borders loops viewpoints
+
+pairsFile(hic)
+##  NULL
+
+metadata(hic)
+##  list()
+
+

import also works for other types of ContactFile (HicFile, HicproFile, PairsFile), e.g. 

+
    +
  • For HicFile and HicproFile, import seamlessly returns a HiCExperiment as well:
  • +
+
+
hf <- HicFile(hicf)
+hic <- import(hf)
+hic
+##  `HiCExperiment` object with 13,681,280 contacts over 12,165 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1702b65c0b7_7836" 
+##  focus: "whole genome" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 1000 
+##  interactions: 2965693 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • For PairsFile, the returned object is a representation of Hi-C β€œpairs” in R, i.e. GInteractions +
  • +
+
+
pf <- PairsFile(pairsf)
+pairs <- import(pf)
+pairs
+##  GInteractions object with 471364 interactions and 3 metadata columns:
+##             seqnames1   ranges1     seqnames2   ranges2 |     frag1     frag2
+##                 <Rle> <IRanges>         <Rle> <IRanges> | <numeric> <numeric>
+##         [1]        II       105 ---        II     48548 |      1358      1681
+##         [2]        II       113 ---        II     45003 |      1358      1658
+##         [3]        II       119 ---        II    687251 |      1358      5550
+##         [4]        II       160 ---        II     26124 |      1358      1510
+##         [5]        II       169 ---        II     39052 |      1358      1613
+##         ...       ...       ... ...       ...       ... .       ...       ...
+##    [471360]        II    808605 ---        II    809683 |      6316      6320
+##    [471361]        II    808609 ---        II    809917 |      6316      6324
+##    [471362]        II    808617 ---        II    809506 |      6316      6319
+##    [471363]        II    809447 ---        II    809685 |      6319      6321
+##    [471364]        II    809472 ---        II    809675 |      6319      6320
+##              distance
+##             <integer>
+##         [1]     48443
+##         [2]     44890
+##         [3]    687132
+##         [4]     25964
+##         [5]     38883
+##         ...       ...
+##    [471360]      1078
+##    [471361]      1308
+##    [471362]       889
+##    [471363]       238
+##    [471364]       203
+##    -------
+##    regions: 549331 ranges and 0 metadata columns
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+

+2.4.1.2 Customizing the import +

+

To reduce the import to only parse the data that is relevant to the study, two arguments can be passed to import, along with a ContactFile.

+
+
+
+ +
+
+Key import arguments: +
+
+
+
    +
  • +focus: This can be used to only parse data for a specific genomic location.
  • +
  • +resolution: This can be used to choose which resolution to parse the contact matrix at (this is ignored if the ContactFile is not multi-resolution, e.g. .cool or HiC-Pro generated matrices)
  • +
+
+
+
    +
  • Import interactions within a single chromosome:
  • +
+
+
hic <- import(cf, focus = 'II', resolution = 2000)
+
+regions(hic) # ---- `regions()` work on `HiCExperiment` the same way than on `GInteractions`
+##  GRanges object with 407 ranges and 4 metadata columns:
+##                     seqnames        ranges strand |    bin_id    weight   chr
+##                        <Rle>     <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##           II_1_2000       II        1-2000      * |       116       NaN    II
+##        II_2001_4000       II     2001-4000      * |       117       NaN    II
+##        II_4001_6000       II     4001-6000      * |       118       NaN    II
+##        II_6001_8000       II     6001-8000      * |       119       NaN    II
+##       II_8001_10000       II    8001-10000      * |       120 0.0461112    II
+##                 ...      ...           ...    ... .       ...       ...   ...
+##    II_804001_806000       II 804001-806000      * |       518 0.0493107    II
+##    II_806001_808000       II 806001-808000      * |       519 0.0611355    II
+##    II_808001_810000       II 808001-810000      * |       520       NaN    II
+##    II_810001_812000       II 810001-812000      * |       521       NaN    II
+##    II_812001_813184       II 812001-813184      * |       522       NaN    II
+##                        center
+##                     <integer>
+##           II_1_2000      1000
+##        II_2001_4000      3000
+##        II_4001_6000      5000
+##        II_6001_8000      7000
+##       II_8001_10000      9000
+##                 ...       ...
+##    II_804001_806000    805000
+##    II_806001_808000    807000
+##    II_808001_810000    809000
+##    II_810001_812000    811000
+##    II_812001_813184    812592
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+table(seqnames(regions(hic)))
+##  
+##     I   II  III   IV    V   VI  VII VIII   IX    X   XI  XII XIII  XIV   XV 
+##     0  407    0    0    0    0    0    0    0    0    0    0    0    0    0 
+##   XVI 
+##     0
+
+anchors(hic) # ---- `anchors()` work on `HiCExperiment` the same way than on `GInteractions`
+##  $first
+##  GRanges object with 34063 ranges and 4 metadata columns:
+##            seqnames        ranges strand |    bin_id    weight   chr
+##               <Rle>     <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##        [1]       II        1-2000      * |       116       NaN    II
+##        [2]       II        1-2000      * |       116       NaN    II
+##        [3]       II        1-2000      * |       116       NaN    II
+##        [4]       II        1-2000      * |       116       NaN    II
+##        [5]       II        1-2000      * |       116       NaN    II
+##        ...      ...           ...    ... .       ...       ...   ...
+##    [34059]       II 804001-806000      * |       518 0.0493107    II
+##    [34060]       II 806001-808000      * |       519 0.0611355    II
+##    [34061]       II 806001-808000      * |       519 0.0611355    II
+##    [34062]       II 806001-808000      * |       519 0.0611355    II
+##    [34063]       II 808001-810000      * |       520       NaN    II
+##               center
+##            <integer>
+##        [1]      1000
+##        [2]      1000
+##        [3]      1000
+##        [4]      1000
+##        [5]      1000
+##        ...       ...
+##    [34059]    805000
+##    [34060]    807000
+##    [34061]    807000
+##    [34062]    807000
+##    [34063]    809000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+##  
+##  $second
+##  GRanges object with 34063 ranges and 4 metadata columns:
+##            seqnames        ranges strand |    bin_id    weight   chr
+##               <Rle>     <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##        [1]       II        1-2000      * |       116       NaN    II
+##        [2]       II     4001-6000      * |       118       NaN    II
+##        [3]       II     6001-8000      * |       119       NaN    II
+##        [4]       II    8001-10000      * |       120 0.0461112    II
+##        [5]       II   10001-12000      * |       121 0.0334807    II
+##        ...      ...           ...    ... .       ...       ...   ...
+##    [34059]       II 810001-812000      * |       521       NaN    II
+##    [34060]       II 806001-808000      * |       519 0.0611355    II
+##    [34061]       II 808001-810000      * |       520       NaN    II
+##    [34062]       II 810001-812000      * |       521       NaN    II
+##    [34063]       II 808001-810000      * |       520       NaN    II
+##               center
+##            <integer>
+##        [1]      1000
+##        [2]      5000
+##        [3]      7000
+##        [4]      9000
+##        [5]     11000
+##        ...       ...
+##    [34059]    811000
+##    [34060]    807000
+##    [34061]    809000
+##    [34062]    811000
+##    [34063]    809000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+
    +
  • Import interactions within a segment of a chromosome:
  • +
+
+
hic <- import(cf, focus = 'II:40000-60000', resolution = 1000)
+
+regions(hic) 
+##  GRanges object with 21 ranges and 4 metadata columns:
+##                   seqnames      ranges strand |    bin_id    weight   chr
+##                      <Rle>   <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##    II_39001_40000       II 39001-40000      * |       270 0.0220798    II
+##    II_40001_41000       II 40001-41000      * |       271 0.0246775    II
+##    II_41001_42000       II 41001-42000      * |       272 0.0269232    II
+##    II_42001_43000       II 42001-43000      * |       273 0.0341849    II
+##    II_43001_44000       II 43001-44000      * |       274 0.0265386    II
+##               ...      ...         ...    ... .       ...       ...   ...
+##    II_55001_56000       II 55001-56000      * |       286 0.0213532    II
+##    II_56001_57000       II 56001-57000      * |       287 0.0569839    II
+##    II_57001_58000       II 57001-58000      * |       288 0.0338612    II
+##    II_58001_59000       II 58001-59000      * |       289 0.0294531    II
+##    II_59001_60000       II 59001-60000      * |       290 0.0306662    II
+##                      center
+##                   <integer>
+##    II_39001_40000     39500
+##    II_40001_41000     40500
+##    II_41001_42000     41500
+##    II_42001_43000     42500
+##    II_43001_44000     43500
+##               ...       ...
+##    II_55001_56000     55500
+##    II_56001_57000     56500
+##    II_57001_58000     57500
+##    II_58001_59000     58500
+##    II_59001_60000     59500
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+anchors(hic)
+##  $first
+##  GRanges object with 210 ranges and 4 metadata columns:
+##          seqnames      ranges strand |    bin_id    weight   chr    center
+##             <Rle>   <IRanges>  <Rle> | <numeric> <numeric> <Rle> <integer>
+##      [1]       II 40001-41000      * |       271 0.0246775    II     40500
+##      [2]       II 40001-41000      * |       271 0.0246775    II     40500
+##      [3]       II 40001-41000      * |       271 0.0246775    II     40500
+##      [4]       II 40001-41000      * |       271 0.0246775    II     40500
+##      [5]       II 40001-41000      * |       271 0.0246775    II     40500
+##      ...      ...         ...    ... .       ...       ...   ...       ...
+##    [206]       II 57001-58000      * |       288 0.0338612    II     57500
+##    [207]       II 57001-58000      * |       288 0.0338612    II     57500
+##    [208]       II 58001-59000      * |       289 0.0294531    II     58500
+##    [209]       II 58001-59000      * |       289 0.0294531    II     58500
+##    [210]       II 59001-60000      * |       290 0.0306662    II     59500
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+##  
+##  $second
+##  GRanges object with 210 ranges and 4 metadata columns:
+##          seqnames      ranges strand |    bin_id    weight   chr    center
+##             <Rle>   <IRanges>  <Rle> | <numeric> <numeric> <Rle> <integer>
+##      [1]       II 40001-41000      * |       271 0.0246775    II     40500
+##      [2]       II 41001-42000      * |       272 0.0269232    II     41500
+##      [3]       II 42001-43000      * |       273 0.0341849    II     42500
+##      [4]       II 43001-44000      * |       274 0.0265386    II     43500
+##      [5]       II 44001-45000      * |       275 0.0488968    II     44500
+##      ...      ...         ...    ... .       ...       ...   ...       ...
+##    [206]       II 58001-59000      * |       289 0.0294531    II     58500
+##    [207]       II 59001-60000      * |       290 0.0306662    II     59500
+##    [208]       II 58001-59000      * |       289 0.0294531    II     58500
+##    [209]       II 59001-60000      * |       290 0.0306662    II     59500
+##    [210]       II 59001-60000      * |       290 0.0306662    II     59500
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+
    +
  • Import interactions between two chromosomes:
  • +
+
+
hic2 <- import(cf, focus = 'II|XV', resolution = 4000)
+
+regions(hic2)
+##  GRanges object with 477 ranges and 4 metadata columns:
+##                       seqnames          ranges strand |    bin_id    weight
+##                          <Rle>       <IRanges>  <Rle> | <numeric> <numeric>
+##             II_1_4000       II          1-4000      * |        58       NaN
+##          II_4001_8000       II       4001-8000      * |        59       NaN
+##         II_8001_12000       II      8001-12000      * |        60 0.0274474
+##        II_12001_16000       II     12001-16000      * |        61 0.0342116
+##        II_16001_20000       II     16001-20000      * |        62 0.0195128
+##                   ...      ...             ...    ... .       ...       ...
+##    XV_1072001_1076000       XV 1072001-1076000      * |      2783  0.041763
+##    XV_1076001_1080000       XV 1076001-1080000      * |      2784       NaN
+##    XV_1080001_1084000       XV 1080001-1084000      * |      2785       NaN
+##    XV_1084001_1088000       XV 1084001-1088000      * |      2786       NaN
+##    XV_1088001_1091291       XV 1088001-1091291      * |      2787       NaN
+##                         chr    center
+##                       <Rle> <integer>
+##             II_1_4000    II      2000
+##          II_4001_8000    II      6000
+##         II_8001_12000    II     10000
+##        II_12001_16000    II     14000
+##        II_16001_20000    II     18000
+##                   ...   ...       ...
+##    XV_1072001_1076000    XV   1074000
+##    XV_1076001_1080000    XV   1078000
+##    XV_1080001_1084000    XV   1082000
+##    XV_1084001_1088000    XV   1086000
+##    XV_1088001_1091291    XV   1089646
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+anchors(hic2)
+##  $first
+##  GRanges object with 18032 ranges and 4 metadata columns:
+##            seqnames        ranges strand |    bin_id    weight   chr
+##               <Rle>     <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##        [1]       II        1-4000      * |        58       NaN    II
+##        [2]       II        1-4000      * |        58       NaN    II
+##        [3]       II        1-4000      * |        58       NaN    II
+##        [4]       II        1-4000      * |        58       NaN    II
+##        [5]       II        1-4000      * |        58       NaN    II
+##        ...      ...           ...    ... .       ...       ...   ...
+##    [18028]       II 808001-812000      * |       260       NaN    II
+##    [18029]       II 808001-812000      * |       260       NaN    II
+##    [18030]       II 808001-812000      * |       260       NaN    II
+##    [18031]       II 808001-812000      * |       260       NaN    II
+##    [18032]       II 808001-812000      * |       260       NaN    II
+##               center
+##            <integer>
+##        [1]      2000
+##        [2]      2000
+##        [3]      2000
+##        [4]      2000
+##        [5]      2000
+##        ...       ...
+##    [18028]    810000
+##    [18029]    810000
+##    [18030]    810000
+##    [18031]    810000
+##    [18032]    810000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+##  
+##  $second
+##  GRanges object with 18032 ranges and 4 metadata columns:
+##            seqnames          ranges strand |    bin_id    weight   chr
+##               <Rle>       <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##        [1]       XV     48001-52000      * |      2527 0.0185354    XV
+##        [2]       XV   348001-352000      * |      2602 0.0233750    XV
+##        [3]       XV   468001-472000      * |      2632 0.0153615    XV
+##        [4]       XV   472001-476000      * |      2633 0.0189624    XV
+##        [5]       XV   584001-588000      * |      2661 0.0167715    XV
+##        ...      ...             ...    ... .       ...       ...   ...
+##    [18028]       XV   980001-984000      * |      2760 0.0187827    XV
+##    [18029]       XV   984001-988000      * |      2761 0.0250094    XV
+##    [18030]       XV   992001-996000      * |      2763 0.0185599    XV
+##    [18031]       XV 1004001-1008000      * |      2766 0.0196942    XV
+##    [18032]       XV 1064001-1068000      * |      2781 0.0208220    XV
+##               center
+##            <integer>
+##        [1]     50000
+##        [2]    350000
+##        [3]    470000
+##        [4]    474000
+##        [5]    586000
+##        ...       ...
+##    [18028]    982000
+##    [18029]    986000
+##    [18030]    994000
+##    [18031]   1006000
+##    [18032]   1066000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+
    +
  • Import interactions between segments of two chromosomes:
  • +
+
+
hic3 <- import(cf, focus = 'III:10000-40000|XV:10000-40000', resolution = 2000)
+
+regions(hic3)
+##  GRanges object with 32 ranges and 4 metadata columns:
+##                    seqnames      ranges strand |    bin_id    weight   chr
+##                       <Rle>   <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##     III_8001_10000      III  8001-10000      * |       527       NaN   III
+##    III_10001_12000      III 10001-12000      * |       528       NaN   III
+##    III_12001_14000      III 12001-14000      * |       529       NaN   III
+##    III_14001_16000      III 14001-16000      * |       530 0.0356351   III
+##    III_16001_18000      III 16001-18000      * |       531 0.0230693   III
+##                ...      ...         ...    ... .       ...       ...   ...
+##     XV_30001_32000       XV 30001-32000      * |      5039 0.0482465    XV
+##     XV_32001_34000       XV 32001-34000      * |      5040 0.0241580    XV
+##     XV_34001_36000       XV 34001-36000      * |      5041 0.0273166    XV
+##     XV_36001_38000       XV 36001-38000      * |      5042 0.0542235    XV
+##     XV_38001_40000       XV 38001-40000      * |      5043 0.0206849    XV
+##                       center
+##                    <integer>
+##     III_8001_10000      9000
+##    III_10001_12000     11000
+##    III_12001_14000     13000
+##    III_14001_16000     15000
+##    III_16001_18000     17000
+##                ...       ...
+##     XV_30001_32000     31000
+##     XV_32001_34000     33000
+##     XV_34001_36000     35000
+##     XV_36001_38000     37000
+##     XV_38001_40000     39000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+anchors(hic3)
+##  $first
+##  GRanges object with 11 ranges and 4 metadata columns:
+##         seqnames      ranges strand |    bin_id    weight   chr    center
+##            <Rle>   <IRanges>  <Rle> | <numeric> <numeric> <Rle> <integer>
+##     [1]      III 14001-16000      * |       530 0.0356351   III     15000
+##     [2]      III 16001-18000      * |       531 0.0230693   III     17000
+##     [3]      III 16001-18000      * |       531 0.0230693   III     17000
+##     [4]      III 20001-22000      * |       533 0.0343250   III     21000
+##     [5]      III 22001-24000      * |       534 0.0258604   III     23000
+##     [6]      III 24001-26000      * |       535 0.0290757   III     25000
+##     [7]      III 28001-30000      * |       537 0.0290713   III     29000
+##     [8]      III 30001-32000      * |       538 0.0266373   III     31000
+##     [9]      III 32001-34000      * |       539 0.0201137   III     33000
+##    [10]      III 32001-34000      * |       539 0.0201137   III     33000
+##    [11]      III 36001-38000      * |       541 0.0220603   III     37000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+##  
+##  $second
+##  GRanges object with 11 ranges and 4 metadata columns:
+##         seqnames      ranges strand |    bin_id    weight   chr    center
+##            <Rle>   <IRanges>  <Rle> | <numeric> <numeric> <Rle> <integer>
+##     [1]       XV 16001-18000      * |      5032 0.0187250    XV     17000
+##     [2]       XV 16001-18000      * |      5032 0.0187250    XV     17000
+##     [3]       XV 20001-22000      * |      5034 0.0247973    XV     21000
+##     [4]       XV 14001-16000      * |      5031 0.0379727    XV     15000
+##     [5]       XV 10001-12000      * |      5029 0.0296913    XV     11000
+##     [6]       XV 32001-34000      * |      5040 0.0241580    XV     33000
+##     [7]       XV 16001-18000      * |      5032 0.0187250    XV     17000
+##     [8]       XV 38001-40000      * |      5043 0.0206849    XV     39000
+##     [9]       XV 22001-24000      * |      5035 0.0613856    XV     23000
+##    [10]       XV 30001-32000      * |      5039 0.0482465    XV     31000
+##    [11]       XV 10001-12000      * |      5029 0.0296913    XV     11000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+

+2.4.2 Interacting with HiCExperiment data

+
    +
  • An HiCExperiment object allows parsing of a disk-stored contact matrix.
  • +
  • An HiCExperiment object operates by wrapping together (1) a ContactFile (i.e. a connection to a disk-stored data file) and (2) a GInteractions generated by parsing the data file.
  • +
+

We will use the yeast_hic HiCExperiment object to demonstrate how to parse information from a HiCExperiment object.

+
+
yeast_hic <- contacts_yeast()
+
+
+
yeast_hic
+##  `HiCExperiment` object with 8,757,906 contacts over 763 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "whole genome" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 16000 
+##  interactions: 267709 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: /root/.cache/R/ExperimentHub/1702dcdfa3b_7753 
+##  metadata(3): ID org date
+
+

+2.4.2.1 Interactions

+

The imported genomic interactions can be directly exposed using the interactions function and are returned as a GInteractions object.

+
+
interactions(yeast_hic)
+##  GInteractions object with 267709 interactions and 4 metadata columns:
+##             seqnames1       ranges1     seqnames2       ranges2 |   bin_id1
+##                 <Rle>     <IRanges>         <Rle>     <IRanges> | <numeric>
+##         [1]         I       1-16000 ---         I       1-16000 |         0
+##         [2]         I       1-16000 ---         I   16001-32000 |         0
+##         [3]         I       1-16000 ---         I   32001-48000 |         0
+##         [4]         I       1-16000 ---         I   48001-64000 |         0
+##         [5]         I       1-16000 ---         I   64001-80000 |         0
+##         ...       ...           ... ...       ...           ... .       ...
+##    [267705]       XVI 896001-912000 ---       XVI 912001-928000 |       759
+##    [267706]       XVI 896001-912000 ---       XVI 928001-944000 |       759
+##    [267707]       XVI 912001-928000 ---       XVI 912001-928000 |       760
+##    [267708]       XVI 912001-928000 ---       XVI 928001-944000 |       760
+##    [267709]       XVI 928001-944000 ---       XVI 928001-944000 |       761
+##               bin_id2     count  balanced
+##             <numeric> <numeric> <numeric>
+##         [1]         0      2836 1.0943959
+##         [2]         1      2212 0.9592069
+##         [3]         2      1183 0.4385242
+##         [4]         3       831 0.2231192
+##         [5]         4       310 0.0821255
+##         ...       ...       ...       ...
+##    [267705]       760      3565  1.236371
+##    [267706]       761      1359  0.385016
+##    [267707]       760      3534  2.103988
+##    [267708]       761      3055  1.485794
+##    [267709]       761      4308  1.711565
+##    -------
+##    regions: 763 ranges and 4 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome
+
+

Because genomic interactions are actually stored as GInteractions, regions and anchors work on HiCExperiment objects just as they work with GInteractions!

+
+
regions(yeast_hic)
+##  GRanges object with 763 ranges and 4 metadata columns:
+##                      seqnames        ranges strand |    bin_id     weight
+##                         <Rle>     <IRanges>  <Rle> | <numeric>  <numeric>
+##            I_1_16000        I       1-16000      * |         0  0.0196442
+##        I_16001_32000        I   16001-32000      * |         1  0.0220746
+##        I_32001_48000        I   32001-48000      * |         2  0.0188701
+##        I_48001_64000        I   48001-64000      * |         3  0.0136679
+##        I_64001_80000        I   64001-80000      * |         4  0.0134860
+##                  ...      ...           ...    ... .       ...        ...
+##    XVI_880001_896000      XVI 880001-896000      * |       758 0.00910873
+##    XVI_896001_912000      XVI 896001-912000      * |       759 0.01421350
+##    XVI_912001_928000      XVI 912001-928000      * |       760 0.02439992
+##    XVI_928001_944000      XVI 928001-944000      * |       761 0.01993237
+##    XVI_944001_948066      XVI 944001-948066      * |       762        NaN
+##                        chr    center
+##                      <Rle> <integer>
+##            I_1_16000     I      8000
+##        I_16001_32000     I     24000
+##        I_32001_48000     I     40000
+##        I_48001_64000     I     56000
+##        I_64001_80000     I     72000
+##                  ...   ...       ...
+##    XVI_880001_896000   XVI    888000
+##    XVI_896001_912000   XVI    904000
+##    XVI_912001_928000   XVI    920000
+##    XVI_928001_944000   XVI    936000
+##    XVI_944001_948066   XVI    946033
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+anchors(yeast_hic)
+##  $first
+##  GRanges object with 267709 ranges and 4 metadata columns:
+##             seqnames        ranges strand |    bin_id    weight   chr
+##                <Rle>     <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##         [1]        I       1-16000      * |         0 0.0196442     I
+##         [2]        I       1-16000      * |         0 0.0196442     I
+##         [3]        I       1-16000      * |         0 0.0196442     I
+##         [4]        I       1-16000      * |         0 0.0196442     I
+##         [5]        I       1-16000      * |         0 0.0196442     I
+##         ...      ...           ...    ... .       ...       ...   ...
+##    [267705]      XVI 896001-912000      * |       759 0.0142135   XVI
+##    [267706]      XVI 896001-912000      * |       759 0.0142135   XVI
+##    [267707]      XVI 912001-928000      * |       760 0.0243999   XVI
+##    [267708]      XVI 912001-928000      * |       760 0.0243999   XVI
+##    [267709]      XVI 928001-944000      * |       761 0.0199324   XVI
+##                center
+##             <integer>
+##         [1]      8000
+##         [2]      8000
+##         [3]      8000
+##         [4]      8000
+##         [5]      8000
+##         ...       ...
+##    [267705]    904000
+##    [267706]    904000
+##    [267707]    920000
+##    [267708]    920000
+##    [267709]    936000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+##  
+##  $second
+##  GRanges object with 267709 ranges and 4 metadata columns:
+##             seqnames        ranges strand |    bin_id    weight   chr
+##                <Rle>     <IRanges>  <Rle> | <numeric> <numeric> <Rle>
+##         [1]        I       1-16000      * |         0 0.0196442     I
+##         [2]        I   16001-32000      * |         1 0.0220746     I
+##         [3]        I   32001-48000      * |         2 0.0188701     I
+##         [4]        I   48001-64000      * |         3 0.0136679     I
+##         [5]        I   64001-80000      * |         4 0.0134860     I
+##         ...      ...           ...    ... .       ...       ...   ...
+##    [267705]      XVI 912001-928000      * |       760 0.0243999   XVI
+##    [267706]      XVI 928001-944000      * |       761 0.0199324   XVI
+##    [267707]      XVI 912001-928000      * |       760 0.0243999   XVI
+##    [267708]      XVI 928001-944000      * |       761 0.0199324   XVI
+##    [267709]      XVI 928001-944000      * |       761 0.0199324   XVI
+##                center
+##             <integer>
+##         [1]      8000
+##         [2]     24000
+##         [3]     40000
+##         [4]     56000
+##         [5]     72000
+##         ...       ...
+##    [267705]    920000
+##    [267706]    936000
+##    [267707]    920000
+##    [267708]    936000
+##    [267709]    936000
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+

+2.4.2.2 Bins and seqinfo

+

Additional useful information can be recovered from a HiCExperiment object. This includes:

+
    +
  • The seqinfo of the HiCExperiment:
  • +
+
+
seqinfo(yeast_hic)
+##  Seqinfo object with 16 sequences from an unspecified genome:
+##    seqnames seqlengths isCircular genome
+##    I            230218       <NA>   <NA>
+##    II           813184       <NA>   <NA>
+##    III          316620       <NA>   <NA>
+##    IV          1531933       <NA>   <NA>
+##    V            576874       <NA>   <NA>
+##    ...             ...        ...    ...
+##    XII         1078177       <NA>   <NA>
+##    XIII         924431       <NA>   <NA>
+##    XIV          784333       <NA>   <NA>
+##    XV          1091291       <NA>   <NA>
+##    XVI          948066       <NA>   <NA>
+
+

This lists the different chromosomes available to parse along with their length.

+
    +
  • The bins of the HiCExperiment:
  • +
+
+
bins(yeast_hic)
+##  GRanges object with 763 ranges and 2 metadata columns:
+##                      seqnames        ranges strand |    bin_id     weight
+##                         <Rle>     <IRanges>  <Rle> | <numeric>  <numeric>
+##            I_1_16000        I       1-16000      * |         0  0.0196442
+##        I_16001_32000        I   16001-32000      * |         1  0.0220746
+##        I_32001_48000        I   32001-48000      * |         2  0.0188701
+##        I_48001_64000        I   48001-64000      * |         3  0.0136679
+##        I_64001_80000        I   64001-80000      * |         4  0.0134860
+##                  ...      ...           ...    ... .       ...        ...
+##    XVI_880001_896000      XVI 880001-896000      * |       758 0.00910873
+##    XVI_896001_912000      XVI 896001-912000      * |       759 0.01421350
+##    XVI_912001_928000      XVI 912001-928000      * |       760 0.02439992
+##    XVI_928001_944000      XVI 928001-944000      * |       761 0.01993237
+##    XVI_944001_948066      XVI 944001-948066      * |       762        NaN
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome
+
+
+
+
+ +
+
+Difference between bins and regions +
+
+
+

bins are not equivalent to regions of an HiCExperiment.

+
    +
  • +bins refer to all the possible regions of a HiCExperiment. For instance, for a HiCExperiment with a total genome size of 1,000,000 and a resolution of 2000, bins will always return a GRanges object with 500 ranges.
  • +
  • +regions, on the opposite, refer to the union of anchors of all the interactions imported in a HiCExperiment object.
  • +
+

Thus, all the regions will necessarily be a subset of the HiCExperiment bins, or equal to bins if no focus has been specified when importing a ContactFile.

+
+
+

+2.4.2.3 Scores

+

Of course, what the end-user would be looking for is the frequency for each genomic interaction. Such frequency scores are available using the scores function. scores returns a list with a number of different types of scores.

+
+
head(scores(yeast_hic))
+##  List of length 2
+##  names(2): count balanced
+
+head(scores(yeast_hic, "count"))
+##  [1] 2836 2212 1183  831  310  159
+
+head(scores(yeast_hic, "balanced"))
+##  [1] 1.09439586 0.95920688 0.43852417 0.22311917 0.08212549 0.03345221
+
+

Calling interactions(hic) returns a GInteractions with scores already stored in extra columns. This short-hand allows one to dynamically check scores directly from the interactions output.

+
+
interactions(yeast_hic)
+##  GInteractions object with 267709 interactions and 4 metadata columns:
+##             seqnames1       ranges1     seqnames2       ranges2 |   bin_id1
+##                 <Rle>     <IRanges>         <Rle>     <IRanges> | <numeric>
+##         [1]         I       1-16000 ---         I       1-16000 |         0
+##         [2]         I       1-16000 ---         I   16001-32000 |         0
+##         [3]         I       1-16000 ---         I   32001-48000 |         0
+##         [4]         I       1-16000 ---         I   48001-64000 |         0
+##         [5]         I       1-16000 ---         I   64001-80000 |         0
+##         ...       ...           ... ...       ...           ... .       ...
+##    [267705]       XVI 896001-912000 ---       XVI 912001-928000 |       759
+##    [267706]       XVI 896001-912000 ---       XVI 928001-944000 |       759
+##    [267707]       XVI 912001-928000 ---       XVI 912001-928000 |       760
+##    [267708]       XVI 912001-928000 ---       XVI 928001-944000 |       760
+##    [267709]       XVI 928001-944000 ---       XVI 928001-944000 |       761
+##               bin_id2     count  balanced
+##             <numeric> <numeric> <numeric>
+##         [1]         0      2836 1.0943959
+##         [2]         1      2212 0.9592069
+##         [3]         2      1183 0.4385242
+##         [4]         3       831 0.2231192
+##         [5]         4       310 0.0821255
+##         ...       ...       ...       ...
+##    [267705]       760      3565  1.236371
+##    [267706]       761      1359  0.385016
+##    [267707]       760      3534  2.103988
+##    [267708]       761      3055  1.485794
+##    [267709]       761      4308  1.711565
+##    -------
+##    regions: 763 ranges and 4 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome
+
+head(interactions(yeast_hic)$count)
+##  [1] 2836 2212 1183  831  310  159
+
+

+2.4.2.4 topologicalFeatures

+

In Hi-C studies, β€œtopological features” refer to genomic structures identified (usually from a Hi-C map, but not necessarily). For instance, one may want to study known structural loops anchored at CTCF sites, or interactions around or over centromeres, or simply specific genomic β€œviewpoints”.

+

HiCExperiment objects can store topologicalFeatures to facilitate this analysis. By default, four empty topologicalFeatures are stored in a list:

+
    +
  • compartments
  • +
  • borders
  • +
  • loops
  • +
  • viewpoints
  • +
+

Additional topologicalFeatures can be added to this list (read next chapter for more detail).

+
+
topologicalFeatures(yeast_hic)
+##  List of length 5
+##  names(5): compartments borders loops viewpoints centromeres
+
+topologicalFeatures(yeast_hic, 'centromeres')
+##  GRanges object with 16 ranges and 0 metadata columns:
+##         seqnames        ranges strand
+##            <Rle>     <IRanges>  <Rle>
+##     [1]        I 151583-151641      +
+##     [2]       II 238361-238419      +
+##     [3]      III 114322-114380      +
+##     [4]       IV 449879-449937      +
+##     [5]        V 152522-152580      +
+##     ...      ...           ...    ...
+##    [12]      XII 151366-151424      +
+##    [13]     XIII 268222-268280      +
+##    [14]      XIV 628588-628646      +
+##    [15]       XV 326897-326955      +
+##    [16]      XVI 556255-556313      +
+##    -------
+##    seqinfo: 17 sequences (1 circular) from R64-1-1 genome
+
+

+2.4.2.5 pairsFile

+

As a contact matrix is typically obtained from binning a .pairs file, it is often the case that the matching .pairs file is available to then end-user. A PairsFile can thus be created and associated to the corresponding HiCExperiment object. This allows more accurate estimation of contact distribution, e.g. when calculating distance-dependent genomic interaction frequency.

+
+
pairsFile(yeast_hic) <- pairsf
+
+pairsFile(yeast_hic)
+##                                           EH7703 
+##  "/root/.cache/R/ExperimentHub/1702dcdfa3b_7753"
+
+readLines(pairsFile(yeast_hic), 25)
+##   [1] "## pairs format v1.0"                                                             
+##   [2] "#sorted: chr1-pos1-chr2-pos2"                                                     
+##   [3] "#columns: readID chr1 pos1 chr2 pos2 strand1 strand2 frag1 frag2"                 
+##   [4] "#chromsize: I 230218"                                                             
+##   [5] "#chromsize: II 813184"                                                            
+##   [6] "#chromsize: III 316620"                                                           
+##   [7] "#chromsize: IV 1531933"                                                           
+##   [8] "#chromsize: V 576874"                                                             
+##   [9] "#chromsize: VI 270161"                                                            
+##  [10] "#chromsize: VII 1090940"                                                          
+##  [11] "#chromsize: VIII 562643"                                                          
+##  [12] "#chromsize: IX 439888"                                                            
+##  [13] "#chromsize: X 745751"                                                             
+##  [14] "#chromsize: XI 666816"                                                            
+##  [15] "#chromsize: XII 1078177"                                                          
+##  [16] "#chromsize: XIII 924431"                                                          
+##  [17] "#chromsize: XIV 784333"                                                           
+##  [18] "#chromsize: XV 1091291"                                                           
+##  [19] "#chromsize: XVI 948066"                                                           
+##  [20] "#chromsize: Mito 85779"                                                           
+##  [21] "NS500150:527:HHGYNBGXF:3:21611:19085:3986\tII\t105\tII\t48548\t+\t-\t1358\t1681"  
+##  [22] "NS500150:527:HHGYNBGXF:4:13604:19734:2406\tII\t113\tII\t45003\t-\t+\t1358\t1658"  
+##  [23] "NS500150:527:HHGYNBGXF:2:11108:25178:11036\tII\t119\tII\t687251\t-\t+\t1358\t5550"
+##  [24] "NS500150:527:HHGYNBGXF:1:22301:8468:1586\tII\t160\tII\t26124\t+\t-\t1358\t1510"   
+##  [25] "NS500150:527:HHGYNBGXF:4:23606:24037:2076\tII\t169\tII\t39052\t+\t+\t1358\t1613"
+
+

+2.4.2.6 Importing a PairsFile +

+

The .pairs file linked to a HiCExperiment object can itself be imported in a GInteractions object:

+
+
import(pairsFile(yeast_hic), format = 'pairs')
+##  GInteractions object with 471364 interactions and 3 metadata columns:
+##             seqnames1   ranges1     seqnames2   ranges2 |     frag1     frag2
+##                 <Rle> <IRanges>         <Rle> <IRanges> | <numeric> <numeric>
+##         [1]        II       105 ---        II     48548 |      1358      1681
+##         [2]        II       113 ---        II     45003 |      1358      1658
+##         [3]        II       119 ---        II    687251 |      1358      5550
+##         [4]        II       160 ---        II     26124 |      1358      1510
+##         [5]        II       169 ---        II     39052 |      1358      1613
+##         ...       ...       ... ...       ...       ... .       ...       ...
+##    [471360]        II    808605 ---        II    809683 |      6316      6320
+##    [471361]        II    808609 ---        II    809917 |      6316      6324
+##    [471362]        II    808617 ---        II    809506 |      6316      6319
+##    [471363]        II    809447 ---        II    809685 |      6319      6321
+##    [471364]        II    809472 ---        II    809675 |      6319      6320
+##              distance
+##             <integer>
+##         [1]     48443
+##         [2]     44890
+##         [3]    687132
+##         [4]     25964
+##         [5]     38883
+##         ...       ...
+##    [471360]      1078
+##    [471361]      1308
+##    [471362]       889
+##    [471363]       238
+##    [471364]       203
+##    -------
+##    regions: 549331 ranges and 0 metadata columns
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+

Note that these GInteractions are not binned, contrary to interactions extracted from a HiCExperiment. Anchors of the interactions listed in the GInteractions imported from a disk-stored .pairs file are all of width 1.

+

+2.5 Visual summary of the HiCExperiment data structure

+

The HiCExperiment data structure provided by the HiCExperiment package inherits methods from core GInteractions and BiocFile classes to provide a flexible representation of Hi-C data in R. It allows random access-based queries to seamlessly import parts or all the data contained in disk-stored Hi-C contact matrices in a variety of formats.

+

+

References

+ + +
+
+Huber, W., Carey, V. J., Gentleman, R., Anders, S., Carlson, M., Carvalho, B. S., Bravo, H. C., Davis, S., Gatto, L., Girke, T., Gottardo, R., Hahne, F., Hansen, K. D., Irizarry, R. A., Lawrence, M., Love, M. I., MacDonald, J., Obenchain, V., OleΕ›, A. K., … Morgan, M. (2015). Orchestrating high-throughput genomic analysis with bioconductor. Nature Methods, 12(2), 115–121. https://doi.org/10.1038/nmeth.3252 +
+
+Lun, A. T. L., Perry, M., & Ing-Simmons, E. (2016). Infrastructure for genomic interactions: Bioconductor classes for hi-c, ChIA-PET and related experiments. F1000Research, 5, 950. https://doi.org/10.12688/f1000research.8759.2 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/data-representation_files/figure-html/unnamed-chunk-17-1.png b/docs/devel/pages/data-representation_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 0000000..ee9b31e Binary files /dev/null and b/docs/devel/pages/data-representation_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/docs/devel/pages/disseminating.html b/docs/devel/pages/disseminating.html new file mode 100644 index 0000000..4d5716c --- /dev/null +++ b/docs/devel/pages/disseminating.html @@ -0,0 +1,879 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 8  Data gateways: accessing public Hi-C data portals + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+8  Data gateways: accessing public Hi-C data portals +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter focuses on introducing two important portals hosting public Hi-C datasets: the 4DN Consortium and the DNA Zoo project. Two R packages provide a programmatic access to these portals:

+
    +
  • fourDNData
  • +
  • DNAZooData
  • +
+
+
+

The Hi-C experimental approach has gained significant traction across multiple fields related to genome biology, and several consortia developed large-scale programs based on this technique. The fourDNData and DNAZooData R packages were designed to accelerate the investigation of chromatin structure using these public resources.

+

+8.1 4DN data portal

+

The 4D Nucleome Data Coordination and Integration Center (DCIC) has developed and actively maintains a data portal providing public access to a wealth of resources to investigate 3D chromatin architecture. Notably, 3D chromatin conformation libraries relying on different technologies (β€œin situ” or β€œdilution” Hi-C, Capture Hi-C, Micro-C, DNase Hi-C, …), generated by 50+ collaborating labs, were homogenously processed, yielding more than 350 sets of processed files.

+

fourDNData (read 4DN-Data) is a package giving programmatic access to these uniformly processed Hi-C contact files.

+

The fourDNData() function provides a gateway to 4DN-hosted Hi-C files, including contact matrices (in .hic or .mcool) and other Hi-C derived files such as annotated compartments, domains, insulation scores, or .pairs files.

+
+
library(fourDNData)
+head(fourDNData())
+##  experimentSetAccession     fileType     size organism experimentType details                              dataset                                                       condition               biosource biosourceType             publication                                                                                                                                 URL
+##            4DNES18BMU79        pairs 10151.53    mouse   in situ Hi-C   DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell  primary cell Monahan K et al. (2019) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/49504f97-904e-48c1-8c20-1033680b66da/4DNFIC5AHBPV.pairs.gz
+##            4DNES18BMU79          hic  5285.82    mouse   in situ Hi-C   DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell  primary cell Monahan K et al. (2019)      https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/6cd4378a-8f51-4e65-99eb-15f5c80abf8d/4DNFIT4I5C6Z.hic
+##            4DNES18BMU79        mcool  6110.75    mouse   in situ Hi-C   DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell  primary cell Monahan K et al. (2019)    https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/01fb704f-2fd7-48c6-91af-c5f4584529ed/4DNFIVPAXJO8.mcool
+##            4DNES18BMU79   boundaries     0.12    mouse   in situ Hi-C   DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell  primary cell Monahan K et al. (2019)   https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/5c07cdee-53e2-43e0-8853-cfe5f057b3f1/4DNFIR3XCIMA.bed.gz
+##            4DNES18BMU79   insulation     7.18    mouse   in situ Hi-C   DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell  primary cell Monahan K et al. (2019)       https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/d1f4beb9-701f-4188-abe2-6271fe658770/4DNFIXKKNMS7.bw
+##            4DNES18BMU79 compartments     0.18    mouse   in situ Hi-C   DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell  primary cell Monahan K et al. (2019)       https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/3d429647-51c8-4e3a-a18b-eec0b1480905/4DNFIN13N8C1.bw
+
+

+8.1.1 Querying individual files

+

The fourDNData() function can be used to directly fetch specific files from the 4DN data portal:

+
+
cf <- fourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'mcool')
+##  |===================================|  100%
+
+

This effectively downloads and caches the queried file locally.

+
+
cf
+## [1] "/home/rsg/.cache/R/fourDNData/698470d302f0_4DNFI4988896.mcool"
+
+availableChromosomes(cf)
+## Seqinfo object with 24 sequences from an unspecified genome:
+##   seqnames seqlengths isCircular genome
+##   chr1      248956422       <NA>   <NA>
+##   chr2      242193529       <NA>   <NA>
+##   chr3      198295559       <NA>   <NA>
+##   chr4      190214555       <NA>   <NA>
+##   chr5      181538259       <NA>   <NA>
+##   ...             ...        ...    ...
+##   chr20      64444167       <NA>   <NA>
+##   chr21      46709983       <NA>   <NA>
+##   chr22      50818468       <NA>   <NA>
+##   chrX      156040895       <NA>   <NA>
+##   chrY       57227415       <NA>   <NA>
+
+availableResolutions(cf)
+## resolutions(13): 1000 2000 ... 5000000 10000000
+
+import(cf, focus = "chr4:10000001-20000000", resolution = 5000)
+## `HiCExperiment` object with 14,682 contacts over 2,000 regions
+## -------
+## fileName: "/home/rsg/.cache/R/fourDNData/29051ff3104c_4DNFINSF15ZM.mcool"
+## focus: "chr4:10,000,001-20,000,000"
+## resolutions(13): 1000 2000 ... 5000000 10000000
+## active resolution: 5000
+## interactions: 12016
+## scores(2): count balanced
+## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0)
+## pairsFile: N/A
+## metadata(0):
+
+

Different Hi-C related genomic files are provided by the 4DN consortium. The type of file to fetch can be specified with the type argument:

+
    +
  • +type = 'pairs' will fetch the pairs file which was generated by the 4DN consortium and binned into a contact matrix. Once fetched from the 4DN data portal, the local file can be imported in R using the import function, which will generate a GInteractions object.
  • +
+
+
fourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'pairs') |> 
+    import()
+## GInteractions object with 13821669 interactions and 3 metadata columns:
+##              seqnames1   ranges1     seqnames2   ranges2 |       frag1     frag2  distance
+##                  <Rle> <IRanges>         <Rle> <IRanges> | <character> <numeric> <integer>
+##          [1]      chr1   3000003 ---      chr1  88307603 |          UU        22  85307600
+##          [2]      chr1   3000022 ---      chr1  28227919 |          UU        50  25227897
+##          [3]      chr1   3000023 ---      chr1  50187758 |          RU        35  47187735
+##          [4]      chr1   3000024 ---      chr1   4090828 |          RU         9   1090804
+##          [5]      chr1   3000024 ---      chr1  35080614 |          UU         3  32080590
+##          ...       ...       ... ...       ...       ... .         ...       ...       ...
+##   [13821665]      chr1  24472292 ---      chr1  24472986 |          UU        60       694
+##   [13821666]      chr1  24472292 ---      chr1  24805552 |          RU        60    333260
+##   [13821667]      chr1  24472292 ---      chr1  24874144 |          UU        60    401852
+##   [13821668]      chr1  24472294 ---      chr1 115668400 |          UU        60  91196106
+##   [13821669]      chr1  24472295 ---      chr1  43307467 |          UU        60  18835172
+
+
+
+
+ +
+
+Watch out +
+
+
+

.pairs files can be particularly large and therefore will take both and long time to download and a large storage footprint.

+
+
+
    +
  • +type = 'insulation' will fetch a .bigwig track file precomputed by the 4DN consortium. This track corresponds to the genome-wide insulation score computed by cooltools as described in Crane et al. (2015). To know more about this, read the excerpt from 4DN data portal. Once fetched from the 4DN data portal, the local file can be imported in R using the import function, which will generate a RleList object.
  • +
+
+
fourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'insulation') |> 
+    import(as = 'Rle')
+##  |===================================|  100%
+##  RleList of length 21
+##  $chr1
+##  numeric-Rle of length 195471971 with 38145 runs
+##    Lengths:      3065000         5000 ...         5000       171971
+##    Values :  0.00000e+00  1.01441e-01 ...     0.807009     0.000000
+##  
+##  $chr10
+##  numeric-Rle of length 130694993 with 25100 runs
+##    Lengths:     3175000        5000        5000 ...        5000      169993
+##    Values :  0.00000000  0.37584546  0.33597839 ...    0.628601    0.000000
+##  
+##  $chr11
+##  numeric-Rle of length 122082543 with 23536 runs
+##    Lengths:    3165000       5000       5000 ...       5000     162543
+##    Values :  0.0000000 -0.7906257 -0.7930040 ...   0.515919   0.000000
+##
+##  ...
+
+
    +
  • +type = 'boundaries' will fetch a .bed file precomputed by the 4DN consortium, listing the annotated borders between topological domains. These borders correspond to local minima identified from the genome-wide insulation track. It can also be imported in R using the import function, which will generate a GRanges object.
  • +
+
+
fourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'boundaries') |> 
+    import()
+##  |===================================|  100%
+##  GRanges object with 6103 ranges and 2 metadata columns:
+##           seqnames            ranges strand |        name     score
+##              <Rle>         <IRanges>  <Rle> | <character> <numeric>
+##       [1]     chr1   4380001-4385000      * |      Strong  0.695274
+##       [2]     chr1   4760001-4765000      * |        Weak  0.444476
+##       [3]     chr1   4910001-4915000      * |        Weak  0.353184
+##       [4]     chr1   5180001-5185000      * |      Strong  0.565763
+##       [5]     chr1   6170001-6175000      * |      Strong  1.644911
+##       ...      ...               ...    ... .         ...       ...
+##    [6099]     chrY 89725001-89730000      * |        Weak  0.258094
+##    [6100]     chrY 89790001-89795000      * |        Weak  0.442186
+##    [6101]     chrY 89895001-89900000      * |        Weak  0.279879
+##    [6102]     chrY 90025001-90030000      * |      Strong  0.660699
+##    [6103]     chrY 90410001-90415000      * |      Strong  1.160018
+
+
    +
  • +type = 'compartments' will fetch a .bigwig track file precomputed by the 4DN consortium. This track corresponds to the selected genome-wide eigenvector computed by cooltools and representing A/B compartments. To know more about this, read the excerpt from 4DN data portal. Once fetched from the 4DN data portal, the local file can be imported in R using the import function, which will generate a RleList object. The score represents the eigenvector values, and by convention a genomic bin with a positive score is associated with the A compartment whereas a genomic bin with a negative score is associated with the B compartment.
  • +
+
+
fourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'compartments') |> 
+    import()
+##  |===================================|  100%
+##  RleList of length 21
+##  $chr1
+##  numeric-Rle of length 195471971 with 771 runs
+##    Lengths:     3000000      250000      250000 ...      250000      221971
+##    Values :         NaN -0.83457172 -0.98202854 ...  0.45792237         NaN
+##  
+##  $chr10
+##  numeric-Rle of length 130694993 with 512 runs
+##    Lengths:     3000000      250000      250000 ...      250000      194993
+##    Values :         NaN -0.99524581 -0.76405841 ...   0.0583894         NaN
+##  
+##  $chr11
+##  numeric-Rle of length 122082543 with 478 runs
+##    Lengths:     3000000      250000      250000 ...      250000       82543
+##    Values :         NaN -0.00653325  0.26659977 ...  0.25900587         NaN
+
+

+8.1.2 Querying a complete experiment dataset

+

Rather than importing multiple files corresponding to a single experimentSet accession ID one by one, one can import all the available files associated with a experimentSet accession ID into a HiCExperiment object by using the fourDNHiCExperiment() function.

+
+
hic <- fourDNHiCExperiment('4DNESSS7VU57')
+## Fetching Hi-C contact map from 4DN portal
+##   |===================================================================| 100%
+## 
+## Compartments not found for the provided experimentSet accession.
+## Fetching insulation bigwig file from 4DN portal
+##   |===================================================================| 100%
+## 
+## Fetching borders bed file from 4DN portal
+##   |===================================================================| 100%
+
+

This is a more efficient way to import datasets, as it aggregates the different bits together into a single HiCExperiment object with populated topologicalFeatures and metadata slots.

+
+
hic
+## `HiCExperiment` object with 544,370,135 contacts over 286 regions
+## -------
+## fileName: "/home/rsg/.cache/R/fourDNData/392eba3a587_4DNFIZ59STGB.mcool"
+## focus: "whole genome"
+## resolutions(13): 1000 2000 ... 5000000 10000000
+## active resolution: 10000000
+## interactions: 40088
+## scores(2): count balanced
+## topologicalFeatures: compartments(0) borders(7887)
+## pairsFile: N/A
+## metadata(2): 4DN_info diamond_insulation
+
+
+
metadata(hic)
+##  $`4DN_info`
+##  experimentSetAccession   fileType    size organism experimentType        details                             dataset               condition      biosource biosourceType                publication  URL
+##            4DNESSS7VU57      pairs 9731.58    mouse   in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells  female granulosa cells granulosa cell  primary cell  Lindeman RE et al. (2021)  https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/b7da6d89-9e24-48a7-b3a6-f30a49c843e3/4DNFI2PHVZ5S.pairs.gz
+##            4DNESSS7VU57        hic 4160.17    mouse   in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells  female granulosa cells granulosa cell  primary cell  Lindeman RE et al. (2021)  https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/327f091d-6a63-47c4-9752-2dff303a13d9/4DNFI6GFHB6G.hic
+##            4DNESSS7VU57      mcool 2863.90    mouse   in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells  female granulosa cells granulosa cell  primary cell  Lindeman RE et al. (2021)  https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/2fed1cf8-b334-4165-a32f-df3f9ae4d6d7/4DNFIZ59STGB.mcool
+##            4DNESSS7VU57 insulation    7.25    mouse   in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells  female granulosa cells granulosa cell  primary cell  Lindeman RE et al. (2021)  https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/88e1d2ad-4d59-4c6f-9793-4fd8afc74762/4DNFI65DQZJ7.bw
+##            4DNESSS7VU57 boundaries    0.12    mouse   in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells  female granulosa cells granulosa cell  primary cell  Lindeman RE et al. (2021)  https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/2a29eec0-f551-4d50-8c0a-f4d4c2acd0db/4DNFIV519AWN.bed.gz
+##  
+##  $diamond_insulation
+##  RleList of length 20
+##      $chr1
+##      numeric-Rle of length 195471971 with 37959 runs
+##        Lengths:    3085000       5000       5000 ...       5000     186971
+##        Values :  0.0000000  0.3967191  0.3961740 ...  0.8223819  0.0000000
+##      
+##      $chr10
+##      numeric-Rle of length 130694993 with 24994 runs
+##        Lengths:      3180000         5000 ...         5000       179993
+##        Values :  0.00000e+00  5.35871e-01 ...   0.60626638   0.00000000
+## 
+##      ...
+
+

+8.2 DNA Zoo

+

The DNA Zoo Consortium is a collaborative group whose aim is to correct and refine genome assemblies across the tree of life using Hi-C approaches. As of 2023, they have performed Hi-C across more than 300 animal, plant and fungi species.

+

DNAZooData is a package giving programmatic access to these uniformly processed Hi-C contact files, as well as the refined genome assemblies.

+

The DNAZooData() function provides a gateway to DNA Zoo-hosted Hi-C files, fetching and caching relevant contact matrices in .hic format It returns a HicFile object, which can then be imported in memory using import().

+
+
library(DNAZooData)
+head(DNAZooData())
+##                  species                              readme                                                         readme_link original_assembly     new_assembly                                                             new_assembly_link new_assembly_link_status                                                                 hic_link
+##         Acinonyx_jubatus        Acinonyx_jubatus/README.json        https://dnazoo.s3.wasabisys.com/Acinonyx_jubatus/README.json           aciJub1      aciJub1_HiC         https://dnazoo.s3.wasabisys.com/Acinonyx_jubatus/aciJub1_HiC.fasta.gz                      200    https://dnazoo.s3.wasabisys.com/Acinonyx_jubatus/aciJub1.rawchrom.hic
+##       Acropora_millepora      Acropora_millepora/README.json      https://dnazoo.s3.wasabisys.com/Acropora_millepora/README.json       amil_sf_1.1  amil_sf_1.1_HiC   https://dnazoo.s3.wasabisys.com/Acropora_millepora/amil_sf_1.1_HiC.fasta.gz                      200   https://dnazoo.s3.wasabisys.com/Acropora_millepora/amil_sf_1.1_HiC.hic
+##      Addax_nasomaculatus     Addax_nasomaculatus/README.json     https://dnazoo.s3.wasabisys.com/Addax_nasomaculatus/README.json      ASM1959352v1 ASM1959352v1_HiC https://dnazoo.s3.wasabisys.com/Addax_nasomaculatus/ASM1959352v1_HiC.fasta.gz                      200 https://dnazoo.s3.wasabisys.com/Addax_nasomaculatus/ASM1959352v1_HiC.hic
+##            Aedes_aegypti           Aedes_aegypti/README.json           https://dnazoo.s3.wasabisys.com/Aedes_aegypti/README.json        AGWG.draft         AaegL5.0               https://dnazoo.s3.wasabisys.com/Aedes_aegypti/AaegL5.0.fasta.gz                      404                                                                     <NA>
+##    Aedes_aegypti__AaegL4   Aedes_aegypti__AaegL4/README.json   https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL4/README.json            AaegL3           AaegL4         https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL4/AaegL4.fasta.gz                      200         https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL4/AaegL4.hic
+##  Aedes_aegypti__AaegL5.0 Aedes_aegypti__AaegL5.0/README.json https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL5.0/README.json        AGWG.draft         AaegL5.0     https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL5.0/AaegL5.0.fasta.gz                      200     https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL5.0/AaegL5.0.hic
+
+

For example, we can directly fetch a Hi-C dataset generated from a tardigrade sample by specifying the right species argument.

+
+
hicfile <- DNAZooData(species = 'Hypsibius_dujardini')
+##  Fetching Hi-C data from DNAZoo
+##  |===================================|  100%
+hicfile
+##  HicFile object
+##  .hic file: /home/rsg/.cache/R/DNAZooData/400d7e2b0145_nHd_3.1_HiC.hic
+##  resolution: 5000
+##  pairs file:
+##  metadata(6): organism draftAssembly ... credits assemblyURL
+
+

Here again, the resulting HicFile is populated with metadata parsed from the DNA Zoo data portal.

+
+
metadata(hicfile)$organism
+##  $vernacular
+##  [1] "Tardigrade"
+##  
+##  $binomial
+##  [1] "Hypsibius dujardini"
+##  
+##  $funFact
+##  [1] "<i>Hypsibius dujardini</i> is a species of tardigrade, a tiny microscopic organism. They are also commonly called water bears. This species is found world-wide!"
+##  
+##  $extraInfo
+##  [1] "on BioKIDS website"
+##  
+##  $extraInfoLink
+##  [1] "http://www.biokids.umich.edu/critters/Hypsibius_dujardini/"
+##  
+##  $image
+##  [1] "https://static.wixstatic.com/media/2b9330_82db39c219f24b20a75cb38943aad1fb~mv2.jpg"
+##  
+##  $imageCredit
+##  [1] "By Willow Gabriel, Goldstein Lab - https://www.flickr.com/photos/waterbears/1614095719/ Template:Uploader Transferred from en.wikipedia to Commons., CC BY-SA 2.5, https://commons.wikimedia.org/w/index.php?curi
+##  d=2261992"
+##  
+##  $isChromognomes
+##  [1] "FALSE"
+##  
+##  $taxonomy
+##  [1] "Species:202423-914154-914155-914158-155166-155362-710171-710179-710192-155390-155420"
+
+

HiCFile metadata also points to a URL to directly fetch the genome assembly corrected by the DNA Zoo consortium.

+
+
metadata(hicfile)$assemblyURL
+##  [1] "https://dnazoo.s3.wasabisys.com/Hypsibius_dujardini/nHd_3.1_HiC.fasta.gz"
+
+

References

+ + +
+
+Crane, E., Bian, Q., McCord, R. P., Lajoie, B. R., Wheeler, B. S., Ralston, E. J., Uzawa, S., Dekker, J., & Meyer, B. J. (2015). Condensin-driven remodelling of x chromosome topology during dosage compensation. Nature, 523(7559), 240–244. https://doi.org/10.1038/nature14450 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/images/20230215221337.png b/docs/devel/pages/images/20230215221337.png new file mode 100644 index 0000000..bd4bb87 Binary files /dev/null and b/docs/devel/pages/images/20230215221337.png differ diff --git a/docs/devel/pages/images/20230221172531.png b/docs/devel/pages/images/20230221172531.png new file mode 100644 index 0000000..b094cad Binary files /dev/null and b/docs/devel/pages/images/20230221172531.png differ diff --git a/docs/devel/pages/images/20230303125432.png b/docs/devel/pages/images/20230303125432.png new file mode 100644 index 0000000..42336b9 Binary files /dev/null and b/docs/devel/pages/images/20230303125432.png differ diff --git a/docs/devel/pages/images/20230306102639.png b/docs/devel/pages/images/20230306102639.png new file mode 100644 index 0000000..76e5969 Binary files /dev/null and b/docs/devel/pages/images/20230306102639.png differ diff --git a/docs/devel/pages/images/20230309114047.png b/docs/devel/pages/images/20230309114047.png new file mode 100644 index 0000000..9741639 Binary files /dev/null and b/docs/devel/pages/images/20230309114047.png differ diff --git a/docs/devel/pages/images/20230309114202.png b/docs/devel/pages/images/20230309114202.png new file mode 100644 index 0000000..0bfa463 Binary files /dev/null and b/docs/devel/pages/images/20230309114202.png differ diff --git a/docs/devel/pages/images/20230321230247.png b/docs/devel/pages/images/20230321230247.png new file mode 100644 index 0000000..26a198d Binary files /dev/null and b/docs/devel/pages/images/20230321230247.png differ diff --git a/docs/devel/pages/images/20230321233026.png b/docs/devel/pages/images/20230321233026.png new file mode 100644 index 0000000..7bf6667 Binary files /dev/null and b/docs/devel/pages/images/20230321233026.png differ diff --git a/docs/devel/pages/images/20230322002953.png b/docs/devel/pages/images/20230322002953.png new file mode 100644 index 0000000..8f66da0 Binary files /dev/null and b/docs/devel/pages/images/20230322002953.png differ diff --git a/docs/devel/pages/images/20230322003342.png b/docs/devel/pages/images/20230322003342.png new file mode 100644 index 0000000..005ec69 Binary files /dev/null and b/docs/devel/pages/images/20230322003342.png differ diff --git a/docs/devel/pages/images/20230322085136.png b/docs/devel/pages/images/20230322085136.png new file mode 100644 index 0000000..0412ca2 Binary files /dev/null and b/docs/devel/pages/images/20230322085136.png differ diff --git a/docs/devel/pages/images/20230322102803.png b/docs/devel/pages/images/20230322102803.png new file mode 100644 index 0000000..0db02f7 Binary files /dev/null and b/docs/devel/pages/images/20230322102803.png differ diff --git a/docs/devel/pages/images/20230322102919.png b/docs/devel/pages/images/20230322102919.png new file mode 100644 index 0000000..d26e548 Binary files /dev/null and b/docs/devel/pages/images/20230322102919.png differ diff --git a/docs/devel/pages/images/20230322181000.png b/docs/devel/pages/images/20230322181000.png new file mode 100644 index 0000000..bad6f8a Binary files /dev/null and b/docs/devel/pages/images/20230322181000.png differ diff --git a/docs/devel/pages/images/20230322181300.png b/docs/devel/pages/images/20230322181300.png new file mode 100644 index 0000000..3fa2e44 Binary files /dev/null and b/docs/devel/pages/images/20230322181300.png differ diff --git a/docs/devel/pages/images/20230324125800.png b/docs/devel/pages/images/20230324125800.png new file mode 100644 index 0000000..f21b029 Binary files /dev/null and b/docs/devel/pages/images/20230324125800.png differ diff --git a/docs/devel/pages/images/20230327182802.png b/docs/devel/pages/images/20230327182802.png new file mode 100644 index 0000000..3c94591 Binary files /dev/null and b/docs/devel/pages/images/20230327182802.png differ diff --git a/docs/devel/pages/images/20230403090000.png b/docs/devel/pages/images/20230403090000.png new file mode 100644 index 0000000..da047d5 Binary files /dev/null and b/docs/devel/pages/images/20230403090000.png differ diff --git a/docs/devel/pages/images/20230403134800.png b/docs/devel/pages/images/20230403134800.png new file mode 100644 index 0000000..09eb45a Binary files /dev/null and b/docs/devel/pages/images/20230403134800.png differ diff --git a/docs/devel/pages/images/20230421134800.jpg b/docs/devel/pages/images/20230421134800.jpg new file mode 100644 index 0000000..d619fdc Binary files /dev/null and b/docs/devel/pages/images/20230421134800.jpg differ diff --git a/docs/devel/pages/images/20230523141745.jpg b/docs/devel/pages/images/20230523141745.jpg new file mode 100644 index 0000000..4275de2 Binary files /dev/null and b/docs/devel/pages/images/20230523141745.jpg differ diff --git a/docs/devel/pages/images/20230523144800.png b/docs/devel/pages/images/20230523144800.png new file mode 100644 index 0000000..f516645 Binary files /dev/null and b/docs/devel/pages/images/20230523144800.png differ diff --git a/docs/devel/pages/images/20230523152700.png b/docs/devel/pages/images/20230523152700.png new file mode 100644 index 0000000..d5883bc Binary files /dev/null and b/docs/devel/pages/images/20230523152700.png differ diff --git a/docs/devel/pages/images/20230523153300.png b/docs/devel/pages/images/20230523153300.png new file mode 100644 index 0000000..edb80d7 Binary files /dev/null and b/docs/devel/pages/images/20230523153300.png differ diff --git a/docs/devel/pages/images/20230523180000.png b/docs/devel/pages/images/20230523180000.png new file mode 100644 index 0000000..b6dd3f5 Binary files /dev/null and b/docs/devel/pages/images/20230523180000.png differ diff --git a/docs/devel/pages/images/20230523180300.png b/docs/devel/pages/images/20230523180300.png new file mode 100644 index 0000000..c2a7760 Binary files /dev/null and b/docs/devel/pages/images/20230523180300.png differ diff --git a/docs/devel/pages/images/20230525134200.png b/docs/devel/pages/images/20230525134200.png new file mode 100644 index 0000000..6db8fa6 Binary files /dev/null and b/docs/devel/pages/images/20230525134200.png differ diff --git a/docs/devel/pages/interactions-centric.html b/docs/devel/pages/interactions-centric.html new file mode 100644 index 0000000..c2fec98 --- /dev/null +++ b/docs/devel/pages/interactions-centric.html @@ -0,0 +1,962 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 6  Interactions-centric analysis + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+6  Interactions-centric analysis +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter focuses on the various analytical tools offered by HiContacts to compute interaction-related metrics from a HiCExperiment object.

+
+
+

Interaction-centric analyses consider a HiCExperiment object from the β€œinteractions” perspective to perform a range of operations on genomic interactions.
+This encompasses:

+ +
+
+
+ +
+
+Note +
+
+
+
    +
  • Contrary to functions presented in the previous chapter, the functions described in this chapter are not: they take HiCExperiment objects as input and generally return data frames rather than modified HiCExperiment objects.
  • +
  • Internally, most of the functions presented in this chapter make a call to interactions(<HiCExperiment>) to coerce it into GInteractions.
  • +
+
+
+
+ +
+
+

To demonstrate HiContacts functionalities, we will create an HiCExperiment object from an example .cool file provided in the HiContactsData package.

+
+
library(HiCExperiment)
+library(HiContactsData)
+
+# ---- This downloads example `.mcool` and `.pairs` files and caches them locally 
+coolf <- HiContactsData('yeast_wt', 'mcool')
+pairsf <- HiContactsData('yeast_wt', 'pairs.gz')
+
+# ---- This creates a connection to the disk-stored `.mcool` file
+cf <- CoolFile(coolf)
+cf
+
+# ---- This creates a connection to the disk-stored `.pairs` file
+pf <- PairsFile(pairsf)
+pf
+
+# ---- This imports contacts from the chromosome `II` at resolution `2000`
+hic <- import(cf, focus = 'II', resolution = 2000)
+
+
+
hic
+##  `HiCExperiment` object with 471,364 contacts over 407 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 34063 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
+
+
+

+6.1 Distance law(s)

+

+6.1.1 P(s) from a single .pairs file

+

Distance laws are generally computed directly from .pairs files. This is because the .pairs files are at 1-bp resolution whereas the contact matrices (for example from .cool files) are binned at a minimum resolution.

+

An example .pairs file can be fetched from the ExperimentHub database using the HiContactsData package.

+
+
library(HiCExperiment)
+library(HiContactsData)
+pairsf <- HiContactsData('yeast_wt', 'pairs.gz')
+pf <- PairsFile(pairsf)
+
+
+
pf
+##  PairsFile object
+##  resource: /root/.cache/R/ExperimentHub/1702dcdfa3b_7753
+
+

If needed, PairsFile connections can be imported directly into a GInteractions object with import().

+
+
import(pf)
+##  GInteractions object with 471364 interactions and 3 metadata columns:
+##             seqnames1   ranges1     seqnames2   ranges2 |     frag1     frag2
+##                 <Rle> <IRanges>         <Rle> <IRanges> | <numeric> <numeric>
+##         [1]        II       105 ---        II     48548 |      1358      1681
+##         [2]        II       113 ---        II     45003 |      1358      1658
+##         [3]        II       119 ---        II    687251 |      1358      5550
+##         [4]        II       160 ---        II     26124 |      1358      1510
+##         [5]        II       169 ---        II     39052 |      1358      1613
+##         ...       ...       ... ...       ...       ... .       ...       ...
+##    [471360]        II    808605 ---        II    809683 |      6316      6320
+##    [471361]        II    808609 ---        II    809917 |      6316      6324
+##    [471362]        II    808617 ---        II    809506 |      6316      6319
+##    [471363]        II    809447 ---        II    809685 |      6319      6321
+##    [471364]        II    809472 ---        II    809675 |      6319      6320
+##              distance
+##             <integer>
+##         [1]     48443
+##         [2]     44890
+##         [3]    687132
+##         [4]     25964
+##         [5]     38883
+##         ...       ...
+##    [471360]      1078
+##    [471361]      1308
+##    [471362]       889
+##    [471363]       238
+##    [471364]       203
+##    -------
+##    regions: 549331 ranges and 0 metadata columns
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+

We can compute a P(s) per chromosome from this .pairs file using the distanceLaw function.

+
+
library(HiContacts)
+ps <- distanceLaw(pf, by_chr = TRUE) 
+##  Importing pairs file /root/.cache/R/ExperimentHub/1702dcdfa3b_7753 in memory. This may take a while...
+ps
+##  # A tibble: 115 Γ— 6
+##    chr   binned_distance          p     norm_p norm_p_unity slope
+##    <chr>           <dbl>      <dbl>      <dbl>        <dbl> <dbl>
+##  1 II                 14 0.00000212 0.00000106         2.27  0   
+##  2 II                 16 0.0000170  0.0000170         36.4   1.56
+##  3 II                 17 0.0000361  0.0000180         38.6   1.55
+##  4 II                 19 0.0000424  0.0000212         45.5   1.55
+##  5 II                 21 0.0000467  0.0000233         50.0   1.54
+##  6 II                 23 0.0000870  0.0000290         62.1   1.53
+##  # β„Ή 109 more rows
+
+

The plotPs() and plotPsSlope() functions are convenient ggplot2-based functions with pre-configured settings optimized for P(s) visualization.

+
+
library(ggplot2)
+plotPs(ps, aes(x = binned_distance, y = norm_p, color = chr))
+##  Warning: Removed 67 rows containing missing values (`geom_line()`).
+
+
+

+
+
+
+
plotPsSlope(ps, aes(x = binned_distance, y = slope, color = chr))
+##  Warning: Removed 67 rows containing missing values (`geom_line()`).
+
+
+

+
+
+
+
+

+6.1.2 P(s) for multiple .pairs files

+

Let’s first import a second example dataset. We’ll import pairs identified in a eco1 yeast mutant.

+
+
eco1_pairsf <- HiContactsData('yeast_eco1', 'pairs.gz')
+eco1_pf <- PairsFile(eco1_pairsf)
+
+
+
eco1_ps <- distanceLaw(eco1_pf, by_chr = TRUE) 
+##  Importing pairs file /root/.cache/R/ExperimentHub/f9346a45c35_7755 in memory. This may take a while...
+eco1_ps
+##  # A tibble: 115 Γ— 6
+##    chr   binned_distance          p     norm_p norm_p_unity slope
+##    <chr>           <dbl>      <dbl>      <dbl>        <dbl> <dbl>
+##  1 II                 14 0.00000201 0.00000100        0.660  0   
+##  2 II                 16 0.0000221  0.0000221        14.5    1.46
+##  3 II                 17 0.0000492  0.0000246        16.2    1.46
+##  4 II                 19 0.0000412  0.0000206        13.5    1.45
+##  5 II                 21 0.0000653  0.0000326        21.5    1.45
+##  6 II                 23 0.0000803  0.0000268        17.6    1.44
+##  # β„Ή 109 more rows
+
+

A little data wrangling can help plotting the distance laws for 2 different samples in the same plot.

+
+
library(dplyr)
+merged_ps <- rbind(
+    ps |> mutate(sample = 'WT'), 
+    eco1_ps |> mutate(sample = 'eco1')
+)
+plotPs(merged_ps, aes(x = binned_distance, y = norm_p, color = sample, linetype = chr)) + 
+    scale_color_manual(values = c('#c6c6c6', '#ca0000'))
+##  Warning: Removed 134 rows containing missing values (`geom_line()`).
+
+
+

+
+
+
+
plotPsSlope(merged_ps, aes(x = binned_distance, y = slope, color = sample, linetype = chr)) + 
+    scale_color_manual(values = c('#c6c6c6', '#ca0000'))
+##  Warning: Removed 135 rows containing missing values (`geom_line()`).
+
+
+

+
+
+
+
+

+6.1.3 P(s) from HiCExperiment objects

+

Alternatively, distance laws can be computed from binned matrices directly by providing HiCExperiment objects. For deeply sequenced datasets, this can be significantly faster than when using original .pairs files, but the smoothness of the resulting curves will be greatly impacted, notably at short distances.

+
+
ps_from_hic <- distanceLaw(hic, by_chr = TRUE) 
+##  pairsFile not specified. The P(s) curve will be an approximation.
+plotPs(ps_from_hic, aes(x = binned_distance, y = norm_p))
+##  Warning: Removed 9 rows containing missing values (`geom_line()`).
+
+
+

+
+
+
+
plotPsSlope(ps_from_hic, aes(x = binned_distance, y = slope))
+##  Warning: Removed 8 rows containing missing values (`geom_line()`).
+
+
+

+
+
+
+
+

+6.2 Cis/trans ratios

+

The ratio between cis interactions and trans interactions is often used to assess the overall quality of a Hi-C dataset. It can be computed per chromosome using the cisTransRatio() function. You will need to provide a genome-wide HiCExperiment to estimate cis/trans ratios!

+
+
full_hic <- import(cf, resolution = 2000)
+ct <- cisTransRatio(full_hic) 
+ct
+##  # A tibble: 16 Γ— 6
+##  # Groups:   chr [16]
+##    chr       cis  trans n_total cis_pct trans_pct
+##    <fct>   <dbl>  <dbl>   <dbl>   <dbl>     <dbl>
+##  1 I      186326  96738  283064   0.658     0.342
+##  2 II     942728 273966 1216694   0.775     0.225
+##  3 III    303980 127087  431067   0.705     0.295
+##  4 IV    1858062 418218 2276280   0.816     0.184
+##  5 V      607090 220873  827963   0.733     0.267
+##  6 VI     280282 127771  408053   0.687     0.313
+##  # β„Ή 10 more rows
+
+

It can be plotted using ggplot2-based visualization functions.

+
+
ggplot(ct, aes(x = chr, y = cis_pct)) + 
+    geom_col(position = position_stack()) + 
+    theme_bw() + 
+    guides(x=guide_axis(angle = 90)) + 
+    scale_y_continuous(labels = scales::percent) + 
+    labs(x = 'Chromosomes', y = '% of cis contacts')
+
+
+

+
+
+
+
+

Cis/trans contact ratios will greatly vary depending on the cell cycle phase the sample is in! For instance, chromosomes during the mitosis phase of the cell cycle have very little trans contacts, due to their structural organization and individualization.

+

+6.3 Virtual 4C profiles

+

Interaction profile of a genomic locus of interest with its surrounding environment or the rest of the genome is frequently generated. In some cases, this can help in identifying and/or comparing regulatory or structural interactions.

+

For instance, we can compute the genome-wide virtual 4C profile of interactions anchored at the centromere in chromosome II (located at ~ 238kb).

+
+
library(GenomicRanges)
+v4C <- virtual4C(full_hic, viewpoint = GRanges("II:230001-240000"))
+v4C
+##  GRanges object with 6045 ranges and 4 metadata columns:
+##           seqnames        ranges strand |       score        viewpoint
+##              <Rle>     <IRanges>  <Rle> |   <numeric>      <character>
+##       [1]        I        1-2000      * |  0.00000000 II:230001-240000
+##       [2]        I     2001-4000      * |  0.00000000 II:230001-240000
+##       [3]        I     4001-6000      * |  0.00129049 II:230001-240000
+##       [4]        I     6001-8000      * |  0.00000000 II:230001-240000
+##       [5]        I    8001-10000      * |  0.00000000 II:230001-240000
+##       ...      ...           ...    ... .         ...              ...
+##    [6041]      XVI 940001-942000      * | 0.000775721 II:230001-240000
+##    [6042]      XVI 942001-944000      * | 0.000000000 II:230001-240000
+##    [6043]      XVI 944001-946000      * | 0.000000000 II:230001-240000
+##    [6044]      XVI 946001-948000      * | 0.000000000 II:230001-240000
+##    [6045]      XVI 948001-948066      * | 0.000000000 II:230001-240000
+##              center in_viewpoint
+##           <numeric>    <logical>
+##       [1]    1000.5        FALSE
+##       [2]    3000.5        FALSE
+##       [3]    5000.5        FALSE
+##       [4]    7000.5        FALSE
+##       [5]    9000.5        FALSE
+##       ...       ...          ...
+##    [6041]    941000        FALSE
+##    [6042]    943000        FALSE
+##    [6043]    945000        FALSE
+##    [6044]    947000        FALSE
+##    [6045]    948034        FALSE
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome; no seqlengths
+
+

ggplot2 can be used to visualize the 4C-like profile over multiple chromosomes.

+
+
+
df <- as_tibble(v4C)
+ggplot(df, aes(x = center, y = score)) + 
+    geom_area(position = "identity", alpha = 0.5) + 
+    theme_bw() + 
+    labs(x = "Position", y = "Contacts with viewpoint") +
+    scale_x_continuous(labels = scales::unit_format(unit = "M", scale = 1e-06)) + 
+    facet_wrap(~seqnames, scales = 'free_y')
+
+
+

+
+
+
+
+
+

This clearly highlights trans interactions of the chromosome II centromere with the centromeres from other chromosomes.

+

+6.4 Scalograms

+

Scalograms were introduced in Lioy et al. (2018) to investigate distance-dependent contact frequencies for individual genomic bins along chromosomes.
+To generate a scalogram, one needs to provide a HiCExperiment object with a valid associated pairsFile.

+
+
pairsFile(hic) <- pairsf
+scalo <- scalogram(hic) 
+##  Importing pairs file /root/.cache/R/ExperimentHub/1702dcdfa3b_7753 in memory. This may take a while...
+plotScalogram(scalo |> filter(chr == 'II'), ylim = c(1e3, 1e5))
+
+
+

+
+
+
+
+

Several scalograms can be plotted together to compare distance-dependent contact frequencies along a given chromosome in different samples.

+
+
+
eco1_hic <- import(
+    CoolFile(HiContactsData('yeast_eco1', 'mcool')), 
+    focus = 'II', 
+    resolution = 2000
+)
+##  see ?HiContactsData and browseVignettes('HiContactsData') for documentation
+##  loading from cache
+eco1_pairsf <- HiContactsData('yeast_eco1', 'pairs.gz')
+##  see ?HiContactsData and browseVignettes('HiContactsData') for documentation
+##  loading from cache
+pairsFile(eco1_hic) <- eco1_pairsf
+eco1_scalo <- scalogram(eco1_hic) 
+##  Importing pairs file /root/.cache/R/ExperimentHub/f9346a45c35_7755 in memory. This may take a while...
+merged_scalo <- rbind(
+    scalo |> mutate(sample = 'WT'), 
+    eco1_scalo |> mutate(sample = 'eco1')
+)
+plotScalogram(merged_scalo |> filter(chr == 'II'), ylim = c(1e3, 1e5)) + 
+    facet_grid(~sample)
+
+
+

+
+
+
+
+
+

This example points out the overall longer interactions within the long arm of the chromosome II in an eco1 mutant.

+

References

+ + +
+
+Lioy, V. S., Cournac, A., Marbouty, M., Duigou, S., Mozziconacci, J., EspΓ©li, O., Boccard, F., & Koszul, R. (2018). Multiscale structuring of the e. Coli chromosome by nucleoid-associated and condensin proteins. Cell, 172(4), 771–783.e18. https://doi.org/10.1016/j.cell.2017.12.027 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/interactions-centric_files/figure-html/ps-1.png b/docs/devel/pages/interactions-centric_files/figure-html/ps-1.png new file mode 100644 index 0000000..08abccf Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/ps-1.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/ps-2.png b/docs/devel/pages/interactions-centric_files/figure-html/ps-2.png new file mode 100644 index 0000000..c89649c Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/ps-2.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-10-1.png b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 0000000..774bed7 Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-10-2.png b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-10-2.png new file mode 100644 index 0000000..9618d29 Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-10-2.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-11-1.png b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-11-1.png new file mode 100644 index 0000000..060eae9 Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-11-1.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-11-2.png b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-11-2.png new file mode 100644 index 0000000..c20076e Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-11-2.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-13-1.png b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 0000000..3d4994e Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-15-1.png b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-15-1.png new file mode 100644 index 0000000..3879fc7 Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-15-1.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-16-1.png b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 0000000..17429b1 Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-17-1.png b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 0000000..10cafee Binary files /dev/null and b/docs/devel/pages/interactions-centric_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/docs/devel/pages/interoperability.html b/docs/devel/pages/interoperability.html new file mode 100644 index 0000000..71c467b --- /dev/null +++ b/docs/devel/pages/interoperability.html @@ -0,0 +1,1125 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 9  Interoperability: using HiCExperiment with other R packages + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+9  Interoperability: using HiCExperiment with other R packages +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This notebook illustrates how to use a range of popular Hi-Cβ€”related R packages with HiCExperiment objects. Conversion to the data structures supported by the following packages is illustrated here:

+
    +
  • diffHic
  • +
  • hicrep
  • +
  • multiHiCcompare
  • +
  • TopDom
  • +
  • +GOTHiC +
  • +
+
+
+

+9.1 diffHic

+

diffHic is the first R package dedicated to Hi-C processing and analysis (Lun & Smyth (2015)). It is packed with useful functions to generate a contact matrix from read pairs and to perform downstream investigation, including normalization, 2D β€œpeak” (i.e. loops) finding and aggregation, differential interaction between samples, etc. It works seamlessly with the InteractionSet class of object, which can be easily obtained from a HiCExperiment object.

+

To do so, we first need to extract GInteractions from one or several HiCExperiment objects and create a single InteractionSet object.

+
+
library(InteractionSet)
+library(GenomicRanges)
+library(HiCExperiment)
+library(HiContactsData)
+
+# ---- This downloads an example `.mcool` file and caches it locally 
+coolf <- HiContactsData('yeast_wt', 'mcool')
+##  see ?HiContactsData and browseVignettes('HiContactsData') for documentation
+##  loading from cache
+cool <- import(coolf, format = 'cool')
+gi <- cool |> 
+    interactions() |> 
+    as("ReverseStrictGInteractions")
+iset <- InteractionSet(
+    assays = list(
+        counts = matrix(gi$count, ncol = 1), 
+        balanced = matrix(gi$balanced, ncol = 1)
+    ), 
+    interactions = gi, 
+    colData = data.frame(lib = c("WT"), totals = sum(gi$count))
+)
+
+

From there, we can filter interactions to only retain those with significant enrichment over background.

+
+
library(diffHic)
+set.seed(1234)
+
+# --- Filter to find aggregated interactions
+enrichments <- enrichedPairs(iset)
+filter <- filterPeaks(enrichments, min.enrich = log2(1.2), min.diag = 5)
+filtered_iset <- iset[filter]
+filtered_iset
+##  class: InteractionSet 
+##  dim: 41872 1 
+##  metadata(0):
+##  assays(2): counts balanced
+##  rownames: NULL
+##  rowData names(4): bin_id1 bin_id2 count balanced
+##  colnames: NULL
+##  colData names(2): lib totals
+##  type: ReverseStrictGInteractions
+##  regions: 12079
+
+# --- Visualize filtered interactions 
+library(plyinteractions)
+library(HiContacts)
+##  Registered S3 methods overwritten by 'readr':
+##    method                    from 
+##    as.data.frame.spec_tbl_df vroom
+##    as_tibble.spec_tbl_df     vroom
+##    format.col_spec           vroom
+##    print.col_spec            vroom
+##    print.collector           vroom
+##    print.date_names          vroom
+##    print.locale              vroom
+##    str.col_spec              vroom
+interactions(filtered_iset) |> 
+    filter(seqnames2 == 'II', seqnames1 == seqnames2) |> 
+    plotMatrix(use.scores = 'count')
+
+
+

+
+
+
+
+

Next, we can cluster filtered interactions that are next to each other.

+
+
# --- Cluster interactions to find loops
+clustered_iset <- clusterPairs(filtered_iset, tol = 5000)
+clustered_iset$interactions 
+##  ReverseStrictGInteractions object with 1644 interactions and 0 metadata columns:
+##           seqnames1       ranges1 strand1     seqnames2       ranges2 strand2
+##               <Rle>     <IRanges>   <Rle>         <Rle>     <IRanges>   <Rle>
+##       [1]         I  15001-149000       * ---         I      1-122000       *
+##       [2]         I 133001-148000       * ---         I 127001-139000       *
+##       [3]         I 154001-160000       * ---         I 128001-149000       *
+##       [4]         I 168001-173000       * ---         I 138001-148000       *
+##       [5]         I 184001-196000       * ---         I   15001-23000       *
+##       ...       ...           ...     ... ...       ...           ...     ...
+##    [1640]       XVI 897001-898000       * ---       XVI 831001-832000       *
+##    [1641]       XVI 907001-910000       * ---       XVI 840001-843000       *
+##    [1642]       XVI 926001-934000       * ---       XVI 872001-878000       *
+##    [1643]       XVI 933001-934000       * ---       XVI 858001-859000       *
+##    [1644]       XVI 933001-942000       * ---       XVI 928001-934000       *
+##    -------
+##    regions: 2822 ranges and 0 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome
+
+# --- Visualize clustered interactions 
+interactions(filtered_iset) |> 
+    mutate(cluster = clustered_iset$indices[[1]]) |> 
+    filter(seqnames2 == 'II', seqnames1 == seqnames2) |> 
+    plotMatrix(use.scores = 'cluster')
+
+
+

+
+
+
+
+

Finally, we can visualize identified individual interaction clusters identified with diffHic using HiContacts.

+
+
# --- Plot matrix at a clustered loops
+cgi <- clustered_iset$interactions[554]
+seqn <- seqnames(anchors(cgi, type="second"))
+start <- start(anchors(cgi, type="second")) - 50000
+end <- end(anchors(cgi, type="first")) + 50000
+interactions_peak <- GRanges(seqn, IRanges(start, end))
+p <- plotMatrix(cool[interactions_peak])
+
+library(ggplot2)
+an <- anchors(cgi)
+p + geom_rect(
+    data = data.frame(xmin = start(an[[2]]), xmax = end(an[[2]]), ymin = start(an[[1]]), ymax = end(an[[1]])), 
+    aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), 
+    inherit.aes = FALSE, 
+    fill = NA, 
+    colour = 'cyan'
+)
+
+
+

+
+
+
+
+

+9.2 HiCrep

+

hicrep is a popular package to compute stratum-adjusted correlations between Hi-C datasets (Yang et al. (2017)). β€œStratum” refers to the distance from the main diagonal: with increase distance from the main diagonal, interactions of the DNA polymer are bound to decrease. hicrep computes a β€œper-stratum” correlation score and computes a weighted average correlation for entire chromosomes.

+
+
+
+ +
+
+Installing hicrep +
+
+
+

hicrep package has been available from Bioconductor for many years but has been withdrawn from their repositories at some point. You can always install hicrep directly from its GitHub repository as follows:

+
+
remotes::install_github('TaoYang-dev/hicrep')
+
+
+
+

In order to use hicrep, we first need to create two HiCExperiment objects.

+
+
# ---- This downloads example `.mcool` files and caches them locally 
+coolf_eco1 <- HiContactsData('yeast_eco1', 'mcool')
+
+
+
hic_wt <- import(coolf_wt, format = 'cool')
+hic_eco1 <- import(coolf_eco1, format = 'cool')
+
+

We can now run the main get.scc function from hicrep. The documentation for this function is available from the console by typing ?hicrep::get.scc. More information is also available from the GitHub page. It informs the end user that the input for this function should be two intra-chromosomal Hi-C raw count matrices in square (optionally sparse) format.

+
+
hic_wt
+##  `HiCExperiment` object with 8,757,906 contacts over 12,079 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "whole genome" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 1000 
+##  interactions: 2945692 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+as.matrix(hic_wt["IV"], use.scores = 'count')[1:10, 1:10]
+##  10 x 10 sparse Matrix of class "dgTMatrix"
+##                           
+##   [1,] . 1 . . 1 . . . . .
+##   [2,] 1 . . . . . . . . .
+##   [3,] . . . . . . . . . .
+##   [4,] . . . . . . . . . .
+##   [5,] 1 . . . . . . . 1 .
+##   [6,] . . . . . . . . . .
+##   [7,] . . . . . . . . . .
+##   [8,] . . . . . . . . 1 .
+##   [9,] . . . . 1 . . 1 . .
+##  [10,] . . . . . . . . . .
+
+library(hicrep)
+scc <- get.scc(
+    as.matrix(hic_wt["IV"], use.scores = 'count'), 
+    as.matrix(hic_eco1["IV"], use.scores = 'count'), 
+    resol = 1000, h = 25, lbr = 5000, ubr = 50000
+)
+scc
+##  $corr
+##   [1] 0.9412784 0.9410680 0.9408082 0.9404796 0.9404544 0.9402584 0.9400710
+##   [8] 0.9398965 0.9397935 0.9397027 0.9396112 0.9393001 0.9393180 0.9390608
+##  [15] 0.9391645 0.9394670 0.9395147 0.9396798 0.9397547 0.9398291 0.9401371
+##  [22] 0.9402369 0.9402251 0.9404188 0.9404327 0.9403101 0.9402634 0.9401683
+##  [29] 0.9401746 0.9394978 0.9391277 0.9381969 0.9371561 0.9357012 0.9342620
+##  [36] 0.9324366 0.9302835 0.9277556 0.9247008 0.9208466 0.9166648 0.9120206
+##  [43] 0.9060828 0.9002430 0.8931754 0.8847777
+##  
+##  $wei
+##   [1] 123.2500 123.1667 123.0833 123.0000 122.9167 122.8333 122.7500 122.6667
+##   [9] 122.5833 122.5000 122.4167 122.3333 122.2500 122.1667 122.0833 122.0000
+##  [17] 121.9167 121.8333 121.7500 121.6667 121.5833 121.5000 121.4167 121.3333
+##  [25] 121.2500 121.1667 121.0833 121.0000 120.9167 120.8333 120.7500 120.6667
+##  [33] 120.5833 120.5000 120.4167 120.3333 120.2500 120.1667 120.0833 120.0000
+##  [41] 119.9167 119.8333 119.7500 119.6667 119.5833 119.5000
+##  
+##  $scc
+##            [,1]
+##  [1,] 0.9334303
+##  
+##  $std
+##  [1] 0.001994845
+
+scc$scc
+##            [,1]
+##  [1,] 0.9334303
+
+

+9.3 multiHiCcompare

+

The multiHiCcompare package provides functions for joint normalization and difference detection in multiple Hi-C datasets (Stansfield et al. (2019)). According to its excerpt, to perform differential interaction analysis, it requires a list of raw counts for different samples/replicates, stored in data frames with four columns (chr, start1, start2, count).
+Manipulate a HiCExperiment object to coerce it into such structure is straightforward.

+
+
library(dplyr)
+library(tidyr)
+library(purrr)
+hics <- list(
+    "wt" = import(coolf_wt, format = 'cool'),
+    "eco1" = import(coolf_eco1, format = 'cool')
+)
+hics_list <- map(hics, ~ .x['XI'] |> 
+    as.data.frame() |>
+    mutate(chr = 1) |> 
+    relocate(chr) |>
+    select(chr, start1, start2, count)
+)
+head(hics_list[[1]])
+##    chr start1 start2 count
+##  1   1      1      1     2
+##  2   1      1   1001     3
+##  3   1      1   2001     3
+##  4   1      1   3001    13
+##  5   1      1   4001     9
+##  6   1      1   5001    13
+
+

Once this list is generated, the classical multiHiCcompare workflow can be applied: first run make_hicexp(), followed by cyclic_loess(), then hic_exactTest() and finally results():

+
+
DI <- hics_list |> 
+    make_hicexp(
+        data_list = hics_list, 
+        groups = factor(c(1, 2))
+    ) |> 
+    cyclic_loess() |> 
+    hic_exactTest() |> 
+    results()
+DI
+##         chr region1 region2 D      logFC    logCPM    p.value     p.adj
+##      1:   1       1    1001 1  0.4279414  6.382927 0.78960192 1.0000000
+##      2:   1       1    3001 3  1.0325237  8.339327 0.06035705 0.9501367
+##      3:   1       1    4001 4  0.6862141  7.597689 0.34723639 1.0000000
+##      4:   1       1    5001 5  0.5124878  7.960339 0.43133791 1.0000000
+##      5:   1       1    6001 6 -0.3568672  8.563374 0.52289982 1.0000000
+##     ---                                                                
+##  22637:   1  663001  666001 3 -1.1680738  7.158551 0.17500113 1.0000000
+##  22638:   1  664001  664001 0  1.4530501  8.536212 0.16535151 1.0000000
+##  22639:   1  664001  665001 1 -0.1014769  8.166275 1.00000000 1.0000000
+##  22640:   1  665001  665001 0 -0.3110054 10.013750 0.60075706 1.0000000
+##  22641:   1  665001  666001 1 -0.4989794  7.750157 0.41481212 1.0000000
+
+

+9.4 TopDom

+

The TopDom method is widely used to annotate topological domains in genomes from Hi-C data (Shin et al. (2015)). The TopDom package was created to implement this method in R (Bengtsson et al. (2020)).

+

Unfortunately, the format of the input to TopDom is rather tricky (see ?TopDom::readHiC). The following chunk of code shows how to coerce a HiCExperiment object into a TopDom-compatible object.

+
+
library(TopDom)
+hic <- import(coolf_wt, format = 'cool')
+HiCExperiment2TopDom <- function(hic, chr) {
+    data <- list()
+    cm <- as(hic[chr], 'ContactMatrix')
+    data$counts <- as.matrix(cm) |> base::as.matrix()
+    data$counts[is.na(data$counts)] <- 0
+    data$bins <- regions(cm) |> 
+        as.data.frame() |> 
+        select(seqnames, start, end) |>
+        mutate(seqnames = as.character(seqnames)) |>
+        mutate(id = 1:n(), start = start - 1) |> 
+        relocate(id) |> 
+        dplyr::rename(chr = seqnames, from.coord = start, to.coord = end)
+    class(data) <- 'TopDomData'
+    return(data)
+}
+hic_topdom <- HiCExperiment2TopDom(hic, "II")
+hic_topdom
+##  TopDomData:
+##  bins:
+##  'data.frame':   813 obs. of  4 variables:
+##   $ id        : int  1 2 3 4 5 6 7 8 9 10 ...
+##   $ chr       : chr  "II" "II" "II" "II" ...
+##   $ from.coord: num  0 1000 2000 3000 4000 5000 6000 7000 8000 9000 ...
+##   $ to.coord  : int  1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 ...
+##  counts:
+##   num [1:813, 1:813] 0 0 0 0 0 0 0 0 0 0 ...
+
+

Now that we have coerced a HiCExperiment object into a TopDom-compatible object, we can use the main TopDom function to annotate topological domains.

+
+
domains <- TopDom::TopDom(hic_topdom, window.size = 5)
+domains
+##  TopDom:
+##  Parameters:
+##  - window.size: 5
+##  - statFilter: TRUE
+##  binSignal:
+##  'data.frame':   813 obs. of  7 variables:
+##   $ id        : int  1 2 3 4 5 6 7 8 9 10 ...
+##   $ chr       : chr  "II" "II" "II" "II" ...
+##   $ from.coord: num  0 1000 2000 3000 4000 5000 6000 7000 8000 9000 ...
+##   $ to.coord  : int  1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 ...
+##   $ local.ext : num  -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 0 0 ...
+##   $ mean.cf   : num  0 0 0 0 0 ...
+##   $ pvalue    : num  1 1 1 1 1 ...
+##  domain:
+##  'data.frame':   61 obs. of  7 variables:
+##   $ chr       : chr  "II" "II" "II" "II" ...
+##   $ from.id   : int  1 9 31 36 47 61 76 82 91 102 ...
+##   $ from.coord: num  0 8000 30000 35000 46000 60000 75000 81000 90000 101000 ...
+##   $ to.id     : int  8 30 35 46 60 75 81 90 101 136 ...
+##   $ to.coord  : num  8000 30000 35000 46000 60000 75000 81000 90000 101000 136000 ...
+##   $ tag       : chr  "gap" "domain" "gap" "domain" ...
+##   $ size      : num  8000 22000 5000 11000 14000 15000 6000 9000 11000 35000 ...
+##  bed:
+##  'data.frame':   61 obs. of  4 variables:
+##   $ chrom     : chr  "II" "II" "II" "II" ...
+##   $ chromStart: num  0 8000 30000 35000 46000 60000 75000 81000 90000 101000 ...
+##   $ chromEnd  : num  8000 30000 35000 46000 60000 75000 81000 90000 101000 136000 ...
+##   $ name      : chr  "gap" "domain" "gap" "domain" ...
+
+

The resulting domains object can be used to extract annotated domains, store them in topologicalFeatures of the original HiCExperiment, and optionally write a bed file to export them in text.

+
+
topologicalFeatures(hic, 'domain') <- domains$bed |> 
+    mutate(chromStart = chromStart + 1) |> 
+    filter(name == 'domain') |> 
+    makeGRangesFromDataFrame()
+topologicalFeatures(hic, 'domain')
+##  GRanges object with 52 ranges and 0 metadata columns:
+##         seqnames        ranges strand
+##            <Rle>     <IRanges>  <Rle>
+##     [1]       II    8001-30000      *
+##     [2]       II   35001-46000      *
+##     [3]       II   46001-60000      *
+##     [4]       II   60001-75000      *
+##     [5]       II   75001-81000      *
+##     ...      ...           ...    ...
+##    [48]       II 664001-681000      *
+##    [49]       II 681001-707000      *
+##    [50]       II 707001-714000      *
+##    [51]       II 714001-761000      *
+##    [52]       II 761001-806000      *
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+rtracklayer::export(topologicalFeatures(hic, 'domain'), 'hic_domains.bed')
+
+

+9.5 GOTHiC

+

GOTHiC relies on a cumulative binomial test to detect interactions between distal genomic loci that have significantly more reads than expected by chance in Hi-C experiments (Mifsud et al. (2017)).

+
+
+
+ +
+
+Using the GOTHiC function +
+
+
+

Unfortunately, the main GOTHiC function require two .bam files as input. These files are often deleted due to their larger size, while the filtered pairs file itself is retained.

+

Moreover, the internal nuts and bolts of the main GOTHiC function perform several operations that are not required in modern workflows:

+
    +
  1. +Filtering pairs from same restriction fragment; this step is now usually taken care of automatically, e.g. with HiCool Hi-C processing package.
  2. +
  3. +Filtering short-range pairs; the GOTHiC package hard-codes a 10kb lower threshold for minimum pair distance. More advanced optimized filtering approaches have been implemented since then, to circumvent the need for such hard-coded threshold.
  4. +
  5. +Binning pairs; this step is also already taken care of, when working with Hi-C matrices in modern formats, e.g. with .(m)cool files.
  6. +
+
+
+

Based on these facts, we can simplify the binomial test function provided by GOTHiC so that it can directly used binned interactions imported as a HiCExperiment object in R.

+
+
Show the code for GOTHiC_binomial function
GOTHiC_binomial <- function(x) {
+
+    if (length(trans(x)) != 0) stop("Only `cis` interactions can be used here.")
+    ints <- interactions(x) |>
+        as.data.frame() |> 
+        select(seqnames1, start1, seqnames2, start2, count) |>
+        dplyr::rename(chr1 = seqnames1, locus1 = start1, chr2 = seqnames2, locus2 = start2, frequencies = count) |>
+        mutate(locus1 = locus1 - 1, locus2 = locus2 - 1) |>
+        mutate(int1 = paste0(chr1, '_', locus1), int2 = paste0(chr2, '_', locus2))
+    
+    numberOfReadPairs <- sum(ints$frequencies)
+    all_bins <- unique(c(unique(ints$int1), unique(ints$int2)))
+    all_bins <- sort(all_bins)
+    upperhalfBinNumber <- (length(all_bins)^2 - length(all_bins))/2
+
+    cov <- ints |> 
+        group_by(int1) |> 
+        tally(frequencies) |> 
+        full_join(ints |> 
+            group_by(int2) |> 
+            tally(frequencies), 
+            by = c('int1' = 'int2')
+        ) |> 
+        rowwise() |> 
+        mutate(coverage = sum(n.x, n.y, na.rm = TRUE)) |> 
+        ungroup() |>
+        mutate(relative_coverage = coverage/sum(coverage))
+    
+    results <- mutate(ints,
+        cov1 = left_join(ints, select(cov, int1, relative_coverage), by = c('int1' = 'int1'))$relative_coverage, 
+        cov2 = left_join(ints, select(cov, int1, relative_coverage), by = c('int2' = 'int1'))$relative_coverage,
+        probability = cov1 * cov2 * 2 * 1/(1 - sum(cov$relative_coverage^2)),
+        predicted = probability * numberOfReadPairs
+    ) |> 
+    rowwise() |>
+    mutate(
+        pvalue = binom.test(
+            frequencies, 
+            numberOfReadPairs, 
+            probability,
+            alternative = "greater"
+        )$p.value
+    ) |> 
+    ungroup() |> 
+    mutate(
+        logFoldChange = log2(frequencies / predicted), 
+        qvalue = stats::p.adjust(pvalue, method = "BH", n = upperhalfBinNumber)
+    )
+
+    scores(x, "probability") <- results$probability
+    scores(x, "predicted") <- results$predicted
+    scores(x, "pvalue") <- results$pvalue
+    scores(x, "qvalue") <- results$qvalue
+    scores(x, "logFoldChange") <- results$logFoldChange
+
+    return(x)
+
+} 
+
+
+
+
res <- GOTHiC_binomial(hic["II"])
+res
+##  `HiCExperiment` object with 471,364 contacts over 802 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 1000 
+##  interactions: 74360 
+##  scores(7): count balanced probability predicted pvalue qvalue logFoldChange 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) domain(52) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+interactions(res)
+##  GInteractions object with 74360 interactions and 9 metadata columns:
+##            seqnames1       ranges1 strand1     seqnames2       ranges2
+##                <Rle>     <IRanges>   <Rle>         <Rle>     <IRanges>
+##        [1]        II        1-1000       * ---        II     1001-2000
+##        [2]        II        1-1000       * ---        II     5001-6000
+##        [3]        II        1-1000       * ---        II     6001-7000
+##        [4]        II        1-1000       * ---        II     8001-9000
+##        [5]        II        1-1000       * ---        II    9001-10000
+##        ...       ...           ...     ... ...       ...           ...
+##    [74356]        II 807001-808000       * ---        II 809001-810000
+##    [74357]        II 807001-808000       * ---        II 810001-811000
+##    [74358]        II 808001-809000       * ---        II 808001-809000
+##    [74359]        II 808001-809000       * ---        II 809001-810000
+##    [74360]        II 809001-810000       * ---        II 809001-810000
+##            strand2 |   bin_id1   bin_id2     count  balanced probability
+##              <Rle> | <numeric> <numeric> <numeric> <numeric>   <numeric>
+##        [1]       * |       231       232         1       NaN 7.83580e-09
+##        [2]       * |       231       236         2       NaN 2.81318e-08
+##        [3]       * |       231       237         1       NaN 2.02960e-08
+##        [4]       * |       231       239         2       NaN 6.73108e-08
+##        [5]       * |       231       240         3       NaN 7.37336e-08
+##        ...     ... .       ...       ...       ...       ...         ...
+##    [74356]       * |      1038      1040         8 0.0472023 3.85638e-07
+##    [74357]       * |      1038      1041         1       NaN 5.03006e-08
+##    [74358]       * |      1039      1039         1       NaN 8.74604e-08
+##    [74359]       * |      1039      1040         7       NaN 1.02111e-07
+##    [74360]       * |      1040      1040         2 0.0411355 1.19216e-07
+##             predicted      pvalue      qvalue logFoldChange
+##             <numeric>   <numeric>   <numeric>     <numeric>
+##        [1] 0.00369352 3.68670e-03 0.063385760       8.08079
+##        [2] 0.01326033 8.71446e-05 0.001926954       7.23674
+##        [3] 0.00956681 9.52120e-03 0.150288341       6.70775
+##        [4] 0.03172791 4.92808e-04 0.009806734       5.97810
+##        [5] 0.03475538 6.81713e-06 0.000173165       6.43158
+##        ...        ...         ...         ...           ...
+##    [74356]  0.1817758 2.51560e-11 1.07966e-09       5.45977
+##    [74357]  0.0237099 2.34310e-02 3.38098e-01       5.39837
+##    [74358]  0.0412257 4.03875e-02 5.49519e-01       4.60031
+##    [74359]  0.0481315 1.13834e-13 5.77259e-12       7.18423
+##    [74360]  0.0561941 1.52097e-03 2.79707e-02       5.15344
+##    -------
+##    regions: 802 ranges and 4 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome
+
+ +

References

+ + +
+
+Bengtsson, H., Shin, H., Lazaris, H., Hu, G., & Zhou, X. (2020). R package TopDom: An efficient and deterministic method for identifying topological domains in genomes. https://github.com/HenrikBengtsson/TopDom +
+
+Lun, A. T. L., & Smyth, G. K. (2015). diffHic: a Bioconductor package to detect differential genomic interactions in Hi-C data. BMC Bioinf., 16(1), 1–11. https://doi.org/10.1186/s12859-015-0683-0 +
+
+Mifsud, B., Martincorena, I., Darbo, E., Sugar, R., Schoenfelder, S., Fraser, P., & Luscombe, N. M. (2017). GOTHiC, a probabilistic model to resolve complex biases and to identify real interactions in hi-c data. PLOS ONE, 12(4), e0174744. https://doi.org/10.1371/journal.pone.0174744 +
+
+Shin, H., Shi, Y., Dai, C., Tjong, H., Gong, K., Alber, F., & Zhou, X. J. (2015). TopDom: An efficient and deterministic method for identifying topological domains in genomes. Nucleic Acids Research, 44(7), e70–e70. https://doi.org/10.1093/nar/gkv1505 +
+
+Stansfield, J. C., Cresswell, K. G., & Dozmorov, M. G. (2019). multiHiCcompare: Joint normalization and comparative analysis of complex hi-c experiments. Bioinformatics, 35(17), 2916–2923. https://doi.org/10.1093/bioinformatics/btz048 +
+
+Yang, T., Zhang, F., YardΔ±mcΔ±, G. G., Song, F., Hardison, R. C., Noble, W. S., Yue, F., & Li, Q. (2017). HiCRep: Assessing the reproducibility of hi-c data using a stratum-adjusted correlation coefficient. Genome Research, 27(11), 1939–1949. https://doi.org/10.1101/gr.220640.117 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-3-1.png b/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 0000000..2e00e44 Binary files /dev/null and b/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-3-1.png differ diff --git a/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-4-1.png b/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-4-1.png new file mode 100644 index 0000000..f1e35e8 Binary files /dev/null and b/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-4-1.png differ diff --git a/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-5-1.png b/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-5-1.png new file mode 100644 index 0000000..cb1e06a Binary files /dev/null and b/docs/devel/pages/interoperability_files/figure-html/unnamed-chunk-5-1.png differ diff --git a/docs/devel/pages/matrix-centric.html b/docs/devel/pages/matrix-centric.html new file mode 100644 index 0000000..8f509ba --- /dev/null +++ b/docs/devel/pages/matrix-centric.html @@ -0,0 +1,974 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 5  Matrix-centric analysis + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+5  Matrix-centric analysis +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter focuses on the various analytical tools offered by HiContacts to compute matrix-related metrics from a HiCExperiment object.

+
+
+

In the first part of this book, we have seen how to query parts or all of the data contained in Hi-C contact matrices using the HiCExperiment object (Chapter 2), how to manipulate HiCExperiment objects (Chapter 3) and how to visualize Hi-C contact matrices as heatmaps (Chapter 4).

+

The HiContacts package directly operates on HiCExperiment objects and extends its usability by providing a comprehensive toolkit to analyze Hi-C data, focusing on four main topics:

+ +

Matrix-centric analyses consider a HiCExperiment object from the β€œmatrix” perspective to perform a range of matrix-based operations. This encompasses:

+ +

+
+
+
+ +
+
+Note +
+
+
+
    +
  • All the functions described in this chapter are endomorphisms: they take HiCExperiment objects as input and return modified HiCExperiment objects.
  • +
  • Internally, most of the functions presented in this chapter make a call to as.matrix(<HiCExperiment>) to coerce it into a matrix.
  • +
+
+
+
+ +
+
+

To demonstrate HiContacts functionalities, we will create an HiCExperiment object from an example .cool file provided in the HiContactsData package.

+
+
library(HiCExperiment)
+library(HiContactsData)
+
+# ---- This downloads an example `.mcool` file and caches it locally 
+coolf <- HiContactsData('yeast_wt', 'mcool')
+
+# ---- This creates a connection to the disk-stored `.mcool` file
+cf <- CoolFile(coolf)
+cf
+
+# ---- This imports contacts from the chromosome `II` at resolution `2000`
+hic <- import(cf, focus = 'II', resolution = 2000)
+
+
+
hic
+##  `HiCExperiment` object with 471,364 contacts over 407 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 34063 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
+
+
+

+5.1 Operations in an individual matrix

+

+5.1.1 Balancing a raw interaction count map

+

Hi-C sequencing coverage is systematically affected by multiple confounding factors, e.g.  density of restriction sites, GC%, genome mappability, etc.. Overall, it generally ends up not homogenous throughout the entire genome and this leads to artifacts in un-normalized count matrices.

+

To correct for sequencing coverage heterogeneity of raw count maps, Hi-C data can be normalized using matrix balancing approaches (Cournac et al. (2012), Imakaev et al. (2012)). This is generally done directly on the disk-stored matrices using out-of-memory strategies (e.g. with cooler balance <.cool>). However, if contact matrix files are imported into a HiCExperiment object but no balanced scores are available, in-memory balancing can be performed using the normalize function. This adds an extra ICE element in scores list (while the interactions themselves are unmodified).

+
+
normalized_hic <- normalize(hic)
+normalized_hic
+##  `HiCExperiment` object with 471,364 contacts over 407 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 34063 
+##  scores(3): count balanced ICE 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+

It is possible to plot the different scores of the resulting object to visualize the newly computed scores. In this example, ICE scores should be nearly identical to balanced scores, which were originally imported from the disk-stored contact matrix.

+
+
+
patchwork::wrap_plots(
+    plotMatrix(normalized_hic, use.scores = 'count', caption = FALSE),
+    plotMatrix(normalized_hic, use.scores = 'balanced', caption = FALSE),
+    plotMatrix(normalized_hic, use.scores = 'ICE', caption = FALSE), 
+    nrow = 1
+)
+
+
+

+
+
+
+
+
+

+5.1.2 Computing observed/expected (O/E) map

+

The most prominent feature of a balanced Hi-C matrix is the strong main diagonal. This main diagonal is observed because interactions between immediate adjacent genomic loci are more prone to happen than interactions spanning longer genomic distances. This β€œexpected” behavior is due to the polymer nature of the chromosomes being studied, and can be locally estimated using the distance-dependent interaction frequency (a.k.a. the β€œdistance law”, or P(s)). It can be used to compute an expected matrix on interactions.

+

When it is desirable to β€œmask” this polymer behavior to emphasize topological structures formed by chromosomes, one can divide a given balanced matrix by its expected matrix, i.e. calculate the observed/expected (O/E) map. This is sometimes called β€œdetrending”, as it effectively removes the average polymer behavior from the balanced matrix.

+

The detrend function performs this operation on a given HiCExperiment object. It adds two extra elements in scores list: expected and detrended metrics (while the interactions themselves are unmodified).

+
+
detrended_hic <- detrend(hic)
+detrended_hic
+##  `HiCExperiment` object with 471,364 contacts over 407 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 34063 
+##  scores(4): count balanced expected detrended 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+

Topological features will be visually more prominent in the O/E detrended Hi-C map.

+
+
+
patchwork::wrap_plots(
+    plotMatrix(detrended_hic, use.scores = 'balanced', scale = 'log10', limits = c(-3.5, -1.2), caption = FALSE),
+    plotMatrix(detrended_hic, use.scores = 'expected', scale = 'log10', limits = c(-3.5, -1.2), caption = FALSE),
+    plotMatrix(detrended_hic, use.scores = 'detrended', scale = 'linear', limits = c(-1, 1), cmap = bwrColors(), caption = FALSE), 
+    nrow = 1
+)
+
+
+

+
+
+
+
+
+
+
+
+ +
+
+Scale for detrended scores +
+
+
+
    +
  • +expected scores are in linear scale and Β± in the same amplitude than balanced scores;
  • +
  • +detrended scores are in log2 scale, in general approximately centered around 0. When plotting detrended scores, scale = linear should be set to prevent the default log10 scaling.
  • +
+
+
+

+5.1.3 Computing autocorrelated map

+

Correlation matrices are often calculated from balanced Hi-C matrices. For instance, in genomes composed of eu- and heterochromatin, a correlation matrix can be used to reveal a checkerboard pattern emphasizing the segregation of chromatin into two A/B compartments (Lieberman-Aiden et al. (2009)).

+

The autocorrelate function is used to compute a correlation matrix of a HiCExperiment object. For each pair of interacting loci, the autocorrelated score represents the correlation between their respective interaction profiles with the rest of the genome.

+
+
autocorr_hic <- autocorrelate(hic)
+##  
+autocorr_hic
+##  `HiCExperiment` object with 471,364 contacts over 407 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 34063 
+##  scores(5): count balanced expected detrended autocorrelated 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+

Since these metrics represent correlation scores, they range between -1 and 1. Two loci with an autocorrelated score close to -1 have anti-correlated interaction profiles, while two loci with a autocorrelated score close to 1 are likely to interact with shared targets.

+
+
summary(scores(autocorr_hic, 'autocorrelated'))
+##     Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
+##  -0.4156  0.0025  0.0504  0.0645  0.1036  1.0000     564
+
+

Correlated and anti-correlated loci will be visually represented in the autocorrelated Hi-C map in red and blue pixels, respectively.

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

Here we have illustrated how to compute an autocorrelation matrix from a HiCExperiment object using the example yeast Hi-C experiment. Bear in mind that this is unusual and not very useful, as yeast chromatin is not segregated in two compartments but rather follows a Rabl conformation (Duan et al. (2010)). An example of autocorrelation map from a vertebrate Hi-C experiment (for which chromatin is segregated in A/B compartments) is shown in Chapter 10.

+
+
+
+
plotMatrix(
+    autocorr_hic, 
+    use.scores = 'autocorrelated', 
+    scale = 'linear', 
+    limits = c(-0.4, 0.4), 
+    cmap = bgrColors()
+)
+
+
+

+
+
+
+
+
+
+
+ +
+
+Scale for autocorrelated scores +
+
+
+
    +
  • +autocorrelated scores are in linear scale, in general approximately centered around 0. When plotting autocorrelated scores, scale = linear should be set to prevent the default log10 scaling.
  • +
  • +limits should be manually set to c(-x, x) (0 < x <= 1) to ensure that the color range is effectively centered on 0.
  • +
+
+
+

+5.1.4 Despeckling (smoothing out) a contact map

+

Shallow-sequenced Hi-C libraries or matrices binned with an overly small bin size sometimes produce β€œgrainy” Hi-C maps with noisy backgrounds. A grainy map may also be obtained when dividing two matrices, e.g. when computing the O/E ratio with detrend. This is particularly true for sparser long-range interactions. To overcome such limitations, HiCExperiment objects can be β€œdespeckled” to smooth out focal speckles.

+
+
hic2 <- detrend(hic['II:400000-700000'])
+hic2 <- despeckle(hic2, use.scores = 'detrended', focal.size = 2)
+hic2
+##  `HiCExperiment` object with 168,785 contacts over 150 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:400,000-700,000" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 11325 
+##  scores(5): count balanced expected detrended detrended.despeckled 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+

The added <use.scores>.despeckled scores correspond to scores averaged using a window, whose width is provided with the focal.size argument. This results in a smoother Hi-C heatmap, effectively removing the β€œspeckles” observed at longer range.

+
+
+
library(InteractionSet)
+loops <- system.file('extdata', 'S288C-loops.bedpe', package = 'HiCExperiment') |> 
+    import() |> 
+    makeGInteractionsFromGRangesPairs()
+borders <- system.file('extdata', 'S288C-borders.bed', package = 'HiCExperiment') |> 
+    import()
+patchwork::wrap_plots(
+    plotMatrix(hic2, caption = FALSE),
+    plotMatrix(hic2, use.scores = 'detrended', scale = 'linear', limits = c(-1, 1), caption = FALSE),
+    plotMatrix(
+        hic2, 
+        use.scores = 'detrended.despeckled', 
+        scale = 'linear', 
+        limits = c(-1, 1), 
+        caption = FALSE, 
+        loops = loops, 
+        borders = borders
+    ),
+    nrow = 1
+)
+
+
+

+
+
+
+
+
+
+
+
+ +
+
+Scale for despeckled scores +
+
+
+

despeckled scores are in the same scale than the scores they were computed from.

+
+
+

+5.2 Operations between multiple matrices

+

+5.2.1 Merging maps

+

Hi-C libraries are often sequenced in multiple rounds, for example when high genome coverage is required. This results in multiple contact matrix files being generated. The merge function can be used to bind several HiCExperiment objects into a single one.

+

The different HiCExperiment objects do not need to all have identical regions, as shown in the following example.

+
+
hic_sub1 <- subsetByOverlaps(hic, GRanges("II:100001-200000"))
+hic_sub2 <- subsetByOverlaps(hic, GRanges("II:300001-400000"))
+bound_hic <- merge(hic_sub1, hic_sub2)
+plotMatrix(bound_hic)
+
+
+

+
+
+
+
+

+5.2.2 Computing ratio between two maps

+

Comparing two Hi-C maps can be useful to infer which genomic loci are differentially interacting between experimental conditions. Comparing two HiCExperiment objects can be done in R using the divide function.

+

For example, we can divide the eco1 mutant Hi-C data by wild-type Hi-C dataset using the divide function.

+
+
hic_eco1 <- import(
+    CoolFile(HiContactsData('yeast_eco1', 'mcool')), 
+    focus = 'II', 
+    resolution = 2000
+)
+
+
+
div_contacts <- divide(hic_eco1, by = hic) 
+div_contacts
+##  `HiCExperiment` object with 996,154 contacts over 407 regions 
+##  -------
+##  fileName: N/A 
+##  focus: "II" 
+##  resolutions(1): 2000
+##  active resolution: 2000 
+##  interactions: 60894 
+##  scores(6): count.x balanced.x count.by balanced.by balanced.fc balanced.l2fc 
+##  topologicalFeatures: () 
+##  pairsFile: N/A 
+##  metadata(2): hce_list operation
+
+

We can visually compare wild-type and eco1 maps side by side (left) and their ratio map (right). This highlights the depletion of short-range and increase of long-range interactions in the eco1 dataset.

+
+
cowplot::plot_grid(
+    plotMatrix(hic_eco1, compare.to = hic, limits = c(-4, -1)), 
+    plotMatrix(
+        div_contacts, 
+        use.scores = 'balanced.fc', 
+        scale = 'log2', 
+        limits = c(-1, 1),
+        cmap = bwrColors()
+    )
+)
+
+
+

+
+
+
+
+

References

+ + +
+
+Cournac, A., Marie-Nelly, H., Marbouty, M., Koszul, R., & Mozziconacci, J. (2012). Normalization of a chromosomal contact map. BMC Genomics, 13(1). https://doi.org/10.1186/1471-2164-13-436 +
+
+Duan, Z., Andronescu, M., Schutz, K., McIlwain, S., Kim, Y. J., Lee, C., Shendure, J., Fields, S., Blau, C. A., & Noble, W. S. (2010). A three-dimensional model of the yeast genome. Nature, 465(7296), 363–367. https://doi.org/10.1038/nature08973 +
+
+Imakaev, M., Fudenberg, G., McCord, R. P., Naumova, N., Goloborodko, A., Lajoie, B. R., Dekker, J., & Mirny, L. A. (2012). Iterative correction of hi-c data reveals hallmarks of chromosome organization. Nature Methods, 9(10), 999–1003. https://doi.org/10.1038/nmeth.2148 +
+
+Lieberman-Aiden, E., Berkum, N. L. van, Williams, L., Imakaev, M., Ragoczy, T., Telling, A., Amit, I., Lajoie, B. R., Sabo, P. J., Dorschner, M. O., Sandstrom, R., Bernstein, B., Bender, M. A., Groudine, M., Gnirke, A., Stamatoyannopoulos, J., Mirny, L. A., Lander, E. S., & Dekker, J. (2009). Comprehensive mapping of long-range interactions reveals folding principles of the human genome. Science, 326(5950), 289–293. https://doi.org/10.1126/science.1181369 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-10-1.png b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 0000000..c4bf5d0 Binary files /dev/null and b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-12-1.png b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-12-1.png new file mode 100644 index 0000000..8a1f05b Binary files /dev/null and b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-12-1.png differ diff --git a/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-13-1.png b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 0000000..74ae516 Binary files /dev/null and b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-16-1.png b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 0000000..6bbe0fe Binary files /dev/null and b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-5-1.png b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-5-1.png new file mode 100644 index 0000000..6e55060 Binary files /dev/null and b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-5-1.png differ diff --git a/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-7-1.png b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 0000000..e88f9ab Binary files /dev/null and b/docs/devel/pages/matrix-centric_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/docs/devel/pages/parsing.html b/docs/devel/pages/parsing.html new file mode 100644 index 0000000..bd032ab --- /dev/null +++ b/docs/devel/pages/parsing.html @@ -0,0 +1,1471 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 3  Manipulating Hi-C data in R + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+3  Manipulating Hi-C data in R +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter focuses on:

+
    +
  • Modifying information associated with an existing HiCExperiment object
  • +
  • Subsetting a HiCExperiment object
  • +
  • Coercing a HiCExperiment object in a base data structure
  • +
+
+
+
+
+
+ +
+
+Important reminder +
+
+
+
    +
  • An HiCExperiment object allows random access parsing of a disk-stored contact matrix.
  • +
  • An HiCExperiment object operates by wrapping together (1) a ContactFile (i.e. a connection to a disk-stored data file) and (2) a GInteractions generated by parsing the data file.
  • +
+
+
+
+ +
+
+
    +
  • Creating a connection to a disk-stored contact matrix:
  • +
+
+
# coolf <- "<path-to-disk-stored-contact-matrix.cool>"
+coolf <- HiContactsData('yeast_wt', 'mcool')
+cf <- CoolFile(coolf)
+availableResolutions(cf)
+
+availableChromosomes(cf)
+
+
    +
  • Importing a contact matrix over a specific genomic location, at a given resolution:
  • +
+
+
hic <- import(cf, focus = 'II:10000-50000', resolution = 4000)
+hic
+##  `HiCExperiment` object with 10,801 contacts over 11 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:10,000-50,000" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 4000 
+##  interactions: 45 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Recovering genomic interactions stored in a HiCExperiment:
  • +
+
+
interactions(hic)
+##  GInteractions object with 45 interactions and 4 metadata columns:
+##         seqnames1     ranges1     seqnames2     ranges2 |   bin_id1   bin_id2
+##             <Rle>   <IRanges>         <Rle>   <IRanges> | <numeric> <numeric>
+##     [1]        II 12001-16000 ---        II 12001-16000 |        61        61
+##     [2]        II 12001-16000 ---        II 16001-20000 |        61        62
+##     [3]        II 12001-16000 ---        II 20001-24000 |        61        63
+##     [4]        II 12001-16000 ---        II 24001-28000 |        61        64
+##     [5]        II 12001-16000 ---        II 28001-32000 |        61        65
+##     ...       ...         ... ...       ...         ... .       ...       ...
+##    [41]        II 36001-40000 ---        II 40001-44000 |        67        68
+##    [42]        II 36001-40000 ---        II 44001-48000 |        67        69
+##    [43]        II 40001-44000 ---        II 40001-44000 |        68        68
+##    [44]        II 40001-44000 ---        II 44001-48000 |        68        69
+##    [45]        II 44001-48000 ---        II 44001-48000 |        69        69
+##             count  balanced
+##         <numeric> <numeric>
+##     [1]       213  0.249303
+##     [2]       673  0.449271
+##     [3]       325  0.210001
+##     [4]       137  0.125732
+##     [5]        77  0.106917
+##     ...       ...       ...
+##    [41]       941  0.358860
+##    [42]       275  0.114972
+##    [43]       675  0.253868
+##    [44]       497  0.204920
+##    [45]       295  0.133344
+##    -------
+##    regions: 11 ranges and 4 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome
+
+
+
+
+
+ +
+
+

To demonstrate how to manipulate a HiCExperiment object, we will create an HiCExperiment object from an example .cool file provided in the HiContactsData package.

+
+
library(HiCExperiment)
+library(HiContactsData)
+
+# ---- This downloads an example `.mcool` file and caches it locally 
+coolf <- HiContactsData('yeast_wt', 'mcool')
+##  see ?HiContactsData and browseVignettes('HiContactsData') for documentation
+##  loading from cache
+
+# ---- This creates a connection to the disk-stored `.mcool` file
+cf <- CoolFile(coolf)
+cf
+##  CoolFile object
+##  .mcool file: /root/.cache/R/ExperimentHub/1701a09a86_7752 
+##  resolution: 1000 
+##  pairs file: 
+##  metadata(0):
+
+# ---- This imports contacts from the long arm of chromosome `II`, at resolution `2000`
+hic <- import(cf, focus = 'II:300001-813184', resolution = 2000)
+hic
+##  `HiCExperiment` object with 306,212 contacts over 257 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300,001-813,184" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 18513 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
+
+
+

+3.1 Subsetting a contact matrix

+

Two entirely different approaches are possible to subset of a Hi-C contact matrix:

+
    +
  • Subsetting before importing: leveraging random access to a disk-stored contact matrix to only import interactions overlapping with a genomic locus of interest.

  • +
  • Subsetting after importing: parsing the entire contact matrix in memory, and subsequently subset interactions overlapping with a genomic locus of interest.

  • +
+

+

+3.1.1 Subsetting before import: with focus +

+

Specifying a focus when importing a dataset in R (i.e. "Subset first, then parse") is generally the recommended approach to import Hi-C data in R.

+

The focus argument can be set when importing a ContactFile in R, as follows:

+
+
import(cf, focus = "...")
+
+

This ensures that only the needed data is parsed in R, reducing memory load and accelerating the import. Thus, this should be the preferred way of parsing HiCExperiment data, as disk-stored contact matrices allow efficient random access to indexed data.

+

focus can be any of the following string types:

+
+
#   "II"                                  --> import contacts over an entire chromosome
+#   "II:300001-800000"                    --> import on-diagonal contacts within a chromosome
+#   "II:300001-400000|II:600001-700000"   --> import off-diagonal contacts within a chromosome
+#   "II|III"                              --> import contacts between two chromosomes
+#   "II:300001-800000|V:1-500000"         --> import contacts between segments of two chromosomes
+
+
+ +
+
+
    +
  • Subsetting to a specific on-diagonal genomic location using standard UCSC coordinates query:
  • +
+
+
import(cf, focus = 'II:300001-800000', resolution = 2000)
+##  `HiCExperiment` object with 301,018 contacts over 250 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300,001-800,000" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 17974 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting to a specific off-diagonal genomic location using pairs of coordinates query:
  • +
+
+
import(cf, focus = 'II:300001-400000|II:600001-700000', resolution = 2000)
+##  `HiCExperiment` object with 402 contacts over 100 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300001-400000|II:600001-700000" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 357 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting interactions to retain those constrained within a single chromosome:
  • +
+
+
import(cf, focus = 'II', resolution = 2000)
+##  `HiCExperiment` object with 471,364 contacts over 407 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 34063 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting interactions to retain those between two chromosomes:
  • +
+
+
import(cf, focus = 'II|III', resolution = 2000)
+##  `HiCExperiment` object with 9,092 contacts over 566 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II|III" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 7438 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting interactions to retain those between parts of two chromosomes:
  • +
+
+
import(cf, focus = 'II:300001-800000|V:1-500000', resolution = 2000)
+##  `HiCExperiment` object with 7,147 contacts over 500 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300001-800000|V:1-500000" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 6523 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
+
+
+ +

+3.1.2 Subsetting after import

+

It may sometimes be desirable to import a full dataset from disk first, and only then perform in-memory subsetting of the HiCExperiment object (i.e. "Parse first, then subset"). This is for example necessary when the end user aims to investigate subsets of interactions across a large number of different areas of a contact matrix.

+

Several strategies are possible to allow subsetting of imported data, either with subsetByOverlaps or [.

+

+3.1.2.1 subsetByOverlaps(<HiCExperiment>, <GRanges>) +

+

subsetByOverlaps can take a HiCExperiment as a query and a GRanges as a query. In this case, the GRanges is used to extract a subset of a HiCExperiment constrained within a specific genomic location.

+
+
telomere <- GRanges("II:700001-813184")
+subsetByOverlaps(hic, telomere) |> interactions()
+##  GInteractions object with 1540 interactions and 4 metadata columns:
+##           seqnames1       ranges1     seqnames2       ranges2 |   bin_id1
+##               <Rle>     <IRanges>         <Rle>     <IRanges> | <numeric>
+##       [1]        II 700001-702000 ---        II 700001-702000 |       466
+##       [2]        II 700001-702000 ---        II 702001-704000 |       466
+##       [3]        II 700001-702000 ---        II 704001-706000 |       466
+##       [4]        II 700001-702000 ---        II 706001-708000 |       466
+##       [5]        II 700001-702000 ---        II 708001-710000 |       466
+##       ...       ...           ... ...       ...           ... .       ...
+##    [1536]        II 804001-806000 ---        II 810001-812000 |       518
+##    [1537]        II 806001-808000 ---        II 806001-808000 |       519
+##    [1538]        II 806001-808000 ---        II 808001-810000 |       519
+##    [1539]        II 806001-808000 ---        II 810001-812000 |       519
+##    [1540]        II 808001-810000 ---        II 808001-810000 |       520
+##             bin_id2     count  balanced
+##           <numeric> <numeric> <numeric>
+##       [1]       466        30 0.0283618
+##       [2]       467       145 0.0709380
+##       [3]       468       124 0.0704979
+##       [4]       469        59 0.0510221
+##       [5]       470        59 0.0384004
+##       ...       ...       ...       ...
+##    [1536]       521         1       NaN
+##    [1537]       519        15 0.0560633
+##    [1538]       520        25       NaN
+##    [1539]       521         1       NaN
+##    [1540]       520        10       NaN
+##    -------
+##    regions: 57 ranges and 4 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome
+
+

By default, subsetByOverlaps(hic, telomere) will only recover interactions constrained within telomere, i.e. interactions for which both ends are in telomere.

+

Alternatively, type = "any" can be specified to get all interactions with at least one of their anchors within telomere.

+
+
subsetByOverlaps(hic, telomere, type = "any") |> interactions()
+##  GInteractions object with 6041 interactions and 4 metadata columns:
+##           seqnames1       ranges1     seqnames2       ranges2 |   bin_id1
+##               <Rle>     <IRanges>         <Rle>     <IRanges> | <numeric>
+##       [1]        II 300001-302000 ---        II 702001-704000 |       266
+##       [2]        II 300001-302000 ---        II 704001-706000 |       266
+##       [3]        II 300001-302000 ---        II 768001-770000 |       266
+##       [4]        II 300001-302000 ---        II 784001-786000 |       266
+##       [5]        II 302001-304000 ---        II 740001-742000 |       267
+##       ...       ...           ... ...       ...           ... .       ...
+##    [6037]        II 804001-806000 ---        II 810001-812000 |       518
+##    [6038]        II 806001-808000 ---        II 806001-808000 |       519
+##    [6039]        II 806001-808000 ---        II 808001-810000 |       519
+##    [6040]        II 806001-808000 ---        II 810001-812000 |       519
+##    [6041]        II 808001-810000 ---        II 808001-810000 |       520
+##             bin_id2     count    balanced
+##           <numeric> <numeric>   <numeric>
+##       [1]       467         1 0.000590999
+##       [2]       468         1 0.000686799
+##       [3]       500         1 0.000728215
+##       [4]       508         1 0.000923092
+##       [5]       486         1 0.000382222
+##       ...       ...       ...         ...
+##    [6037]       521         1         NaN
+##    [6038]       519        15   0.0560633
+##    [6039]       520        25         NaN
+##    [6040]       521         1         NaN
+##    [6041]       520        10         NaN
+##    -------
+##    regions: 257 ranges and 4 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome
+
+

+3.1.2.2 <HiCExperiment>["..."] +

+

The square bracket operator [ allows for more advanced textual queries, similarly to focus arguments that can be used when importing contact matrices in memory.

+

This ensures that only the needed data is parsed in R, reducing memory load and accelerating the import. Thus, this should be the preferred way of parsing HiCExperiment data, as disk-stored contact matrices allow efficient random access to indexed data.

+

The following string types can be used to subset a HiCExperiment object with the [ notation:

+
+
#   "II"                                  --> import contacts over an entire chromosome
+#   "II:300001-800000"                    --> import on-diagonal contacts within a chromosome
+#   "II:300001-400000|II:600001-700000"   --> import off-diagonal contacts within a chromosome
+#   "II|III"                              --> import contacts between two chromosomes
+#   "II:300001-800000|V:1-500000"         --> import contacts between segments of two chromosomes
+#   c("II", "III", "IV")                  --> import contacts within and between several chromosomes
+
+
+ +
+
+
    +
  • Subsetting to a specific on-diagonal genomic location using standard UCSC coordinates query:
  • +
+
+
hic["II:800001-813184"]
+##  `HiCExperiment` object with 1,040 contacts over 6 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:800,001-813,184" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 19 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting to a specific off-diagonal genomic location using pairs of coordinates query:
  • +
+
+
hic["II:300001-320000|II:800001-813184"]
+##  `HiCExperiment` object with 3 contacts over 6 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300001-320000|II:800001-813184" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 3 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting interactions to retain those constrained within a single chromosome:
  • +
+
+
hic["II"]
+##  `HiCExperiment` object with 306,212 contacts over 257 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 18513 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting interactions to retain those between two chromosomes:
  • +
+
+
hic["II|IV"]
+##  `HiCExperiment` object with 0 contacts over 0 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:1-813184|IV:1-1531933" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 0 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting interactions to retain those between segments of two chromosomes:
  • +
+
+
hic["II:300001-320000|IV:1-100000"]
+##  `HiCExperiment` object with 0 contacts over 0 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300001-320000|IV:1-100000" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 0 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
    +
  • Subsetting interactions to retain those constrained within several chromosomes:
  • +
+
+
hic[c('II', 'III', 'IV')]
+##  `HiCExperiment` object with 306,212 contacts over 257 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II, III, IV" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 18513 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+

Some notes:

+
    +
  • This last example (subsetting for a vector of several chromosomes) is the only scenario for which [-based in-memory subsetting of pre-imported data is the only way to go, as such subsetting is not possible with focus from disk-stored data.
  • +
  • All the other [ subsetting scenarii illustrated above can be achieved more efficiently using the focus argument when importing data into a HiCExperiment object.
  • +
  • However, keep in mind that subsetting preserves extra data, e.g. added scores, topologicalFeatures, metadata or pairsFile, whereas this information is lost using focus with import.
  • +
+
+
+
+

+3.1.3 Zooming on a HiCExperiment +

+

β€œZooming” refers to dynamically changing the resolution of a HiCExperiment. By zooming a HiCExperiment, one can refine or coarsen the contact matrix. This operation takes aContactFile and focus from an existing HiCExperiment input and re-generates a new HiCExperiment with updated resolution, interactions and scores. Note that zoom will preserve existing metadata, topologicalFeatures and pairsFile information.

+
+
hic
+##  `HiCExperiment` object with 306,212 contacts over 257 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300,001-813,184" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 18513 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+zoom(hic, 4000)
+##  `HiCExperiment` object with 306,212 contacts over 129 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300,001-813,184" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 4000 
+##  interactions: 6800 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+zoom(hic, 1000)
+##  `HiCExperiment` object with 306,212 contacts over 514 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300,001-813,184" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 1000 
+##  interactions: 44363 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
+
+
+ +
+
+Note +
+
+
+

The sum of raw counts do not change after zooming, however the number of individual interactions and regions changes.

+
+
length(hic)
+##  [1] 18513
+length(zoom(hic, 1000))
+##  [1] 44363
+length(zoom(hic, 4000))
+##  [1] 6800
+sum(scores(hic, "count"))
+##  [1] 306212
+sum(scores(zoom(hic, 1000), "count"))
+##  [1] 306212
+sum(scores(zoom(hic, 4000), "count"))
+##  [1] 306212
+
+
+
+
+
+
+ +
+
+Important +
+
+
+
    +
  • +zoom does not change the focus! It only affects the resolution (and consequently, the interactions).
  • +
  • +zoom will only work for multi-resolution contact matrices, e.g. .mcool or .hic.
  • +
+
+
+

+3.2 Updating an HiCExperiment object

+
+
+
+ +
+
+TL;DR: Which HiCExperiment slots are mutable (βœ…) / immutable (⛔️)? +
+
+
+
    +
  • +fileName(hic): ⛔️ (obtained from disk-stored file)
  • +
  • +focus(hic): πŸ€” (see subsetting section)
  • +
  • +resolutions(hic): ⛔️ (obtained from disk-stored file)
  • +
  • +resolution(hic): πŸ€” (see zooming section)
  • +
  • +interactions(hic): ⛔️ (obtained from disk-stored file)
  • +
  • +scores(hic): βœ…
  • +
  • +topologicalFeatures(hic): βœ…
  • +
  • +pairsFile(hic): βœ…
  • +
  • +metadata(hic): βœ…
  • +
+
+
+

+3.2.1 Immutable slots

+

An HiCExperiment object acts as an interface exposing disk-stored data. This implies that the fileName slot itself is immutable (i.e. cannot be changed). This should be obvious, as a HiCExperiment has to be associated with a disk-stored contact matrix to properly function (except in some advanced cases developed in next chapters).

+

For this reason, methods to manually modify interactions and resolutions slots are also not exposed in the HiCExperiment package.

+

A corollary of this is that the associated regions and anchors of an HiCExperiment should not be modified by hand either, since they are directly linked to interactions.

+

+3.2.2 Mutable slots

+

That being said, HiCExperiment objects are flexible and can be partially modified in memory without having to change/overwrite the original, disk-stored contact matrix.

+

Several slots can be modified in memory: slots, topologicalFeatures, pairsFile and metadata.

+

+3.2.2.1 scores +

+

We have seen in the previous chapter that scores are stored in a list and are available using the scores function.

+
+
scores(hic)
+##  List of length 2
+##  names(2): count balanced
+
+head(scores(hic, "count"))
+##  [1]  7 92 75 61 38 43
+
+head(scores(hic, "balanced"))
+##  [1] 0.009657438 0.076622340 0.054101992 0.042940512 0.040905212 0.029293930
+
+

Extra scores can be added to this list, e.g. to describe the β€œexpected” interaction frequency for each interaction stored in the HiCExperiment object). This can be achieved using the scores()<- function.

+
+
scores(hic, "random") <- runif(length(hic))
+
+scores(hic)
+##  List of length 3
+##  names(3): count balanced random
+
+head(scores(hic, "random"))
+##  [1] 0.54008758 0.94741632 0.58497023 0.01735713 0.86688684 0.10343547
+
+

+3.2.2.2 topologicalFeatures +

+

The end-user can create additional topologicalFeatures or modify the existing ones using the topologicalFeatures()<- function.

+
+
topologicalFeatures(hic, 'CTCF') <- GRanges(c(
+    "II:340-352", 
+    "II:3520-3532", 
+    "II:7980-7992", 
+    "II:9240-9252" 
+))
+topologicalFeatures(hic, 'CTCF')
+##  GRanges object with 4 ranges and 0 metadata columns:
+##        seqnames    ranges strand
+##           <Rle> <IRanges>  <Rle>
+##    [1]       II   340-352      *
+##    [2]       II 3520-3532      *
+##    [3]       II 7980-7992      *
+##    [4]       II 9240-9252      *
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+topologicalFeatures(hic, 'loops') <- GInteractions(
+    topologicalFeatures(hic, 'CTCF')[rep(1:3, each = 3)],
+    topologicalFeatures(hic, 'CTCF')[rep(1:3, 3)]
+)
+topologicalFeatures(hic, 'loops')
+##  GInteractions object with 9 interactions and 0 metadata columns:
+##        seqnames1   ranges1     seqnames2   ranges2
+##            <Rle> <IRanges>         <Rle> <IRanges>
+##    [1]        II   340-352 ---        II   340-352
+##    [2]        II   340-352 ---        II 3520-3532
+##    [3]        II   340-352 ---        II 7980-7992
+##    [4]        II 3520-3532 ---        II   340-352
+##    [5]        II 3520-3532 ---        II 3520-3532
+##    [6]        II 3520-3532 ---        II 7980-7992
+##    [7]        II 7980-7992 ---        II   340-352
+##    [8]        II 7980-7992 ---        II 3520-3532
+##    [9]        II 7980-7992 ---        II 7980-7992
+##    -------
+##    regions: 3 ranges and 0 metadata columns
+##    seqinfo: 1 sequence from an unspecified genome; no seqlengths
+
+hic
+##  `HiCExperiment` object with 306,212 contacts over 257 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300,001-813,184" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 18513 
+##  scores(3): count balanced random 
+##  topologicalFeatures: compartments(0) borders(0) loops(9) viewpoints(0) CTCF(4) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+

All these objects can be used in *Overlap methods, as they all extend the GRanges class of objects.

+
+
# ---- This counts the number of times `CTCF` anchors are being used in the 
+#      `loops` `GInteractions` object
+countOverlaps(
+    query = topologicalFeatures(hic, 'CTCF'), 
+    subject = topologicalFeatures(hic, 'loops')
+)
+##  [1] 5 5 5 0
+
+

+3.2.2.3 pairsFile +

+

If pairsFile is not specified when importing the ContactFile into a HiCExperiment object, one can add it later.

+
+
pairsf <- HiContactsData('yeast_wt', 'pairs.gz')
+
+
+
pairsFile(hic) <- pairsf
+hic
+##  `HiCExperiment` object with 306,212 contacts over 257 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "II:300,001-813,184" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 18513 
+##  scores(3): count balanced random 
+##  topologicalFeatures: compartments(0) borders(0) loops(9) viewpoints(0) CTCF(4) 
+##  pairsFile: /root/.cache/R/ExperimentHub/1702dcdfa3b_7753 
+##  metadata(0):
+
+

+3.2.2.4 metadata +

+

Metadata associated with a HiCExperiment can be updated at any point.

+
+
metadata(hic) <- list(
+    info = "HiCExperiment created from an example .mcool file from `HiContactsData`", 
+    date = date()
+)
+metadata(hic)
+##  $info
+##  [1] "HiCExperiment created from an example .mcool file from `HiContactsData`"
+##  
+##  $date
+##  [1] "Tue Nov  7 12:45:27 2023"
+
+

+3.3 Coercing HiCExperiment objects

+

Convenient coercing functions exist to transform data stored as a HiCExperiment into another class.

+
    +
  • +as.matrix(): allows to coerce the HiCExperiment into a sparse or dense matrix (using the sparse logical argument, TRUE by default) and choosing specific scores of interest (using the use.scores argument, "balanced" by default).
  • +
+
+
# ----- `as.matrix` coerces a `HiCExperiment` into a `sparseMatrix` by default 
+as.matrix(hic) |> class()
+##  [1] "dgTMatrix"
+##  attr(,"package")
+##  [1] "Matrix"
+
+as.matrix(hic) |> dim()
+##  [1] 257 257
+
+# ----- One can specify which scores should be used when coercing into a matrix
+as.matrix(hic, use.scores = "balanced")[1:5, 1:5]
+##  5 x 5 sparse Matrix of class "dgTMatrix"
+##                                                              
+##  [1,] 0.009657438 0.07662234 0.05410199 0.04294051 0.04090521
+##  [2,] 0.076622340 0.05128277 0.09841564 0.06926737 0.05263611
+##  [3,] 0.054101992 0.09841564 0.05657589 0.08723160 0.07316890
+##  [4,] 0.042940512 0.06926737 0.08723160 0.03699543 0.08403496
+##  [5,] 0.040905212 0.05263611 0.07316890 0.08403496 0.04787415
+
+as.matrix(hic, use.scores = "count")[1:5, 1:5]
+##  5 x 5 sparse Matrix of class "dgTMatrix"
+##                         
+##  [1,]  7  92  75  61  38
+##  [2,] 92 102 226 163  81
+##  [3,] 75 226 150 237 130
+##  [4,] 61 163 237 103 153
+##  [5,] 38  81 130 153  57
+
+# ----- If **expressly required**, one can coerce a HiCExperiment into a dense matrix
+as.matrix(hic, use.scores = "count", sparse = FALSE)[1:5, 1:5]
+##       [,1] [,2] [,3] [,4] [,5]
+##  [1,]    7   92   75   61   38
+##  [2,]   92  102  226  163   81
+##  [3,]   75  226  150  237  130
+##  [4,]   61  163  237  103  153
+##  [5,]   38   81  130  153   57
+
+
    +
  • +as.data.frame(): simply coercing interactions into a rectangular data frame
  • +
+
+
as.data.frame(hic) |> head()
+##    seqnames1 start1   end1 width1 strand1 bin_id1    weight1 center1
+##  1        II 300001 302000   2000       *     266 0.03714342  301000
+##  2        II 300001 302000   2000       *     266 0.03714342  301000
+##  3        II 300001 302000   2000       *     266 0.03714342  301000
+##  4        II 300001 302000   2000       *     266 0.03714342  301000
+##  5        II 300001 302000   2000       *     266 0.03714342  301000
+##  6        II 300001 302000   2000       *     266 0.03714342  301000
+##    seqnames2 start2   end2 width2 strand2 bin_id2    weight2 center2 count
+##  1        II 300001 302000   2000       *     266 0.03714342  301000     7
+##  2        II 302001 304000   2000       *     267 0.02242258  303000    92
+##  3        II 304001 306000   2000       *     268 0.01942093  305000    75
+##  4        II 306001 308000   2000       *     269 0.01895202  307000    61
+##  5        II 308001 310000   2000       *     270 0.02898098  309000    38
+##  6        II 310001 312000   2000       *     271 0.01834118  311000    43
+##       balanced     random
+##  1 0.009657438 0.54008758
+##  2 0.076622340 0.94741632
+##  3 0.054101992 0.58497023
+##  4 0.042940512 0.01735713
+##  5 0.040905212 0.86688684
+##  6 0.029293930 0.10343547
+
+
+
+
+ +
+
+Warning +
+
+
+

These coercing methods only operate on interactions and scores, and discard all other information, e.g. regarding genomic regions, available resolutions, associated metadata, pairsFile or topologicalFeatures.

+
+
+

References

+ + +
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/preamble.html b/docs/devel/pages/preamble.html new file mode 100644 index 0000000..cdeef09 --- /dev/null +++ b/docs/devel/pages/preamble.html @@ -0,0 +1,636 @@ + + + + + + + + + +Orchestrating Hi-C analysis with Bioconductor - Preamble + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Preamble

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

Hi-C is an experimental method to quantify spatial interactions between any pair of genomic loci. While a number of command-line interfaces (CLI) exist to process and manipulate Hi-C data (e.g. cooler (Abdennur & Mirny (2019)), juicer (Durand et al. (2016)) and HiC-Pro (Servant et al. (2015))), they generally suffer from several limitations often found in emerging genomics techniques:

+ +

In this book, we provide an overview of a set of tools that enable processing, visualization and in-depth investigation of Hi-C data in R, ensuring intuitive integration of Hi-C data in the existing Bioconductor ecosystem. We introduce a high-level HiCExperiment data structure to represent Hi-C data, directly extending robust, pre-existing core genomic classes offered by Bioconductor. This guarantees a stable and intuitive Hi-C data representation in R as a genomic entity, which is highly interoperable and can be used by all existing analysis packages in R.

+

+

On top of the HiCExperiment data structure, the HiContacts package offers extended functionalities to perform matrix-centric and interaction-centric analysis directly on HiCExperiment objects and provides powerful visualization tools specifically designed for Hi-C data to facilitate exploratory data analysis. In addition, the HiCool package implements a processing workflow based on a lightweight library to process raw Hi-C data into binned Hi-C contact matrices ready to be imported as HiCExperiment objects. Finally, the fourDNData and DNAZooData packages offer a gateway to major public data repositories directly in R.

+

+
+

Package status

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Github repo πŸ’ΎDoc πŸ“˜Github checks βœ…Bioc builds πŸ—Lifecycle 🌱
HiCExperimentDocrworkflowsBioc release:
Release
Bioc devel:
Devel
HiContactsDocrworkflowsBioc release:
Release
Bioc devel:
Devel
HiCoolDocrworkflowsBioc release:
Release
Bioc devel:
Devel
HiContactsDataDocR-CMD-check-biocBioc release:
Release
Bioc devel:
Devel
DNAZooDataDocrworkflowsBioc release:
Release
Bioc devel:
Devel
fourDNDataDocrworkflowsBioc release:
Release
Bioc devel:
Devel
+
+
+

References

+ + +
+
+Abdennur, N., & Mirny, L. A. (2019). Cooler: Scalable storage for hi-c data and other genomically labeled arrays. Bioinformatics, 36(1), 311–316. https://doi.org/10.1093/bioinformatics/btz540 +
+
+Durand, N. C., Shamim, M. S., Machol, I., Rao, S. S. P., Huntley, M. H., Lander, E. S., & Aiden, E. L. (2016). Juicer provides a one-click system for analyzing loop-resolution hi-c experiments. Cell Systems, 3(1), 95–98. https://doi.org/10.1016/j.cels.2016.07.002 +
+
+Servant, N., Varoquaux, N., Lajoie, B. R., Viara, E., Chen, C.-J., Vert, J.-P., Heard, E., Dekker, J., & Barillot, E. (2015). HiC-pro: An optimized and flexible pipeline for hi-c data processing. Genome Biology, 16(1). https://doi.org/10.1186/s13059-015-0831-x +
+
+
+ + Back to top
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/devel/pages/principles.html b/docs/devel/pages/principles.html new file mode 100644 index 0000000..d42296d --- /dev/null +++ b/docs/devel/pages/principles.html @@ -0,0 +1,1040 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 1  Hi-C pre-processing steps + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+1  Hi-C pre-processing steps +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter introduces the reader to general Hi-C experimental and computational steps to perform the pre-processing of Hi-C. This encompasses read alignment, pairs generation and filtering and pairs binning into a contact matrix file.

+
+
+

+1.1 Experimental considerations

+

+1.1.1 Experimental approach

+

The Hi-C procedure (Lieberman-Aiden et al. (2009)) stems from the clever combination of high-throughput sequencing and Chromatin Conformation Capture (3C) experimental approach (Dekker et al. (2002)).
+In Hi-C, chromatin is crosslinked within intact nuclei and enzymatically digested (usually with one or several restriction enzymes, but Hi-C variants using MNase or DNase exist). End-repair introduces biotinylated dNTPs and is followed by religation, which generates chimeric DNA fragments consisting of genomic loci originally lying in spatial proximity, usually crosslinked to a shared protein complex. After religation, DNA fragments are sheared, biotin-containing fragments are pulled-down and converted into a sequencing library.

+

+

+1.1.2 C variants

+

A number of C variants have been proposed since the publication of the original 3C method (reviewed by Davies et al. (2017)), the main ones being Capture-C and ChIA-PET (see procedure below).

+

+

Capture-C is useful to quantify interactions between a set of regulatory elements of interest. ChIA-PET, on the other hand, can identify interactions mediated by a specific protein of interest. Finally, an increasing number of Hi-C approaches rely on long-read sequencing (e.g. Deshpande et al. (2022), Tavares-Cadete et al. (2020)) to identify clusters of 3D contacts.

+

+1.1.3 Sequencing

+

Hi-C libraries are traditionally sequenced with short-read technology, and are by essence paired-end libraries. For this reason, the end result of the experimental side of the Hi-C consists of two fastq files, each one containing sequences for one extremity of the DNA fragments purified during Hi-C. These are the two files we need to move on to the computational side of Hi-C.

+

Fastq files are plain text files (usually compressed, with the .gz extension). They are generated by the sequencing machine during a sequencing run, and for Hi-C, necessarily come in pairs, generally called *_R1.fq.gz and *_R2.fq.gz.

+

Here is the first read listed in sample_R1.fq.gz file:

+
+
+
sample-R1.fq.gz
+
+
@SRR5399542.1.1 DH1DQQN1:393:H9GEWADXX:1:1101:1187:2211 length=24
+CAACTTCAATACCAGCAGCAGCAA
++
+CCCFFFFFHHHHHJJJJJIJJJJJ
+
+

And here is the first read listed in sample_R2.fq.gz file:

+
+
+
sample-R2.fq.gz
+
+
@SRR5399542.1.1 DH1DQQN1:393:H9GEWADXX:1:1101:1187:2211 length=24
+GCTGTTGTTGTTGTTGTATTTGCA
++
+@@@FFFFFFHHHHIJJIJJHIIEH
+
+

These two reads are the first listed in their respective file. Notice how they bear the same name (first line): they form a pair. The second line corresponds to the sequence read by the sequencer, the third line is a single + separator, and the last line indicates the per-base sequencing quality following a nebulous cypher.

+

+1.2 Hi-C file formats

+

Two important output files are typically generated during Hi-C data pre-processing:

+
    +
  • A β€œpairs” file;
  • +
  • A binned β€œcontact matrix” file
  • +
+

We will now describe the structure of these different types of files. Directly jump to the next chapter if you want to know more about importing data from a contact matrix or a pairs file in R.

+

+1.2.1 Pairs files

+

A β€œpairs” file (optionally, but generally filtered and sorted) is the direct output of processing Hi-C fastq files. It stores information about putative proximity contacts identified by digestion/religation, in the lossless, human-readable, indexable format: the .pairs format.

+

A .pairs file is organized in a header followed by a body:

+
    +
  • +header: starts with # +
      +
    • Required entries +
        +
      • First line: ## pairs format v1.0 +
      • +
      • +#columns: column contents and ordering (e.g. #columns: readID chr1 pos1 chr2 pos2 strand1 strand2 <column_name> <column_name> ...)
      • +
      • +#chromsize: chromosome names and their size in bp, one chromosome per line, in the same order that defines ordering between mates (e.g. #chromsize: chr1 230218). Chromosome order is actually defined by this header, not by the order of pairs listed in the body!
      • +
      +
    • +
    • Optional entries with reserved header keys (sorted, shape, command, genome_assembly) +
        +
      • +#sorted: to indicate the sorting mechanism (e.g. #sorted: chr1-chr2-pos1-pos2, #sorted: chr1-pos1, #sorted: none)
      • +
      • +#shape: to specify whether the matrix is stored as upper triangle or lower triangle (#shape: upper triangle, #shape: lower triangle)
      • +
      • +#command: to specify any command, e.g. the command used to generate the pairs file (#command: bam2pairs mysample.bam mysample)
      • +
      • +#genome_assembly: to specify the genome assembly (e.g. #genome_assembly: hg38)
      • +
      +
    • +
    +
  • +
  • +body: tab-separated columns +
      +
    • 7 reserved (4 of them required) columns: +
        +
      • readID, chr1, pos1, chr2, pos2, strand1, strand2
      • +
      • Columns 2-5 (chr1, pos1, chr2, pos2) are required and cannot have missing values
      • +
      • For column 1, 6 & 7: missing values are annotated with a single-character dummy (.)
      • +
      +
    • +
    • 2 extra reserved, optional column names: +
        +
      • +frag1, frag2: restriction enzyme fragment index used by Juicer +
      • +
      +
    • +
    • Any number of optional columns can be added
    • +
    +
  • +
+
+
+
sample.pairs
+
+
## pairs format v1.0
+#sorted: chr1-chr2-pos1-pos2
+#shape: upper triangle
+#genome_assembly: hg38
+#chromsize: chr1 249250621
+#chromsize: chr2 243199373
+#chromsize: chr3 198022430
+...
+#columns: readID chr1 pos1 chr2 pos2 strand1 strand2
+EAS139:136:FC706VJ:2:2104:23462:197393 chr1 10000 chr1 20000 + +
+EAS139:136:FC706VJ:2:8762:23765:128766 chr1 50000 chr1 70000 + +
+EAS139:136:FC706VJ:2:2342:15343:9863 chr1 60000 chr2 10000 + +
+EAS139:136:FC706VJ:2:1286:25:275154 chr1 30000 chr3 40000 + -
+
+

More information about the conventions related to this text file are provided by the 4DN consortium, which originally formalized the specifications of this file format.

+

+1.2.2 Binned contact matrix files

+

+1.2.2.1 Binning pairs into a matrix

+

The action of β€œbinning” a .pairs file into a contact matrix consists in (1) discretizing a genome reference into genomic bins, (2) attributing bins for each pair’s extremity and (3) computing the interaction frequency between any pair of genomic bins, i.e. the β€œcontact matrix”.

+

For instance, here is a dummy .pairs file with a total of 5 pairs:

+
+
+
dummy.pairs
+
+
## pairs format v1.0
+#sorted: chr1-chr2-pos1-pos2
+#columns: readID chr1 pos1 chr2 pos2 strand1 strand2
+#chromsize: chr1 389
+. chr1 162 chr1 172 . . 
+. chr1 180 chr1 192 . . 
+. chr1 183 chr1 254 . .
+. chr1 221 chr1 273 . . 
+. chr1 254 chr1 298 . . 
+
+

Note that this genome reference is made of a single chromosome (chr1), very short (length of 389). By binning this chromosome in 100bp-wide bins (100 bp is the resolution), one would optain the following four bins:

+
+
+
bins.bed
+
+
<chr>  <pos> <bin>
+chr1   1     100
+chr1   101   200
+chr1   201   300
+chr1   301   389
+
+

Each pair extremity can be changed to an integer indicating the position of the bin it falls in, e.g. for the left-hand extremity of the pairs file printed hereinabove (bin1):

+
<chr1>  <pos1>  ->  <bin1>
+chr1    162     ->  2
+chr1    180     ->  2
+chr1    183     ->  2
+chr1    221     ->  3
+chr1    254     ->  3
+

Similarly for the right-hand extremity of the pairs file (bin2):

+
<chr2>  <pos2>  ->  <bin2>
+chr1    172     ->  chr1 2
+chr1    192     ->  chr1 2
+chr1    254     ->  chr1 3
+chr1    273     ->  chr1 3
+chr1    298     ->  chr1 3
+

By pasting side-to-side the left-hand and right-hand extremities of each pair, the .pairs file can be turned into something like:

+
<bin1> <bin2>
+2      2
+2      2
+2      3
+3      3
+3      3
+

And if we now count the number of each <bin1> <bin2> combinaison, adding a third <count> column, we end up with a count.matrix text file:

+
+
+
count.matrix
+
+
<bin1> <bin2>  <count>
+2      2       2
+2      3       1
+3      3       2
+
+

This count.matrix file lists a total of 5 pairs, and in which bin each extremity of each pair is contained. Thus, a count matrix is a lossy file format, as it β€œrounds up” the position of each pair’s extremity to the genomic bin containing it.

+

This β€œi-j-x” 3-column format, in which i-j relate to a pair of β€œcoordinates” indices (or a pair of genomic bin indices) in a matrix, and x relates to a score associated with the pair of indices, is generally called a β€œCOO sparse matrix”.

+

In this context, the regions.bed acts as a secondary β€œdictionary” describing the nature of i and j indices, i.e. the location of genomic bins.

+

+1.2.2.2 Plain-text matrices: HiC-Pro style

+

The HiC-Pro pipeline (Servant et al. (2015)) outputs 2 text files: a regions.bed file and a count.matrix file. They are generated by the exact process explained above.

+

Together, these two files can describe the interaction frequency between any pair of genomic loci. They are non-binarized text files, and as such are technically human-readable. However, it is relatively hard to get a grasp of these files compared to a plain .pairs file, as information regarding genomic bins and interaction frequencies are stored in separate files. Moreover, because they are non-binarized, these files often end up using a large disk space and cannot be easily indexed. This prevents easy subsetting of the data stored in these files.

+

.(m)cool and .hic file formats are two standards addressing these limitations.

+

+1.2.2.3 .(m)cool matrices

+

The .cool format has been formally defined in Abdennur & Mirny (2019) and is a particular type of HDF5 (Hierarchical Data Format) file. It is an indexed archive file storing rectangular tables called:

+
    +
  • +bins: containing the same information than the regions.bed file;
  • +
  • +pixels: containing the same information than the count.matrix (each β€œpixel” is a pair of 2 bins and has one or several associated scores);
  • +
  • +chroms: summarizing the order and length of the chromosomes present in a Hi-C contact matrix;
  • +
  • +indexes: allowing random access, i.e. parsing of only a subset of the data without having to read through the entire set of data.
  • +
+

+

A single .pairs file binned at different resolutions can also be saved into a single, multi-resolution .mcool file. .mcool essentially consists of nested .cool files.

+

Importantly, as an HDF5-based format, .cool files are binarized, indexed and highly-compressed. This has two major benefits:

+
    +
  1. Smaller disk storage footprint
  2. +
  3. +Rapid subsetting of the data through random access +
  4. +
+

Moreover, parsing .cool files is possible using HDF standard APIs.

+

+1.2.2.4 .hic matrices

+

The .hic format is another type of binarized, indexed and highly-compressed file (Durand et al. (2016)). It can store virtually the same information than a .cool file. However, parsing .hic files is not as straightforward as .cool files, as it does not rely on a generic file standard. Still, the straw library has been implemented in several computing languages to facilitate parsing of .hic files (Durand et al. (2016)).

+

+1.3 Pre-processing Hi-C data

+

+1.3.1 Processing workflow

+

Fundamentally, the main steps performed to pre-process Hi-C are:

+
    +
  1. Separate read mapping
  2. +
  3. Pairs parsing
  4. +
  5. Pairs sorting
  6. +
  7. Pairs filtering
  8. +
  9. Pairs binning into a contact matrix
  10. +
  11. Normalization of contact matrix and multi-resolution matrix generation
  12. +
+

+

In practice, a minimal workflow to pre-process Hi-C data is the following (adapted from Open2C et al. (2023)):

+
+
## Note these fields have to be replaced by appropriate variables: 
+##    <index>
+##    <input.R1.fq.gz>
+##    <input.R2.fq.gz>
+##    <chromsizes.txt>
+##    <prefix>
+bwa mem2 -SP5M <index> <input.R1.fq.gz> <input.R2.fq.gz> \
+    | pairtools parse -c <chromsizes.txt> \
+    | pairtools sort \
+    | pairtools dedup \
+    | cooler cload pairs -c1 2 -p1 3 -c2 4 -p2 5 <chromsizes.txt>:10000 - <prefix>.cool
+cooler zoomify --balance --nproc 32 --resolutions 5000N --out <prefix>.mcool <prefix>.cool
+
+

Several pipelines have been developed to facilitate Hi-C data pre-processing. A few of them stand out from the crowd:

+
    +
  • +nf-distiller: a combination of an aligner + pairtools + cooler +
  • +
  • +HiC-pro (Servant et al. (2015))
  • +
  • +Juicer (Durand et al. (2016))
  • +
+
+
+
+ +
+
+Note +
+
+
+

For larger genomes (> 1Gb) with more than few tens of M of reads per fastq (e.g. > 100M), we recommend pre-processing data on an HPC cluster. Aligners, pairs processing and matrix binning can greatly benefit from parallelization over multiple CPUs (Open2C et al. (2023))).
+To scale up data pre-processing, we recommend to rely on an efficient read mapper such as bwa, followed by pairs parsing, sorting and deduplication with pairtools and binning with cooler.

+
+
+

+1.3.2 hicstuff: lightweight Hi-C pipeline

+

hicstuff is an integrated workflow to process Hi-C data. Some advantages compared to solutions mentioned above are its simplicity, flexibility and lightweight. For shallow sequencing or Hi-C on smaller genomes, it efficiently parses fastq reads and processes data into binned contact matrices with a single terminal command.

+

hicstuff provides both a command-line interface (CLI) and a python API to process fastq reads into a binned contact matrix. A processing pipeline can be launched using the standard command pipeline as follows:

+
+
## Note these fields have to be replaced by appropriate variables: 
+##    <hicstuff-options>
+##    <genome.fa>
+##    <input.R1.fq.gz>
+##    <input.R2.fq.gz>
+hicstuff pipeline \
+   <hicstuff-options> \
+   --genome <genome.fa> \
+   <input.R1.fq.gz> \
+   <input.R2.fq.gz>  
+
+

hicstuff documentation website is available here: https://hicstuff.readthedocs.io/ to read more about available options and internal processing steps.

+

+1.3.3 HiCool: hicstuff within R

+

hicstuff is available as a standalone (conda install -c bioconda hicstuff it!). It is also shipped in an R package: HiCool. Thus, HiCool can process fastq files directly within an R console.

+

+1.3.3.1 Executing HiCool

+

To demonstrate this, we first fetch example .fastq files:

+
+
library(HiContactsData)
+r1 <- HiContactsData(sample = 'yeast_wt', format = 'fastq_R1')
+r2 <- HiContactsData(sample = 'yeast_wt', format = 'fastq_R2')
+
+

We then load the HiCool library and execute the main HiCool function.

+
+
library(HiCool)
+HiCool(
+    r1, 
+    r2, 
+    restriction = 'DpnII,HinfI', 
+    resolutions = c(4000, 8000, 16000), 
+    genome = 'R64-1-1', 
+    output = './HiCool/'
+)
+
+

+1.3.3.2 HiCool arguments

+

Several arguments can be passed to HiCool and some are worth mentioning them:

+
    +
  • +restriction: (default: "DpnII,HinfI")
    +
  • +
  • +resolutions: (default: NULL, automatically inferring resolutions based on genome size)
    +
  • +
  • +iterative: (default: TRUE)
    +
  • +
  • +filter: (default: TRUE)
    +
  • +
  • +balancing_args: (default: " --cis-only --min-nnz 3 --mad-max 7 ")
    +
  • +
  • +threads: (default: 1L)
  • +
+

Other HiCool arguments can be listed by checking HiCool documentation in R: ?HiCool::HiCool.

+

+1.3.3.3 HiCool outputs

+

We can check the generated output files placed in the HiCool/ directory.

+
+
fs::dir_tree('HiCool/')
+
+
    +
  • The *.pairs and *.mcool files are the pairs and contact matrix files, respectively. These are the output files the end-user is generally looking for. +
  • +
  • The *.html file is a report summarizing pairs numbers, filtering, etc…
  • +
  • The *.log file contains all output and error messages, as well as the full list of commands that have been executed to pre-process the input dataset.
  • +
  • The *.pdf graphic files provide a visual representation of the distribution of informative/non-informative pairs.
  • +
+
+
+
+ +
+
+Tip +
+
+
+

All the files generated by a single HiCool pipeline execution contain the same 6-letter unique hash to make sure they are not overwritten if re-executing the same command.

+
+
+

+1.4 Exploratory data analysis of processed Hi-C files

+

Once Hi-C raw data has been transformed into a set of processed files, exploratory data analysis is typically conducted following two main routes:

+
    +
  • Data visualization;
  • +
  • Data investigation.
  • +
+

During the last decade, a number of softwares have been developed to unlock Hi-C data visualization and investigation. Here we provide a non-exhaustive list of notable tools developed throughout the recent years for downstream Hi-C analysis, selected from this longer list.

+
    +
  • +

    2012-2015:

    +
      +
    • HiTC (2012)
    • +
    • HiCCUPS (2014)
    • +
    • HiCseg (2014)
    • +
    • Fit-Hi-C (2014)
    • +
    • HiC-Pro (2015)
    • +
    • diffHic (2015)
    • +
    • cooltools (2015)
    • +
    • HiCUP (2015)
    • +
    • HiCPlotter (2015)
    • +
    • HiFive (2015)
    • +
    +
  • +
  • +

    2016-2019:

    +
      +
    • CHiCAGO (2016)
    • +
    • TADbit (2017)
    • +
    • HiCRep (2017)
    • +
    • HiC-DC (2017)
    • +
    • GoTHIC (2017)
    • +
    • HiCExplorer (2018)
    • +
    • Boost-HiC (2018)
    • +
    • HiCcompare (2018)
    • +
    • HiPiler (2018)
    • +
    • coolpuppy (2019)
    • +
    +
  • +
  • +

    2020-present:

    +
      +
    • Serpentine (2020)
    • +
    • CHESS (2020)
    • +
    • DeepHiC (2020)
    • +
    • Chromosight (2020)
    • +
    • Mustache (2020)
    • +
    • TADcompare (2020)
    • +
    • POSSUM (2021)
    • +
    • Calder (2021)
    • +
    • HICDCPlus (2021)
    • +
    • plotgardener (2021)
    • +
    • GENOVA (2021)
    • +
    +
  • +
+

All references as well as many other softwares and references are available here.

+

References

+ + +
+
+Abdennur, N., & Mirny, L. A. (2019). Cooler: Scalable storage for hi-c data and other genomically labeled arrays. Bioinformatics, 36(1), 311–316. https://doi.org/10.1093/bioinformatics/btz540 +
+
+Davies, J. O. J., Oudelaar, A. M., Higgs, D. R., & Hughes, J. R. (2017). How best to identify chromosomal interactions: A comparison of approaches. Nature Methods, 14(2), 125–134. https://doi.org/10.1038/nmeth.4146 +
+
+Dekker, J., Rippe, K., Dekker, M., & Kleckner, N. (2002). Capturing chromosome conformation. Science, 295(5558), 1306–1311. https://doi.org/10.1126/science.1067799 +
+
+Deshpande, A. S., Ulahannan, N., Pendleton, M., Dai, X., Ly, L., Behr, J. M., Schwenk, S., Liao, W., Augello, M. A., Tyer, C., Rughani, P., Kudman, S., Tian, H., Otis, H. G., Adney, E., Wilkes, D., Mosquera, J. M., Barbieri, C. E., Melnick, A., … ImieliΕ„ski, M. (2022). Identifying synergistic high-order 3D chromatin conformations from genome-scale nanopore concatemer sequencing. Nature Biotechnology, 40(10), 1488–1499. https://doi.org/10.1038/s41587-022-01289-z +
+
+Durand, N. C., Shamim, M. S., Machol, I., Rao, S. S. P., Huntley, M. H., Lander, E. S., & Aiden, E. L. (2016). Juicer provides a one-click system for analyzing loop-resolution hi-c experiments. Cell Systems, 3(1), 95–98. https://doi.org/10.1016/j.cels.2016.07.002 +
+
+Lieberman-Aiden, E., Berkum, N. L. van, Williams, L., Imakaev, M., Ragoczy, T., Telling, A., Amit, I., Lajoie, B. R., Sabo, P. J., Dorschner, M. O., Sandstrom, R., Bernstein, B., Bender, M. A., Groudine, M., Gnirke, A., Stamatoyannopoulos, J., Mirny, L. A., Lander, E. S., & Dekker, J. (2009). Comprehensive mapping of long-range interactions reveals folding principles of the human genome. Science, 326(5950), 289–293. https://doi.org/10.1126/science.1181369 +
+
+Open2C, Abdennur, N., Fudenberg, G., Flyamer, I. M., Galitsyna, A. A., Goloborodko, A., Imakaev, M., & Venev, S. V. (2023). Pairtools: From sequencing data to chromosome contacts. https://doi.org/10.1101/2023.02.13.528389 +
+
+Servant, N., Varoquaux, N., Lajoie, B. R., Viara, E., Chen, C.-J., Vert, J.-P., Heard, E., Dekker, J., & Barillot, E. (2015). HiC-pro: An optimized and flexible pipeline for hi-c data processing. Genome Biology, 16(1). https://doi.org/10.1186/s13059-015-0831-x +
+
+Tavares-Cadete, F., Norouzi, D., Dekker, B., Liu, Y., & Dekker, J. (2020). Multi-contact 3C reveals that the human genome during interphase is largely not entangled. Nature Structural &Amp\(\mathsemicolon\) Molecular Biology, 27(12), 1105–1114. https://doi.org/10.1038/s41594-020-0506-5 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/topological-features.html b/docs/devel/pages/topological-features.html new file mode 100644 index 0000000..870699b --- /dev/null +++ b/docs/devel/pages/topological-features.html @@ -0,0 +1,1147 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 7  Finding topological features in Hi-C + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+7  Finding topological features in Hi-C +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter focuses on the annotation of topological features from Hi-C contact maps, including:

+
    +
  • Chromosome compartments
  • +
  • Topologically associating domains
  • +
  • Stable chromatin loops
  • +
+
+
+

+7.1 Chromosome compartments

+

Chromosome compartments refer to the segregation of the chromatin into active euchromatin (A compartments) and regulated heterochromatin (B compartment).

+

+7.1.1 Importing Hi-C data

+

To investigate chromosome compartments, we will fetch a contact matrix generated from a micro-C experiment (from Krietenstein et al. (2020)). A subset of the genome-wide dataset is provided in the OHCA package. It contains intra-chromosomal interactions within chr17, binned at 5000, 100000 and 250000 bp.

+
+
library(HiCExperiment)
+library(OHCA)
+cf <- fs::path_package('OHCA', 'extdata', 'chr17.mcool')
+microC <- import(cf, resolution = 250000)
+microC
+##  `HiCExperiment` object with 10,086,710 contacts over 334 regions 
+##  -------
+##  fileName: "/tmp/RtmpixmP1F/Rinst529f91dd/OHCA/extdata/chr17.mcool" 
+##  focus: "whole genome" 
+##  resolutions(3): 5000 100000 250000
+##  active resolution: 250000 
+##  interactions: 52755 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+seqinfo(microC)
+##  Seqinfo object with 1 sequence from an unspecified genome:
+##    seqnames seqlengths isCircular genome
+##    chr17      83257441         NA   <NA>
+
+

+7.1.2 Annotating A/B compartments

+

The consensus approach to annotate A/B compartments is to compute the eigenvectors of a Hi-C contact matrix and identify the eigenvector representing the chromosome-wide bi-partite segmentation of the genome.

+

The getCompartments() function performs several internal operations to achieve this:

+
    +
  1. Obtains cis interactions per chromosome
  2. +
  3. Computes O/E contact matrix scores
  4. +
  5. Computes 3 first eigenvectors of this Hi-C contact matrix
  6. +
  7. Normalizes eigenvectors
  8. +
  9. Picks the eigenvector that has the greatest absolute correlation with a phasing track (e.g. a GC% track automatically computed from a genome reference sequence, or a gene density track)
  10. +
  11. Signs this eigenvector so that positive values represent the A compartment
  12. +
+
+
phasing_track <- BSgenome.Hsapiens.UCSC.hg38::BSgenome.Hsapiens.UCSC.hg38
+microC_compts <- getCompartments(microC, genome = phasing_track)
+##  Going through preflight checklist...
+##  Parsing intra-chromosomal contacts for each chromosome...
+##  Computing eigenvectors for each chromosome...
+
+microC_compts
+##  `HiCExperiment` object with 10,086,710 contacts over 334 regions 
+##  -------
+##  fileName: "/tmp/RtmpixmP1F/Rinst529f91dd/OHCA/extdata/chr17.mcool" 
+##  focus: "whole genome" 
+##  resolutions(3): 5000 100000 250000
+##  active resolution: 250000 
+##  interactions: 52755 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(41) borders(0) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(1): eigens
+
+

getCompartments() is an endomorphism: it returns the original object, enriched with two new pieces of information:

+
    +
  • A compartments topologicalFeatures:
  • +
+
+
topologicalFeatures(microC_compts, "compartments")
+##  GRanges object with 41 ranges and 1 metadata column:
+##         seqnames            ranges strand | compartment
+##            <Rle>         <IRanges>  <Rle> | <character>
+##     [1]    chr17    250001-3000000      * |           A
+##     [2]    chr17   3000001-3500000      * |           B
+##     [3]    chr17   3500001-5500000      * |           A
+##     [4]    chr17   5500001-6500000      * |           B
+##     [5]    chr17   6500001-8500000      * |           A
+##     ...      ...               ...    ... .         ...
+##    [37]    chr17 72750001-73250000      * |           A
+##    [38]    chr17 73250001-74750000      * |           B
+##    [39]    chr17 74750001-79250000      * |           A
+##    [40]    chr17 79250001-79750000      * |           B
+##    [41]    chr17 79750001-83250000      * |           A
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome
+
+
    +
  • The calculated eigenvectors stored in metadata:
  • +
+
+
metadata(microC_compts)$eigens
+##  GRanges object with 334 ranges and 9 metadata columns:
+##                                  seqnames            ranges strand |
+##                                     <Rle>         <IRanges>  <Rle> |
+##             chr17.chr17_1_250000    chr17          1-250000      * |
+##        chr17.chr17_250001_500000    chr17     250001-500000      * |
+##        chr17.chr17_500001_750000    chr17     500001-750000      * |
+##       chr17.chr17_750001_1000000    chr17    750001-1000000      * |
+##      chr17.chr17_1000001_1250000    chr17   1000001-1250000      * |
+##                              ...      ...               ...    ... .
+##    chr17.chr17_82250001_82500000    chr17 82250001-82500000      * |
+##    chr17.chr17_82500001_82750000    chr17 82500001-82750000      * |
+##    chr17.chr17_82750001_83000000    chr17 82750001-83000000      * |
+##    chr17.chr17_83000001_83250000    chr17 83000001-83250000      * |
+##    chr17.chr17_83250001_83257441    chr17 83250001-83257441      * |
+##                                     bin_id     weight   chr    center
+##                                  <numeric>  <numeric> <Rle> <integer>
+##             chr17.chr17_1_250000         0        NaN chr17    125000
+##        chr17.chr17_250001_500000         1 0.00626903 chr17    375000
+##        chr17.chr17_500001_750000         2 0.00567190 chr17    625000
+##       chr17.chr17_750001_1000000         3 0.00528588 chr17    875000
+##      chr17.chr17_1000001_1250000         4 0.00464628 chr17   1125000
+##                              ...       ...        ...   ...       ...
+##    chr17.chr17_82250001_82500000       329 0.00463044 chr17  82375000
+##    chr17.chr17_82500001_82750000       330 0.00486910 chr17  82625000
+##    chr17.chr17_82750001_83000000       331 0.00561269 chr17  82875000
+##    chr17.chr17_83000001_83250000       332 0.00546433 chr17  83125000
+##    chr17.chr17_83250001_83257441       333        NaN chr17  83253721
+##                                         E1        E2        E3   phasing
+##                                  <numeric> <numeric> <numeric> <numeric>
+##             chr17.chr17_1_250000  0.000000  0.000000  0.000000  0.383084
+##        chr17.chr17_250001_500000  0.450991  0.653287  0.615300  0.433972
+##        chr17.chr17_500001_750000  0.716784  0.707461  0.845033  0.465556
+##       chr17.chr17_750001_1000000  0.904423  0.414952  0.864288  0.503592
+##      chr17.chr17_1000001_1250000  0.913023  0.266287  0.759016  0.547712
+##                              ...       ...       ...       ...       ...
+##    chr17.chr17_82250001_82500000  1.147060  0.239112  1.133498  0.550872
+##    chr17.chr17_82500001_82750000  1.106937  0.419647  1.169464  0.513212
+##    chr17.chr17_82750001_83000000  0.818990  0.591955  0.850340  0.522432
+##    chr17.chr17_83000001_83250000  0.874038  0.503175  0.847926  0.528448
+##    chr17.chr17_83250001_83257441  0.000000  0.000000  0.000000  0.000000
+##                                      eigen
+##                                  <numeric>
+##             chr17.chr17_1_250000  0.000000
+##        chr17.chr17_250001_500000  0.450991
+##        chr17.chr17_500001_750000  0.716784
+##       chr17.chr17_750001_1000000  0.904423
+##      chr17.chr17_1000001_1250000  0.913023
+##                              ...       ...
+##    chr17.chr17_82250001_82500000  1.147060
+##    chr17.chr17_82500001_82750000  1.106937
+##    chr17.chr17_82750001_83000000  0.818990
+##    chr17.chr17_83000001_83250000  0.874038
+##    chr17.chr17_83250001_83257441  0.000000
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome
+
+

+7.1.3 Exporting compartment tracks

+

To save the eigenvector (as a bigwig file) and the compartments(as a gff file), the export function can be used:

+
+
library(GenomicRanges)
+library(rtracklayer)
+coverage(metadata(microC_compts)$eigens, weight = 'eigen') |> export('microC_eigen.bw')
+topologicalFeatures(microC_compts, "compartments") |> export('microC_compartments.gff3')
+
+

+7.1.4 Visualizing compartment tracks

+

Compartment tracks should be visualized in a dedicated genome browser, with the phasing track loaded as well, to ensure they are phased accordingly.
+That being said, it is possible to visualize a genome track in R besides the matching Hi-C contact matrix.

+
+
library(ggplot2)
+library(patchwork)
+microC <- autocorrelate(microC)
+##  
+p1 <- plotMatrix(microC, use.scores = 'autocorrelated', scale = 'linear', limits = c(-1, 1), caption = FALSE)
+eigen <- coverage(metadata(microC_compts)$eigens, weight = 'eigen')[[1]]
+eigen_df <- tibble(pos = cumsum(runLength(eigen)), eigen = runValue(eigen))
+p2 <- ggplot(eigen_df, aes(x = pos, y = eigen)) + 
+    geom_area() + 
+    theme_void() + 
+    coord_cartesian(expand = FALSE) + 
+    labs(x = "Genomic position", y = "Eigenvector value")
+wrap_plots(p1, p2, ncol = 1, heights = c(10, 1))
+
+
+

+
+
+
+
+

Here, we clearly note the concordance between the Hi-C correlation matrix, highlighting correlated interactions between pairs of genomic segments, and the eigenvector representing chromosome segmentation into 2 compartments: A (for positive values) and B (for negative values).

+

+7.1.5 Saddle plots

+

Saddle plots are typically used to measure the observed vs. expected interaction scores within or between genomic loci belonging to A and B compartments.

+

Non-overlapping genomic windows are grouped in nbins quantiles (typically between 10 and 50 quantiles) according to their A/B compartment eigenvector value, from lowest eigenvector values (i.e. strongest B compartments) to highest eigenvector values (i.e. strongest A compartments). The average observed vs. expected interaction scores are then computed for pairwise eigenvector quantiles and plotted in a 2D heatmap.

+
+
library(BiocParallel)
+plotSaddle(microC_compts, nbins = 25, BPPARAM = SerialParam(progressbar = FALSE))
+
+
+

+
+
+
+
+

Here, the top-left small corner represents average O/E scores between strong B compartments and the bottom-right larger corner represents average O/E scores between strong A compartments. Note that only chr17 interactions are contained in this dataset, explaining the grainy aspect of the saddle plot.

+

+7.2 Topological domains

+

Topological domains (a.k.a. Topologically Associating Domains, TADs, isolated neighborhoods, contact domains, …) refer to local chromosomal segments (e.b. roughly ≀ 1Mb in mammal genomes) which preferentially self-interact, in a constrained manner. They are demarcated by domain boundaries.

+
+

+
+
+

They are generally conserved across cell types and species (Schmitt et al. (2016)), typically correlate with units of DNA replication (Pope et al. (2014)), and could play a role during development (Stadhouders et al. (2019)).

+

+7.2.1 Computing diamond insulation score

+

Several approaches exist to annotate topological domains (Sefer (2022)). Several packages in R implement some of these functionalities, e.g. spectralTAD or TADcompare.

+

HiContacts offers a simple getDiamondInsulation function which computes the diamond insulation score (Crane et al. (2015)). This score quantifies average interaction frequency in an insulation window (of a certain window_size) sliding along contact matrices at a chosen resolution.

+
+
# - Compute insulation score
+bpparam <- SerialParam(progressbar = FALSE)
+hic <- zoom(microC, 5000) |> 
+    refocus('chr17:60000001-83257441') |>
+    getDiamondInsulation(window_size = 100000, BPPARAM = bpparam) |> 
+    getBorders()
+##  Going through preflight checklist...
+##  Scan each window and compute diamond insulation score...
+##  Annotating diamond score prominence for each window...
+
+hic
+##  `HiCExperiment` object with 2,156,222 contacts over 4,652 regions 
+##  -------
+##  fileName: "/tmp/RtmpixmP1F/Rinst529f91dd/OHCA/extdata/chr17.mcool" 
+##  focus: "chr17:60,000,001-83,257,441" 
+##  resolutions(3): 5000 100000 250000
+##  active resolution: 5000 
+##  interactions: 2156044 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(21) loops(0) viewpoints(0) 
+##  pairsFile: N/A 
+##  metadata(1): insulation
+
+

getDiamondInsulation() is an endomorphism: it returns the original object, enriched with two new pieces of information:

+
    +
  • A borders topologicalFeatures:
  • +
+
+
topologicalFeatures(hic, "borders")
+##  GRanges object with 21 ranges and 1 metadata column:
+##           seqnames            ranges strand |     score
+##              <Rle>         <IRanges>  <Rle> | <numeric>
+##    strong    chr17 60105001-60110000      * |  0.574760
+##      weak    chr17 60210001-60215000      * |  0.414425
+##      weak    chr17 61415001-61420000      * |  0.346668
+##    strong    chr17 61500001-61505000      * |  0.544336
+##      weak    chr17 62930001-62935000      * |  0.399794
+##       ...      ...               ...    ... .       ...
+##      weak    chr17 78395001-78400000      * |  0.235613
+##      weak    chr17 79065001-79070000      * |  0.236535
+##      weak    chr17 80155001-80160000      * |  0.284855
+##      weak    chr17 81735001-81740000      * |  0.497478
+##    strong    chr17 81840001-81845000      * |  1.395949
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome
+
+
    +
  • The calculated insulation scores stored in metadata:
  • +
+
+
metadata(hic)$insulation
+##  GRanges object with 4611 ranges and 8 metadata columns:
+##                            seqnames            ranges strand |    bin_id
+##                               <Rle>         <IRanges>  <Rle> | <numeric>
+##    chr17_60100001_60105000    chr17 60100001-60105000      * |     12020
+##    chr17_60105001_60110000    chr17 60105001-60110000      * |     12021
+##    chr17_60110001_60115000    chr17 60110001-60115000      * |     12022
+##    chr17_60115001_60120000    chr17 60115001-60120000      * |     12023
+##    chr17_60120001_60125000    chr17 60120001-60125000      * |     12024
+##                        ...      ...               ...    ... .       ...
+##    chr17_83130001_83135000    chr17 83130001-83135000      * |     16626
+##    chr17_83135001_83140000    chr17 83135001-83140000      * |     16627
+##    chr17_83140001_83145000    chr17 83140001-83145000      * |     16628
+##    chr17_83145001_83150000    chr17 83145001-83150000      * |     16629
+##    chr17_83150001_83155000    chr17 83150001-83155000      * |     16630
+##                               weight   chr    center     score insulation
+##                            <numeric> <Rle> <integer> <numeric>  <numeric>
+##    chr17_60100001_60105000 0.0406489 chr17  60102500  0.188061  -0.750142
+##    chr17_60105001_60110000 0.0255539 chr17  60107500  0.180860  -0.806466
+##    chr17_60110001_60115000       NaN chr17  60112500  0.196579  -0.686232
+##    chr17_60115001_60120000       NaN chr17  60117500  0.216039  -0.550046
+##    chr17_60120001_60125000       NaN chr17  60122500  0.230035  -0.459489
+##                        ...       ...   ...       ...       ...        ...
+##    chr17_83130001_83135000 0.0314684 chr17  83132500  0.262191  -0.270723
+##    chr17_83135001_83140000 0.0307197 chr17  83137500  0.240779  -0.393632
+##    chr17_83140001_83145000 0.0322810 chr17  83142500  0.219113  -0.529664
+##    chr17_83145001_83150000 0.0280840 chr17  83147500  0.199645  -0.663900
+##    chr17_83150001_83155000 0.0272775 chr17  83152500  0.180434  -0.809873
+##                                  min prominence
+##                            <logical>  <numeric>
+##    chr17_60100001_60105000     FALSE         NA
+##    chr17_60105001_60110000      TRUE    0.57476
+##    chr17_60110001_60115000     FALSE         NA
+##    chr17_60115001_60120000     FALSE         NA
+##    chr17_60120001_60125000     FALSE         NA
+##                        ...       ...        ...
+##    chr17_83130001_83135000     FALSE         NA
+##    chr17_83135001_83140000     FALSE         NA
+##    chr17_83140001_83145000     FALSE         NA
+##    chr17_83145001_83150000     FALSE         NA
+##    chr17_83150001_83155000     FALSE         NA
+##    -------
+##    seqinfo: 1 sequence from an unspecified genome
+
+
+
+
+ +
+
+Note +
+
+
+

The getDiamondInsulation function can be parallelized over multiple threads by specifying the Bioconductor generic BPPARAM argument.

+
+
+

+7.2.2 Exporting insulation scores tracks

+

To save the diamond insulation scores (as a bigwig file) and the borders (as a bed file), the export function can be used:

+
+
coverage(metadata(hic)$insulation, weight = 'insulation') |> export('microC_insulation.bw')
+topologicalFeatures(hic, "borders") |> export('microC_borders.bed')
+
+

+7.2.3 Visualizing chromatin domains

+

Insulation tracks should be visualized in a dedicated genome browser.
+That being said, it is possible to visualize a genome track in R besides the matching Hi-C contact matrix.

+
+
hic <- zoom(hic, 100000)
+p1 <- plotMatrix(
+    hic, 
+    use.scores = 'balanced', 
+    limits = c(-3.5, -1),
+    borders = topologicalFeatures(hic, "borders"),
+    caption = FALSE
+)
+insulation <- coverage(metadata(hic)$insulation, weight = 'insulation')[[1]]
+insulation_df <- tibble(pos = cumsum(runLength(insulation)), insulation = runValue(insulation))
+p2 <- ggplot(insulation_df, aes(x = pos, y = insulation)) + 
+    geom_area() + 
+    theme_void() + 
+    coord_cartesian(expand = FALSE) + 
+    labs(x = "Genomic position", y = "Diamond insulation score")
+wrap_plots(p1, p2, ncol = 1, heights = c(10, 1))
+
+
+

+
+
+
+
+

Local minima in the diamond insulation score displayed below the Hi-C contact matrix are identified using the getBorders() function, which automatically estimates a minimum threshold. These local minima correspond to borders and are visually depicted on the Hi-C map by blue diamonds.

+

+7.3 Chromatin loops

+

+7.3.1 chromosight +

+

Chromatin loops, dots, or contacts, refer to a strong increase of interaction frequency between a pair of two genomic loci. They correspond to focal β€œdots” on a Hi-C map. Relying on computer vision algorithms, chromosight uses this property to annotate chromatin loops in a Hi-C map (Matthey-Doret et al. (2020)). chromosight is a standalone python package and is made available in R through the HiCool-managed conda environment with the getLoops() function.

+

+7.3.1.1 Identifying loops

+
+
hic <- HiCool::getLoops(microC, resolution = 5000)
+
+hic
+## `HiCExperiment` object with 917,156 contacts over 100 regions
+## -------
+## fileName: "/home/rsg/.cache/R/fourDNData/4d434d8538a0_4DNFI9FVHJZQ.mcool"
+## focus: "chr17:63,000,001-63,500,000"
+## resolutions(13): 1000 2000 ... 5000000 10000000
+## active resolution: 5000
+## interactions: 5047
+## scores(2): count balanced
+## topologicalFeatures: compartments(0) borders(0) loops(66411) viewpoints(0)
+## pairsFile: N/A
+## metadata(1): chromosight_args
+
+

getLoops() is an endomorphism: it returns the original object, enriched with two new pieces of information:

+
    +
  • A loops topologicalFeatures:
  • +
+
+
topologicalFeatures(hic, "loops")
+## GInteractions object with 66411 interactions and 5 metadata columns:
+##           seqnames1           ranges1     seqnames2           ranges2 |   bin_id1   bin_id2     score      ## pvalue    qvalue
+##               <Rle>         <IRanges>         <Rle>         <IRanges> | <numeric> <numeric> <numeric>   ## <numeric> <numeric>
+##       [1]      chr1     775001-780000 ---      chr1     850001-855000 |       155       170  0.334586 2.## 15995e-05 2.162e-05
+##       [2]      chr1     775001-780000 ---      chr1     865001-870000 |       155       173  0.403336 1.## 62900e-07 1.669e-07
+##       [3]      chr1     865001-870000 ---      chr1     890001-895000 |       173       178  0.337344 1.## 91400e-07 1.957e-07
+##       [4]      chr1     910001-915000 ---      chr1     955001-960000 |       182       191  0.639725 0.## 00000e+00 0.000e+00
+##       [5]      chr1     910001-915000 ---      chr1   1055001-1060000 |       182       211  0.521699 0.## 00000e+00 0.000e+00
+##       ...       ...               ... ...       ...               ... .       ...       ...       ...       ##   ...       ...
+##   [66407]      chrY 19570001-19575000 ---      chrY 19720001-19725000 |    610133    610163  0.315529    3.## 30e-08  3.55e-08
+##   [66408]      chrY 19705001-19710000 ---      chrY 19730001-19735000 |    610160    610165  0.708753    0.## 00e+00  0.00e+00
+##   [66409]      chrY 19765001-19770000 ---      chrY 19800001-19805000 |    610172    610179  0.373635    1.## 10e-09  1.40e-09
+##   [66410]      chrY 20555001-20560000 ---      chrY 20645001-20650000 |    610330    610348  0.603308    0.## 00e+00  0.00e+00
+##   [66411]      chrY 21015001-21020000 ---      chrY 21055001-21060000 |    610422    610430  0.394614    9.## 12e-08  9.45e-08
+##   -------
+##   regions: 84171 ranges and 0 metadata columns
+##   seqinfo: 24 sequences from an unspecified genome; no seqlengths
+
+
    +
  • The arguments used by chromosight, stored in metadata:
  • +
+
+
metadata(hic)$chromosight_args
+## $`--pattern`
+## [1] "loops"
+## 
+## $`--dump`
+## [1] "/data/.cache/R//RtmpSaRwiZ"
+## 
+## $`--inter`
+## [1] FALSE
+## 
+## $`--iterations`
+## [1] "auto"
+## 
+## $`--kernel-config`
+## NULL
+## 
+## $`--perc-zero`
+## [1] "auto"
+## 
+## $`--perc-undetected`
+## [1] "auto"
+## 
+## $`--tsvd`
+## [1] FALSE
+## 
+## $`--win-fmt`
+## [1] "json"
+## 
+## $`--win-size`
+## [1] "auto"
+## 
+## $`--no-plotting`
+## [1] TRUE
+## 
+## $`--smooth-trend`
+## [1] FALSE
+## 
+## $`--norm`
+## [1] "auto"
+## 
+## $`<contact_map>`
+## [1] "/home/rsg/.cache/R/fourDNData/4d434d8538a0_4DNFI9FVHJZQ.mcool::/resolutions/5000"
+## 
+## $`--max-dist`
+## [1] "auto"
+## 
+## $`--min-dist`
+## [1] "auto"
+## 
+## $`--min-separation`
+## [1] "auto"
+## 
+## $`--n-mads`
+## [1] 5
+## 
+## $`<prefix>`
+## [1] "chromosight/chromo"
+## 
+## $`--pearson`
+## [1] "auto"
+## 
+## $`--subsample`
+## [1] "no"
+## 
+## $`--threads`
+## [1] 1
+
+

+7.3.1.2 Importing loops from files

+

If you are using chromosight directly from the terminal (i.e. outside R), you can import the annotated loops in R as follows:

+
+
df <- readr::read_tsv("...") ## Here put your loops file
+loops <- InteractionSet::GInteractions(
+    anchor1 = GenomicRanges::GRanges(
+        df$chrom1, IRanges::IRanges(df$start1+1, df$end1)
+    ),
+    anchor2 = GenomicRanges::GRanges(
+        df$chrom2, IRanges::IRanges(df$start2+1, df$end2)
+    ),
+    bin_id1 = df$bin1, 
+    bin_id2 = df$bin2, 
+    score = df$score, 
+    pvalue = df$pvalue, 
+    qvalue = df$qvalue
+)
+
+

+7.3.1.3 Exporting chromatin loops

+
+
loops <- topologicalFeatures(hic, "loops")
+loops <- loops[loops$score >= 0.4 & loops$qvalue <= 1e-6]
+GenomicInteractions::export.bedpe(loops, 'loops.bedpe')
+
+

+7.3.1.4 Visualizing chromatin loops

+
+
plotMatrix(
+    refocus(hic, 'chr17:62500001-63500000') |> zoom(5000), 
+    loops = loops,
+    limits = c(-4, -1.2),
+    caption = FALSE
+)
+
+

+

+7.3.2 Other R packages

+

A number of other R packages have been developed to identify focal chromatin loops, notably fitHiC (Ay et al. (2014)), GOTHiC (Mifsud et al. (2017)) or idr2d (Krismer et al. (2020)). Each fits a slightly different purpose, and we encourage the end user to read companion publications.

+

References

+ + +
+
+Ay, F., Bailey, T. L., & Noble, W. S. (2014). Statistical confidence estimation for hi-c data reveals regulatory chromatin contacts. Genome Research, 24(6), 999–1011. https://doi.org/10.1101/gr.160374.113 +
+
+Crane, E., Bian, Q., McCord, R. P., Lajoie, B. R., Wheeler, B. S., Ralston, E. J., Uzawa, S., Dekker, J., & Meyer, B. J. (2015). Condensin-driven remodelling of x chromosome topology during dosage compensation. Nature, 523(7559), 240–244. https://doi.org/10.1038/nature14450 +
+
+Krietenstein, N., Abraham, S., Venev, S. V., Abdennur, N., Gibcus, J., Hsieh, T.-H. S., Parsi, K. M., Yang, L., Maehr, R., Mirny, L. A., Dekker, J., & Rando, O. J. (2020). Ultrastructural details of mammalian chromosome architecture. Molecular Cell, 78(3), 554–565.e7. https://doi.org/10.1016/j.molcel.2020.03.003 +
+
+Krismer, K., Guo, Y., & Gifford, D. K. (2020). IDR2D identifies reproducible genomic interactions. Nucleic Acids Research, 48(6), e31–e31. https://doi.org/10.1093/nar/gkaa030 +
+
+Matthey-Doret, C., Baudry, L., Breuer, A., Montagne, R., Guiglielmoni, N., Scolari, V., Jean, E., Campeas, A., Chanut, P. H., Oriol, E., MΓ©ot, A., Politis, L., Vigouroux, A., Moreau, P., Koszul, R., & Cournac, A. (2020). Computer vision for pattern detection in chromosome contact maps. Nature Communications, 11(1). https://doi.org/10.1038/s41467-020-19562-7 +
+
+Mifsud, B., Martincorena, I., Darbo, E., Sugar, R., Schoenfelder, S., Fraser, P., & Luscombe, N. M. (2017). GOTHiC, a probabilistic model to resolve complex biases and to identify real interactions in hi-c data. PLOS ONE, 12(4), e0174744. https://doi.org/10.1371/journal.pone.0174744 +
+
+Pope, B. D., Ryba, T., Dileep, V., Yue, F., Wu, W., Denas, O., Vera, D. L., Wang, Y., Hansen, R. S., Canfield, T. K., Thurman, R. E., Cheng, Y., GΓΌlsoy, G., Dennis, J. H., Snyder, M. P., Stamatoyannopoulos, J. A., Taylor, J., Hardison, R. C., Kahveci, T., … Gilbert, D. M. (2014). Topologically associating domains are stable units of replication-timing regulation. Nature, 515(7527), 402–405. https://doi.org/10.1038/nature13986 +
+
+Schmitt, A. D., Hu, M., Jung, I., Xu, Z., Qiu, Y., Tan, C. L., Li, Y., Lin, S., Lin, Y., Barr, C. L., & Ren, B. (2016). A compendium of chromatin contact maps reveals spatially active regions in the human genome. Cell Reports, 17(8), 2042–2059. https://doi.org/10.1016/j.celrep.2016.10.061 +
+
+Sefer, E. (2022). A comparison of topologically associating domain callers over mammals at high resolution. BMC Bioinformatics, 23(1). https://doi.org/10.1186/s12859-022-04674-2 +
+
+Stadhouders, R., Filion, G. J., & Graf, T. (2019). Transcription factors and 3D genome conformation in cell-fate decisions. Nature, 569(7756), 345–354. https://doi.org/10.1038/s41586-019-1182-7 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-13-1.png b/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 0000000..7c37a24 Binary files /dev/null and b/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-7-1.png b/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 0000000..b88b4e1 Binary files /dev/null and b/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-8-1.png b/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 0000000..9423bee Binary files /dev/null and b/docs/devel/pages/topological-features_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/docs/devel/pages/visualization.html b/docs/devel/pages/visualization.html new file mode 100644 index 0000000..c1796b8 --- /dev/null +++ b/docs/devel/pages/visualization.html @@ -0,0 +1,932 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 4  Hi-C data visualization + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+4  Hi-C data visualization +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter focuses on the various visualization tools offered by HiContacts to plot HiCExperiment contact matrices in R.

+
+
+
+ +
+
+

To demonstrate how to visualize a HiCExperiment contact matrix, we will create an HiCExperiment object from an example .cool file provided in the HiContactsData package.

+
+
library(HiCExperiment)
+library(HiContactsData)
+
+# ---- This downloads an example `.mcool` file and caches it locally 
+coolf <- HiContactsData('yeast_wt', 'mcool')
+
+# ---- This creates a connection to the disk-stored `.mcool` file
+cf <- CoolFile(coolf)
+cf
+
+# ---- This imports contacts from the chromosome `V` at resolution `2000`
+hic <- import(cf, focus = 'V', resolution = 2000)
+
+
+
hic
+##  `HiCExperiment` object with 303,545 contacts over 289 regions 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: "V" 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 2000 
+##  interactions: 20177 
+##  scores(2): count balanced 
+##  topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+
+
+
+

+4.1 Visualizing Hi-C contact maps

+

Visualizing Hi-C contact maps is often a necessary step in exploratory data analysis. A Hi-C contact map is usually displayed as a heatmap, in which:

+
    +
  • Each axis represents a section of the genome of interest (either a segment of a chromosome, or several chromosomes, …).
  • +
  • The color code aims to represent β€œinteraction frequency”, which can be expressed in β€œraw” counts or normalized (balanced).
  • +
  • Other metrics can also be displayed in Hi-C heatmaps, e.g. ratios of interaction frequency between two Hi-C experiments, p-values of differential interaction analysis, …
  • +
  • Axes are often identical, representing interactions constrained within a single genomic window, a.k.a. on-diagonal matrices.
  • +
  • However, axes can be different: this is the case when off-diagonal matrices are displayed.
  • +
+

+4.1.1 Single map

+

Simple visualization of disk-stored Hi-C contact matrices can be done by:

+
    +
  1. Importing the interactions over the genomic location of interest into a HiCExperiment object;
  2. +
  3. Using plotMatrix function (provided by HiContacts) to generate a plot.
  4. +
+
+ +
+
+

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

A caption summarizing the plotting parameters is added below the heatmap. This can be removed with caption = FALSE.

+
+
+

+4.1.2 Horizontal map

+

Hi-C maps are sometimes visualized in a β€œhorizontal” style, where a square on-diagonal heatmap is tilted by 45˚ and truncated to only show interactions up to a certain distance from the main diagonal.

+

When a maxDistance argument is provided to plotMatrix, it automatically generates a horizontal-style heatmap.

+
+
plotMatrix(hic, maxDistance = 200000)
+
+
+

+
+
+
+
+

+4.1.3 Side-by-side maps

+

Sometimes, one may want to visually plot 2 Hi-C samples side by side to compare the interaction landscapes over the same genomic locus. This can be done by adding a second HiCExperiment (imported with the same focus) with the compare.to argument.

+

Here, we are importing a second .mcool file corresponding to a Hi-C experiment performed in a eco1 yeast mutant:

+
+
hic2 <- import(
+    CoolFile(HiContactsData('yeast_eco1', 'mcool')), 
+    focus = 'V', 
+    resolution = 2000
+)
+
+

We then plot the 2 matrices side by side. The first will be displayed in the top right corner and the second (provided with compare.to) will be in the bottom left corner.

+
+
plotMatrix(hic, compare.to = hic2)
+
+
+

+
+
+
+
+

+4.1.4 Plotting multiple chromosomes

+

Interactions from multiple chromosomes can be visualized in a Hi-C heatmap. One needs to (1) first parse the entire contact matrix in R, (2) then subset interactions over chromosomes of interest with [ and (3) use plotMatrix to generate the multi-chromosome plot.

+
+
full_hic <- import(cf, resolution = 4000)
+plotMatrix(full_hic)
+
+
+

+
+
+
+
hic_subset <- full_hic[c("II", "III", "IV")]
+plotMatrix(hic_subset)
+
+
+

+
+
+
+
+

+4.2 Hi-C maps customization options

+

A number of customization options are available for the plotMatrix function. The next subsections focus on how to:

+
    +
  • Pick the scores of interest to represent in a Hi-C heatmap;
  • +
  • Change the numeric scale and boundaries;
  • +
  • Change the color map;
  • +
  • Extra customization options
  • +
+

+4.2.1 Choosing scores

+

By default, plotMatrix will attempt to plot balanced (coverage normalized) Hi-C matrices. However, extra scores may be associated with interactions in a HiCExperiment object (more on this in the next chapter)

+

For instance, we can plot the count scores, which are un-normalized raw contact counts directly obtained when binning a .pairs file:

+
+
plotMatrix(hic, use.scores = 'count')
+
+
+

+
+
+
+
+

+4.2.2 Choosing scale

+

The color scale is automatically adjusted to range from the minimum to the maximum scores of the HiCExperiment being plotted. This can be adjusted using the limits argument.

+
+
plotMatrix(hic, limits = c(-3.5, -1))
+
+
+

+
+
+
+
+

+4.2.3 Choosing color map

+

?HiContacts::palettes returns a list of available color maps to use with plotMatrix. Any custom color map can also be used by manually specifying a vector of colors.

+
+
# ----- `afmhotr` color map is shipped in the `HiContacts` package
+afmhotrColors() 
+##  [1] "#ffffff" "#f8f5c3" "#f4ee8d" "#f6be35" "#ee7d32" "#c44228" "#821d19"
+##  [8] "#381211" "#050606"
+plotMatrix(
+    hic, 
+    use.scores = 'balanced',
+    limits = c(-4, -1),
+    cmap = afmhotrColors()
+)
+
+
+

+
+
+
+
+

+4.3 Advanced visualization

+

+4.3.1 Overlaying topological features

+

Topological features (e.g. chromatin loops, domain borders, A/B compartments, e.g. β€¦) are often displayed over a Hi-C heatmap.

+

To illustrate how to do this, let’s import pre-computed chromatin loops in R. These loops have been identified using chromosight (Matthey-Doret et al. (2020)) on the contact matrix which we imported interactions from.

+
+
library(rtracklayer)
+library(InteractionSet)
+loops <- system.file('extdata', 'S288C-loops.bedpe', package = 'HiCExperiment') |> 
+    import() |> 
+    makeGInteractionsFromGRangesPairs()
+loops
+##  GInteractions object with 162 interactions and 0 metadata columns:
+##          seqnames1       ranges1     seqnames2       ranges2
+##              <Rle>     <IRanges>         <Rle>     <IRanges>
+##      [1]         I     3001-4000 ---         I   29001-30000
+##      [2]         I   29001-30000 ---         I   50001-51000
+##      [3]         I   95001-96000 ---         I 128001-129000
+##      [4]         I 133001-134000 ---         I 157001-158000
+##      [5]        II     8001-9000 ---        II   46001-47000
+##      ...       ...           ... ...       ...           ...
+##    [158]       XVI 773001-774000 ---       XVI 803001-804000
+##    [159]       XVI 834001-835000 ---       XVI 859001-860000
+##    [160]       XVI 860001-861000 ---       XVI 884001-885000
+##    [161]       XVI 901001-902000 ---       XVI 940001-941000
+##    [162]       XVI 917001-918000 ---       XVI 939001-940000
+##    -------
+##    regions: 316 ranges and 0 metadata columns
+##    seqinfo: 16 sequences from an unspecified genome; no seqlengths
+
+

Similarly, borders have also been mapped with chromosight. We can also import them in R.

+
+
borders <- system.file('extdata', 'S288C-borders.bed', package = 'HiCExperiment') |> 
+    import()
+borders
+##  GRanges object with 814 ranges and 0 metadata columns:
+##          seqnames        ranges strand
+##             <Rle>     <IRanges>  <Rle>
+##      [1]        I   73001-74000      *
+##      [2]        I 108001-109000      *
+##      [3]        I 181001-182000      *
+##      [4]       II   90001-91000      *
+##      [5]       II 119001-120000      *
+##      ...      ...           ...    ...
+##    [810]      XVI 777001-778000      *
+##    [811]      XVI 796001-797000      *
+##    [812]      XVI 811001-812000      *
+##    [813]      XVI 890001-891000      *
+##    [814]      XVI 933001-934000      *
+##    -------
+##    seqinfo: 16 sequences from an unspecified genome; no seqlengths
+
+

Chromatin loops are stored in GInteractions while borders are GRanges. The former will be displayed as off-diagonal circles and the later as on-diagonal diamonds on the Hi-C heatmap.

+
+
plotMatrix(hic, loops = loops, borders = borders)
+
+
+

+
+
+
+
+

+4.3.2 Aggregated Hi-C maps

+

Finally, Hi-C map β€œsnippets” (i.e. extracts) are often aggregated together to show an average signal. This analysis is sometimes referred to as APA (Aggregated Plot Analysis).

+

Aggregated Hi-C maps can be computed over a collection of targets using the aggregate function. These targets can be GRanges (to extract on-diagonal snippets) or GInteractions (to extract off-diagonal snippets). The flankingBins specifies how many matrix bins should be extracted on each side of the targets of interest.

+

Here, we compute the aggregated Hi-C snippets of Β± 15kb around each chromatin loop listed in loops.

+
+
hic <- zoom(hic, 1000)
+aggr_loops <- aggregate(hic, targets = loops, flankingBins = 15)
+##  Going through preflight checklist...
+##  Parsing the entire contact matrice as a sparse matrix...
+##  Modeling distance decay...
+##  Filtering for contacts within provided targets...
+aggr_loops
+##  `AggrHiCExperiment` object over 148 targets 
+##  -------
+##  fileName: "/root/.cache/R/ExperimentHub/1701a09a86_7752" 
+##  focus: 148 targets 
+##  resolutions(5): 1000 2000 4000 8000 16000
+##  active resolution: 1000 
+##  interactions: 961 
+##  scores(4): count balanced expected detrended 
+##  slices(4): count balanced expected detrended 
+##  topologicalFeatures: targets(148) compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) 
+##  pairsFile: N/A 
+##  metadata(0):
+
+

aggregate generates a AggrHiCExperiment object, a flavor of HiCExperiment class of objects.

+
    +
  • +AggrHiCExperiment objects have an extra slices slot. This stores a list of arrays, one per scores. Each array is of 3 dimensions, x and y representing the heatmap axes, and z representing the index of the target.
  • +
  • +AggrHiCExperiment objects also have a mandatory topologicalFeatures element named targets, storing the genomic loci provided in aggregate.
  • +
+
+
slices(aggr_loops)
+##  List of length 4
+##  names(4): count balanced expected detrended
+dim(slices(aggr_loops, 'count'))
+##  [1]  31  31 148
+topologicalFeatures(aggr_loops, 'targets')
+##  Pairs object with 148 pairs and 0 metadata columns:
+##                      first            second
+##                  <GRanges>         <GRanges>
+##      [1]     I:14501-44500     I:35501-65500
+##      [2]    I:80501-110500   I:113501-143500
+##      [3]   I:118501-148500   I:142501-172500
+##      [4]    II:33501-63500    II:63501-93500
+##      [5]  II:134501-164500  II:159501-189500
+##      ...               ...               ...
+##    [144] XVI:586501-616500 XVI:606501-636500
+##    [145] XVI:733501-763500 XVI:754501-784500
+##    [146] XVI:758501-788500 XVI:788501-818500
+##    [147] XVI:819501-849500 XVI:844501-874500
+##    [148] XVI:845501-875500 XVI:869501-899500
+
+

The resulting AggrHiCExperiment can be plotted using the same plotMatrix function with the arguments described above.

+
+
plotMatrix(
+    aggr_loops, 
+    use.scores = 'detrended', 
+    scale = 'linear', 
+    limits = c(-1, 1), 
+    cmap = bgrColors()
+)
+
+
+

+
+
+
+
+

References

+ + +
+
+Matthey-Doret, C., Baudry, L., Breuer, A., Montagne, R., Guiglielmoni, N., Scolari, V., Jean, E., Campeas, A., Chanut, P. H., Oriol, E., MΓ©ot, A., Politis, L., Vigouroux, A., Moreau, P., Koszul, R., & Cournac, A. (2020). Computer vision for pattern detection in chromosome contact maps. Nature Communications, 11(1). https://doi.org/10.1038/s41467-020-19562-7 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-10-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 0000000..e3ccc28 Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-11-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-11-1.png new file mode 100644 index 0000000..9408c5d Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-11-1.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-14-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 0000000..195e667 Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-14-1.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-17-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 0000000..d9366cb Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-4-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-4-1.png new file mode 100644 index 0000000..b3ded0a Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-4-1.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-5-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-5-1.png new file mode 100644 index 0000000..b5150ad Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-5-1.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-7-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 0000000..5b5c400 Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-8-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 0000000..9b49460 Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-8-2.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-8-2.png new file mode 100644 index 0000000..51a0d43 Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-8-2.png differ diff --git a/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-9-1.png b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-9-1.png new file mode 100644 index 0000000..32dd9fa Binary files /dev/null and b/docs/devel/pages/visualization_files/figure-html/unnamed-chunk-9-1.png differ diff --git a/docs/devel/pages/workflow-centros.html b/docs/devel/pages/workflow-centros.html new file mode 100644 index 0000000..906a9b3 --- /dev/null +++ b/docs/devel/pages/workflow-centros.html @@ -0,0 +1,724 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 12  Workflow 3: Inter-centromere interactions in yeast + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+12  Workflow 3: Inter-centromere interactions in yeast +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter illustrates how to plot the aggregate signal over pairs of genomic ranges, in this case pairs of yeast centromeres.

+
+
+
+
+
+ +
+
+Datasets +
+
+
+

We leverage two yeast datasets in this notebook.

+
    +
  • One from a WT yeast strain in G1 phase
  • +
  • One from a WT yeast strain in G2/M phase
  • +
+
+
+

+12.1 Importing Hi-C data and plotting contact matrices

+
+
library(HiContacts)
+library(purrr)
+library(ggplot2)
+hics <- list(
+    'G1' = import('/home/rsg/repos/OHCA-data/S288c_G1.mcool', resolution = 4000),
+    'G2M' = import('/home/rsg/repos/OHCA-data/S288c_G2M.mcool', resolution = 4000)
+)
+imap(hics, ~ plotMatrix(
+    .x, use.scores = 'balanced', limits = c(-4, -1), caption = FALSE
+) + ggtitle(.y))
+
+

+

We can visually appreciate that inter-chromosomal interactions, notably between centromeres, are less prominent in G2/M.

+

+12.2 Checking P(s) and cis/trans interactions ratio

+
+
library(dplyr)
+pairs <- list(
+    'G1' = PairsFile('/home/rsg/repos/OHCA-data/S288c_G1.pairs'),
+    'G2M' = PairsFile('/home/rsg/repos/OHCA-data/S288c_G2M.pairs') 
+)
+ps <- imap_dfr(pairs, ~ distanceLaw(.x, by_chr = TRUE) |> 
+    mutate(sample = .y) 
+)
+plotPs(ps, aes(x = binned_distance, y = norm_p, group = interaction(sample, chr), color = sample)) + 
+    scale_color_manual(values = c('black', 'red'))
+plotPsSlope(ps, ggplot2::aes(x = binned_distance, y = slope, group = interaction(sample, chr), color = sample)) + 
+    scale_color_manual(values = c('black', 'red'))
+
+

+

This confirms that interactions in cells synchronized in G2/M are enriched for 10-30kb-long interactions.

+
+
ratios <- imap_dfr(hics, ~ cisTransRatio(.x) |> mutate(sample = .y))
+ggplot(ratios, aes(x = chr, y = trans_pct, fill = sample)) + 
+    geom_col() + 
+    labs(x = 'Chromosomes', y = "% of trans interactions") + 
+    scale_y_continuous(labels = scales::percent) + 
+    facet_grid(~sample)
+
+

+

We can also highlight that trans (inter-chromosomal) interactions are proportionally decreasing in G2/M-synchronized cells.

+

+12.3 Centromere virtual 4C profiles

+
+
data(centros_yeast)
+v4c_centro <- imap_dfr(hics, ~ virtual4C(.x, resize(centros_yeast[2], 8000)) |> 
+    as_tibble() |> 
+    mutate(sample = .y) |> 
+    filter(seqnames == 'IV')
+) 
+ggplot(v4c_centro, aes(x = start, y = score, colour = sample)) +
+    geom_line() +
+    theme_bw() +
+    labs(
+        x = "chrIV position", 
+        y = "Contacts with chrII centromere", 
+        title = "Interaction profile of chrII centromere"
+    )
+
+

+

+12.4 Aggregated 2D signal over all pairs of centromeres

+

We can start by computing all possible pairs of centromeres.

+
+
centros_pairs <- lapply(1:length(centros_yeast), function(i) {
+    lapply(1:length(centros_yeast), function(j) {
+        S4Vectors::Pairs(centros_yeast[i], centros_yeast[j])
+    })
+}) |> 
+    do.call(c, args = _) |>
+    do.call(c, args = _) |> 
+    InteractionSet::makeGInteractionsFromGRangesPairs()
+centros_pairs <- centros_pairs[anchors(centros_pairs, 'first') != anchors(centros_pairs, 'second')]
+
+centros_pairs
+## GInteractions object with 240 interactions and 0 metadata columns:
+##         seqnames1       ranges1     seqnames2       ranges2
+##             <Rle>     <IRanges>         <Rle>     <IRanges>
+##     [1]         I 151583-151641 ---        II 238361-238419
+##     [2]         I 151583-151641 ---       III 114322-114380
+##     [3]         I 151583-151641 ---        IV 449879-449937
+##     [4]         I 151583-151641 ---         V 152522-152580
+##     [5]         I 151583-151641 ---        VI 147981-148039
+##     ...       ...           ... ...       ...           ...
+##   [236]       XVI 556255-556313 ---        XI 440229-440287
+##   [237]       XVI 556255-556313 ---       XII 151366-151424
+##   [238]       XVI 556255-556313 ---      XIII 268222-268280
+##   [239]       XVI 556255-556313 ---       XIV 628588-628646
+##   [240]       XVI 556255-556313 ---        XV 326897-326955
+##   -------
+##   regions: 16 ranges and 0 metadata columns
+##   seqinfo: 17 sequences (1 circular) from R64-1-1 genome
+
+

Then we can aggregate the Hi-C signal over each pair of centromeres.

+
+
aggr_maps <- purrr::imap(hics, ~ {
+    aggr <- aggregate(.x, centros_pairs, maxDistance = 1e999)
+    plotMatrix(
+        aggr, use.scores = 'balanced', limits = c(-5, -1), 
+        cmap = HiContacts::rainbowColors(), 
+        caption = FALSE
+    ) + ggtitle(.y)
+})
+## Going through preflight checklist...
+## Parsing the entire contact matrice as a sparse matrix...
+## Modeling distance decay...
+## Filtering for contacts within provided targets...
+## Going through preflight checklist...
+## Parsing the entire contact matrice as a sparse matrix...
+## Modeling distance decay...
+## Filtering for contacts within provided targets...
+
+cowplot::plot_grid(plotlist = aggr_maps, nrow = 1)
+
+

+

+12.5 Aggregated 1D interaction profile of centromeres

+

One can generalize the previous virtual 4C plot, by extracting the interaction profile between all possible pairs of centromeres in each dataset.

+
+
df <- map_dfr(1:{length(centros_yeast)-1}, function(i) {
+    centro1 <- resize(centros_yeast[i], fix = 'center', 8000)
+    map_dfr({i+1}:length(centros_yeast), function(j) {
+        centro2 <- resize(centros_yeast[j], fix = 'center', 80000)
+        gi <- GInteractions(centro1, centro2)
+        imap_dfr(hics, ~ .x[gi] |> 
+            interactions() |> 
+            as_tibble() |>
+            mutate(
+                sample = .y, 
+                center = center2 - start(resize(centro2, fix = 'center', 1))
+            ) |> 
+            select(sample, seqnames1, seqnames2, center, balanced)
+        )
+    })
+}) 
+p <- ggplot(df, aes(x = center/1e3, y = balanced)) + 
+    geom_line(aes(group = interaction(seqnames1, seqnames2)), alpha = 0.03, col = "black") + 
+    geom_smooth(col = "red", fill = "red") + 
+    theme_bw() + 
+    theme(legend.position = 'none') + 
+    labs(
+        x = "Distance from centromere (kb)", y = "Normalized interaction frequency", 
+        title = "Centromere pairwise interaction profiles"
+    ) +
+    facet_grid(~sample)
+
+

+

References

+ + +
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/workflow-chicken.html b/docs/devel/pages/workflow-chicken.html new file mode 100644 index 0000000..f1b7c76 --- /dev/null +++ b/docs/devel/pages/workflow-chicken.html @@ -0,0 +1,830 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 11  Workflow 2: Chromosome compartment cohesion upon mitosis entry + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+11  Workflow 2: Chromosome compartment cohesion upon mitosis entry +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter illustrates how to:

+
    +
  • Annotate compartments for a list of HiC experiments
  • +
  • Generate saddle plots for a list of HiC experiments
  • +
  • Quantify changes in interactions between compartments between different timepoints
  • +
+
+
+
+
+
+ +
+
+Datasets +
+
+
+

We leverage five chicken datasets in this notebook, published in Gibcus et al. (2018). They are all available from the 4DN data portal using the fourDNData package.

+
    +
  • +4DNES9LEZXN7: chicken cell culture blocked in G2
  • +
  • +4DNESNWWIFZU: chicken cell culture released from G2 block (5min)
  • +
  • +4DNESGDXKM2I: chicken cell culture released from G2 block (10min)
  • +
  • +4DNESIR416OW: chicken cell culture released from G2 block (15min)
  • +
  • +4DNESS8PTK6F: chicken cell culture released from G2 block (30min)
  • +
+
+
+

+11.1 Importing data

+

The 4DN consortium provides access to the datasets published in Gibcus et al. (2018). in R, they can be obtained thanks to the fourDNData gateway package.

+
+
+
+ +
+
+Beware +
+
+
+

The first time the following chunk of code is executed, it will cache a large amount of data (mostly consisting of contact matrices stored in .mcool files).

+
+
+
+
library(HiCExperiment)
+library(fourDNData)
+library(BiocParallel)
+samples <- list(
+    '4DNES9LEZXN7' = 'G2 block', 
+    '4DNESNWWIFZU' = 'prophase (5m)', 
+    '4DNESGDXKM2I' = 'prophase (10m)', 
+    '4DNESIR416OW' = 'prometaphase (15m)', 
+    '4DNESS8PTK6F' = 'prometaphase (30m)' 
+)
+bpparam <- MulticoreParam(workers = 5, progressbar = TRUE)
+hics <- bplapply(names(samples), fourDNHiCExperiment, BPPARAM = bpparam)
+## Fetching local Hi-C contact map from Bioc cache
+## Fetching local compartments bigwig file from Bioc cache
+## Fetching local insulation bigwig file from Bioc cache
+## Fetching local borders bed file from Bioc cache
+## Importing contacts in memory
+## |===================================================| 100% 
+##
+## ...
+
+
+
names(hics) <- samples
+hics[["G2 block"]]
+## `HiCExperiment` object with 150,494,008 contacts over 4,109 regions
+## -------
+## fileName: "/home/rsg/.cache/R/fourDNData/25c33c9d826f_4DNFIT479GDR.mcool"
+## focus: "whole genome"
+## resolutions(13): 1000 2000 ... 5000000 10000000
+## active resolution: 250000
+## interactions: 7262748
+## scores(2): count balanced
+## topologicalFeatures: compartments(891) borders(3465)
+## pairsFile: N/A
+## metadata(3): 4DN_info eigens diamond_insulation
+
+

+11.2 Plotting whole chromosome matrices

+

We can visualize the five different Hi-C maps on the entire chromosome 3 with HiContacts by iterating over each of the HiCExperiment objects.

+
+
library(purrr)
+library(HiContacts)
+pl <- imap(hics, ~ .x['chr3'] |> 
+    zoom(100000) |> 
+    plotMatrix(use.scores = 'balanced', limits = c(-4, -1), caption = FALSE) + 
+    ggtitle(.y)
+)
+library(cowplot)
+plot_grid(plotlist = pl, nrow = 1)
+
+
+

+
+

This highlights the progressive remodeling of chromatin into condensed chromosomes, starting as soon as 5’ after release from G2 phase.

+

+11.3 Zooming on a chromosome section

+

Zooming on a chromosome section, we can plot the Hi-C autocorrelation matrix for each timepoint. These matrices are generally used to highlight the overall correlation of interaction profiles between different segments of a chromosome section (see Chapter 5 for more details).

+
+
## --- Format compartment positions of chr. 4 segment
+.chr <- 'chr4'
+.start <- 59000000L
+.stop <- 75000000L
+library(GenomicRanges)
+coords <- GRanges(paste0(.chr, ':', .start, '-', .stop))
+compts_df <- topologicalFeatures(hics[["G2 block"]], "compartments") |> 
+    subsetByOverlaps(coords, type = 'within') |> 
+    as.data.frame()
+compts_gg <- geom_rect(
+    data = compts_df, 
+    mapping = aes(xmin = start, xmax = end, ymin = -500000, ymax = 0, alpha = compartment), 
+    col = 'black', inherit.aes = FALSE
+)
+
+## --- Subset contact matrices to chr. 4 segment and computing autocorrelation scores
+g2 <- hics[["G2 block"]] |> 
+    subsetByOverlaps(coords) |>
+    zoom(100000) |> 
+    autocorrelate()
+pro5 <- hics[["prophase (5m)"]] |> 
+    subsetByOverlaps(coords) |>
+    zoom(100000) |> 
+    autocorrelate()
+pro30 <- hics[["prometaphase (30m)"]] |> 
+    subsetByOverlaps(coords) |>
+    zoom(100000) |> 
+    autocorrelate()
+
+## --- Plot autocorrelation matrices
+plot_grid(
+    plotMatrix(
+        g2,
+        use.scores = 'autocorrelated', 
+        scale = 'linear', 
+        limits = c(-1, 1), 
+        cmap = bwrColors(), 
+        maxDistance = 10000000, 
+        caption = FALSE
+    ) + ggtitle('G2') + compts_gg,
+    plotMatrix(
+        pro5,
+        use.scores = 'autocorrelated', 
+        scale = 'linear', 
+        limits = c(-1, 1), 
+        cmap = bwrColors(), 
+        maxDistance = 10000000, 
+        caption = FALSE
+    ) + ggtitle('Prophase 5min') + compts_gg,
+    plotMatrix(
+        pro30,
+        use.scores = 'autocorrelated', 
+        scale = 'linear', 
+        limits = c(-1, 1), 
+        cmap = bwrColors(), 
+        maxDistance = 10000000, 
+        caption = FALSE
+    ) + ggtitle('Prometaphase 30min') + compts_gg,
+    nrow = 1
+)
+
+
+

+
+

These correlation matrices suggest that there are two different regimes of chromatin compartment remodeling in this chromosome section:

+
    +
  1. Correlation scores between genomic bins within the compartment A remain positive 5’ after G2 release (albeit reduced compared to G2 block) and eventually become null 30’ after G2 release.
  2. +
  3. Correlation scores between genomic bins within the compartment B are overall null as soon as 5’ after G2 release.
  4. +

+11.4 Generating saddle plots

+

Saddle plots are typically used to measure the observed vs. expected interaction scores within or between genomic loci belonging to A and B compartments. Here, they can be used to check whether the two regimes of chromatin compartment remodeling are observed genome-wide.

+

Non-overlapping genomic windows are grouped by nbins quantiles (typically between 10 and 50 bins) according to their A/B compartment eigenvector value, from lowest eigenvector values (i.e. strongest B compartments) to highest eigenvector values (i.e. strongest A compartments). The average observed vs. expected interaction scores are computed for pairwise eigenvector quantiles and plotted in a 2D heatmap.

+
+
pl <- imap(hics, ~ plotSaddle(.x, nbins = 38, BPPARAM = bpparam) + ggtitle(.y)) 
+plot_grid(plotlist = pl, nrow = 1)
+
+
+

+
+

These plots confirm the previous observation made on chr. 4 and reveal that intra-B compartment interactions are generally lost 5’ after G2 release, while intra-A interactions take up to 15’ after G2 release to disappear.

+
+
+
+ +
+
+Beware +
+
+
+

The plotSaddle() function requires an eigenvector corresponding to A/B compartments. In this example, this eigenvector is recovered from the 4DN data portal. If not already available, this eigenvector can be computed from the contact matrix using the getCompartments() function.

+
+
+

+11.5 Quantifying interactions within and between compartments

+

We can leverage the replicate-merged contact matrices to quantify the interaction frequencies within A or B compartments or between A and B comaprtments, at different timepoints.

+

We can use the A/B compartment annotations obtained at the G2 block timepoint and extract O/E (observed vs expected) scores for interactions within A or B compartments or between A and B compartments, at different timepoints.

+
+
## --- Extract the A/B compartments identified in G2 block
+compts <- topologicalFeatures(hics[["G2 block"]], "compartments")
+compts$ID <- paste0(compts$compartment, seq_along(compts))
+
+## --- Iterate over timepoints to extract `detrended` (O/E) scores and 
+##     compartment annotations
+library(plyranges)
+df <- imap(hics[c(1, 2, 5)], ~ {
+    ints <- cis(.x) |> ## Filter out trans interactions
+        detrend() |> ## Compute O/E scores
+        interactions() ## Recover interactions 
+    ints$comp_first <- join_overlap_left(anchors(ints, "first"), compts)$ID
+    ints$comp_second <- join_overlap_left(anchors(ints, "second"), compts)$ID
+    tibble(
+        sample = .y, 
+        bin1 = ints$comp_first, 
+        bin2 = ints$comp_second, 
+        dist = pairdist(ints), 
+        OE = ints$detrended 
+    ) |> 
+        filter(dist > 5e6) |>
+        mutate(type = case_when(
+            grepl('A', bin1) & grepl('A', bin2) ~ 'AA',
+            grepl('B', bin1) & grepl('B', bin2) ~ 'BB',
+            grepl('A', bin1) & grepl('B', bin2) ~ 'AB',
+            grepl('B', bin1) & grepl('A', bin2) ~ 'BA'
+        )) |> 
+        filter(bin1 != bin2)
+}) |> list_rbind() |> mutate(
+    sample = factor(sample, names(hics)[c(1, 2, 5)])
+)
+
+

We can now plot the changes in O/E scores for intra-A, intra-B, A-B or B-A interactions, splitting boxplots by timepoint.

+
+
ggplot(df, aes(x = type, y = OE, group = type, fill = type)) + 
+    geom_boxplot(outlier.shape = NA) + 
+    facet_grid(~sample) + 
+    theme_bw() + 
+    ylim(c(-2, 2))
+
+

+

This visualization suggests that interactions between genomic loci belonging to the B compartment are lost more rapidly than those between genomic loci belonging to the A compartment, when cells are released from G2 to enter mitosis.

+

References

+ + +
+
+Gibcus, J. H., Samejima, K., Goloborodko, A., Samejima, I., Naumova, N., Nuebler, J., Kanemaki, M. T., Xie, L., Paulson, J. R., Earnshaw, W. C., Mirny, L. A., & Dekker, J. (2018). A pathway for mitotic chromosome formation. Science, 359(6376). https://doi.org/10.1126/science.aao6135 +
+
+
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/pages/workflow-yeast.html b/docs/devel/pages/workflow-yeast.html new file mode 100644 index 0000000..596b5de --- /dev/null +++ b/docs/devel/pages/workflow-yeast.html @@ -0,0 +1,993 @@ + + + + + + +Orchestrating Hi-C analysis with Bioconductor - 10  Workflow 1: Distance-dependent interactions across yeast mutants + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

+10  Workflow 1: Distance-dependent interactions across yeast mutants +

+
+ + + +
+ + + + +
+ + +
+
+
+ +
+
+Aims +
+
+
+

This chapter illustrates how to:

+
    +
  • Compute P(s) of several samples and compare them
  • +
  • Compute distance-adjusted correlation between Hi-C datasets with HiCRep +
  • +
  • Perform differential interaction analysis between Hi-C datasets with multiHiCcompare +
  • +
+
+
+
+
+
+ +
+
+Datasets +
+
+
+

We leverage seven yeast datasets in this notebook. They are all available from SRA:

+
    +
  • +SRR8769554: WT yeast strain, G1 phase (rep1)
  • +
  • +SRR10687276: WT yeast strain, G1 phase (rep12)
  • +
  • +SRR8769549: WT yeast strain, G2/M phase (rep1)
  • +
  • +SRR10687281: WT yeast strain, G2/M phase (rep12)
  • +
  • +SRR8769551: wpl1 mutant yeast strain, G2/M phase (rep1)
  • +
  • +SRR10687278: wpl1 mutant yeast strain, G2/M phase (rep2)
  • +
  • +SRR8769555: wpl1/eco1 mutant yeast strain, G2/M phase
  • +
+
+
+

+10.1 Recovering data from SRA

+

The easiest for this is to directly fetch files from SRA from their FTP server. We can do so using the base download.file function.

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

The next two code chunks illustrate how to do download and process Hi-C reads from SRA, but they are not actually executed when rendering this website as it would take a significant amount of time.

+
+
+
+
# !! This code is not actually executed !!
+dir.create('data')
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/004/SRR8769554/SRR8769554_1.fastq.gz", "data/WT_G1_WT_rep1_R1.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/004/SRR8769554/SRR8769554_2.fastq.gz", "data/WT_G1_WT_rep1_R2.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/076/SRR10687276/SRR10687276_1.fastq.gz", "data/WT_G1_WT_rep2_R1.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/076/SRR10687276/SRR10687276_2.fastq.gz", "data/WT_G1_WT_rep2_R2.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/009/SRR8769549/SRR8769549_1.fastq.gz", "data/WT_G2M_WT_rep1_R1.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/009/SRR8769549/SRR8769549_2.fastq.gz", "data/WT_G2M_WT_rep1_R2.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/081/SRR10687281/SRR10687281_1.fastq.gz", "data/WT_G2M_WT_rep2_R1.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/081/SRR10687281/SRR10687281_2.fastq.gz", "data/WT_G2M_WT_rep2_R2.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/001/SRR8769551/SRR8769551_1.fastq.gz", "data/wpl1_G2M_rep1_R1.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/001/SRR8769551/SRR8769551_2.fastq.gz", "data/wpl1_G2M_rep1_R2.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/078/SRR10687278/SRR10687278_1.fastq.gz", "data/wpl1_G2M_rep2_R1.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/078/SRR10687278/SRR10687278_2.fastq.gz", "data/wpl1_G2M_rep2_R2.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/005/SRR8769555/SRR8769555_1.fastq.gz", "data/wpl1eco1_G2M_R1.fastq.gz")
+download.file("ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/005/SRR8769555/SRR8769555_2.fastq.gz", "data/wpl1eco1_G2M_R2.fastq.gz")
+
+

+10.2 Processing reads with HiCool

+

We will map each pair of fastqs on the yeast genome reference (R64-1-1) using HiCool.

+
+
# !! This code is not actually executed !!
+library(HiCool)
+samples <- c(
+    'WT_G1_rep1', 
+    'WT_G1_rep2', 
+    'WT_G2M_rep1', 
+    'WT_G2M_rep2', 
+    'wpl1_G2M_rep1', 
+    'wpl1_G2M_rep2', 
+    'wpl1eco1_G2M' 
+)
+purrr::map(samples, ~ HiCool(
+    r1 = paste0('data/', .x, '_R1.fastq.gz'), 
+    r2 = paste0('data/', .x, '_R2.fastq.gz'), 
+    genome = 'R64-1-1', 
+    restriction = 'DpnII', 
+    iterative = FALSE, 
+    threads = 15, 
+    output = 'data/HiCool/', 
+    scratch = '/data/scratch/'
+))
+
+

Processed samples are put in data/HiCool directory. CoolFile objects are pointers to individual contact matrices. We can create such objects by using the importHiCoolFolder utility function.

+
+
cfs <- list(
+    WT_G1_rep1 = importHiCoolFolder('data/HiCool', 'GK8ISZ'), 
+    WT_G1_rep2 = importHiCoolFolder('data/HiCool', 'SWZTO0'), 
+    WT_G2M_rep1 = importHiCoolFolder('data/HiCool', '3KHHUE'), 
+    WT_G2M_rep2 = importHiCoolFolder('data/HiCool', 'UVNG7M'), 
+    wpl1_G2M_rep1 = importHiCoolFolder('data/HiCool', 'Q4KX6Z'), 
+    wpl1_G2M_rep2 = importHiCoolFolder('data/HiCool', '3N0L25'), 
+    wpl1eco1_G2M = importHiCoolFolder('data/HiCool', 'LHMXWE')
+)
+cfs
+
+

Now that these pointers have been defined, Hi-C contact matrices can be seamlessly imported in R with import.

+
+
library(purrr)
+library(HiCExperiment)
+hics <- map(cfs, import)
+hics
+## $WT_G1_rep1
+## `HiCExperiment` object with 5,454,145 contacts over 12,079 regions
+## -------
+## fileName: "../OHCA-data/HiCool/matrices/W303_G1_WT_rep1^mapped-S288c^GK8ISZ.mcool"
+## focus: "whole genome"
+## resolutions(5): 1000 2000 4000 8000 16000
+## active resolution: 1000
+## interactions: 3347524
+## scores(2): count balanced
+## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0)
+## pairsFile: ../OHCA-data/HiCool/pairs/W303_G1_WT_rep1^mapped-S288c^GK8ISZ.pairs
+## metadata(3): log args stats
+## 
+## $WT_G1_rep2
+## `HiCExperiment` object with 12,068,214 contacts over 12,079 regions
+## -------
+## fileName: "../OHCA-data/HiCool/matrices/W303_G1_WT_rep2^mapped-S288c^SWZTO0.mcool"
+## focus: "whole genome"
+## resolutions(5): 1000 2000 4000 8000 16000
+## active resolution: 1000
+## interactions: 6756099
+## scores(2): count balanced
+## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0)
+## pairsFile: ../OHCA-data/HiCool/pairs/W303_G1_WT_rep2^mapped-S288c^SWZTO0.pairs
+## metadata(3): log args stats
+## 
+## ... 
+
+

+10.3 Plotting chromosome-wide matrices of merged replicates

+

We can merge replicates with the merge function, and map the plotMatrix function over the resulting list of HiCExperiments.

+
+
library(HiContacts)
+chr <- 'X'
+merged_replicates <- list(
+    WT_G1 = merge(hics[[1]][chr], hics[[2]][chr]), 
+    WT_G2M = merge(hics[[3]][chr], hics[[4]][chr]), 
+    wpl1_G2M = merge(hics[[5]][chr], hics[[6]][chr]), 
+    wpl1eco1_G2M = hics[[7]][chr]
+)
+library(dplyr)
+library(ggplot2)
+maps <- imap(merged_replicates, ~ plotMatrix(
+    .x, use.scores = 'balanced', limits = c(-3.5, -1.5), caption = FALSE
+) + ggtitle(.y))
+cowplot::plot_grid(plotlist = maps, nrow = 1)
+
+

+

We can already note that long-range contacts seem to increase in frequency, in G2/M vs G1, in wpl1 vs WT and in wpl1/eco1 vs wpl1.

+

+10.4 Compute P(s) per replicate and plot it

+

Still using the map function, we can compute average P(s) for each replicate.
+Computation of the P(s) will take some time, as millions of pairs have to be imported in memory, but it will be accurate at the base resolution, rather than bin resolution from matrices.

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

Since matrices were imported after HiCool processing with the importHiCoolFolder, the associated .pairs file has been automatically added to each HiCExperiment object!

+
+
+

The computed P(s) is stored for each sample as a tibble.

+
+
pairsFile(hics[[1]])
+ps <- imap(hics, ~ distanceLaw(.x) |> mutate(sample = .y))
+## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G1_WT_rep1^mapped-S288c^GK8ISZ.pairs in memory. This may take a while...
+## |===============================================================| 100% 318 MB
+## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G1_WT_rep2^mapped-S288c^SWZTO0.pairs in memory. This may take a while...
+## |===============================================================| 100% 674 MB
+## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_WT_rep1^mapped-S288c^3KHHUE.pairs in memory. This may take a while...
+## |===============================================================| 100% 709 MB
+## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_WT_rep2^mapped-S288c^UVNG7M.pairs in memory. This may take a while...
+## |==============================================================| 100% 1683 MB
+## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_wpl1_rep1^mapped-S288c^Q4KX6Z.pairs in memory. This may take a while...
+## |==============================================================| 100% 1269 MB
+## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_wpl1_rep2^mapped-S288c^3N0L25.pairs in memory. This may take a while...
+## |==============================================================| 100% 1529 MB
+## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_wpl1-eco1^mapped-S288c^LHMXWE.pairs in memory. This may take a while...
+## |==============================================================| 100% 1036 MB
+ps[[1]]
+## # A tibble: 133 x 6
+##   binned_distance          p     norm_p norm_p_unity slope sample
+##             <dbl>      <dbl>      <dbl>        <dbl> <dbl> <chr>
+## 1               1 0.000154   0.000154         249.   0     WT_G1_rep1
+## 2               2 0.0000563  0.0000563         91.2  0.702 WT_G1_rep1
+## 3               3 0.0000417  0.0000417         67.5  0.699 WT_G1_rep1
+## 4               4 0.00000835 0.00000835        13.5  0.696 WT_G1_rep1
+## 5               5 0.00000501 0.00000501         8.10 0.693 WT_G1_rep1
+## 6               6 0.00000250 0.00000250         4.05 0.690 WT_G1_rep1
+## # ... with 127 more rows
+
+

We can bind all tibbles together and plot P(s) and their slope for each sample.

+
+
df <- list_rbind(ps)
+plotPs(
+    df, aes(x = binned_distance, y = norm_p, 
+    group = sample, color = sample)
+)
+plotPsSlope(
+    df, aes(x = binned_distance, y = slope, 
+    group = sample, color = sample)
+)
+
+

+

+10.5 Correlation between replicates with hicrep +

+

hicrep is a popular package to compute stratum-adjusted correlations between Hi-C datasets. β€œStratum” refers to the distance from the main diagonal: with increase distance from the main diagonal, interactions of the DNA polymer are bound to decrease. hicrep computes a β€œper-stratum” correlation score and computes a weighted average correlation for entire chromosomes.

+

We can check the documentation for hicrep main function, get.scc. This tells us that mat1 and mat2 n*n intrachromosomal contact maps of raw counts should be provided. Fortunately, HiCExperiment objects can easily be coerced into actual dense matrices using as.matrix() function.

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

Make sure to use the count scores, which are required by hicrep.

+
+
+

We can calculate the overall stratum-corrected correlation score over the chromosome IV between the two G2M WT replicates.

+
+
library(hicrep)
+scc <- get.scc(
+    hics[['WT_G2M_rep1']]["IV"] |> as.matrix(use.scores = 'count'), 
+    hics[['WT_G2M_rep2']]["IV"] |> as.matrix(use.scores = 'count'), 
+    resol = 1000, h = 2, lbr = 5000, ubr = 50000
+)
+names(scc)
+## [1] "corr" "wei"  "scc"  "std"
+scc$scc
+##           [,1]
+## [1,] 0.9785691
+
+

This can be generalized to all pairwise combinations of Hi-C datasets.

+
+
library(purrr)
+library(dplyr)
+library(ggplot2)
+mats <- map(hics, ~ .x["IV"] |> as.matrix(use.scores = 'count'))
+df <- map(1:7, function(i) {
+    map(1:7, function(j) {
+        data.frame(
+            i = names(hics)[i], 
+            j = names(hics)[j], 
+            scc = hicrep::get.scc(mats[[i]], mats[[j]], resol = 1000, h = 2, lbr = 5000, ubr = 200000)$scc
+        ) |>
+            mutate(i = factor(i, names(cfs))) |>
+            mutate(j = factor(j, names(cfs)))
+    }) |> list_rbind()
+}) |> list_rbind()
+ggplot(df, aes(x = i, y = j, fill = scc)) + 
+    geom_tile() + 
+    scale_x_discrete(guide = guide_axis(angle = 90)) + 
+    theme_bw() + 
+    coord_fixed(ratio = 1) + 
+    scale_fill_gradientn(colours = bgrColors())
+
+

+

We can even iterate over an extra level, to compute stratum-corrected correlation for all chromosomes. Here, we will only compute correlation scores between any sample and WT_G2M_rep1 sample.

+
+
+
+ +
+
+Parallelizing over chromosomes +
+
+
+

BiocParallel::bplapply() replaces purrr::map() here, as it allows parallelization of independent correlation computation runs over multiple CPUs.

+
+
+
+
# Some chromosomes will be ignored as they are too small for this analysis 
+chrs <- c('II', 'IV', 'V', 'VII', 'VIII', 'IX', 'X', 'XI', 'XIII', 'XIV', 'XVI')
+bpparam <- BiocParallel::MulticoreParam(workers = 6, progressbar = TRUE)
+df <- BiocParallel::bplapply(chrs, function(CHR) {
+    mats <- map(hics, ~ .x[CHR] |> interactions() |> gi2cm('count') |> cm2matrix())
+
+        map(c(1, 2, 4, 5, 6, 7), function(j) {
+            data.frame(
+                chr = CHR,
+                i = "WT_G2M_rep1", 
+                j = names(mats)[j], 
+                dist = seq(5000, 200000, 1000),
+                scc = hicrep::get.scc(mats[["WT_G2M_rep1"]], mats[[j]], resol = 1000, h = 2, lbr = 5000, ubr = 200000) 
+            ) |> mutate(j = factor(j, names(mats)))
+        }) |> list_rbind()
+
+}, BPPARAM = bpparam) |> list_rbind()
+
+

A tiny bit of data wrangling will allow us to plot the mean +/- confidence interval (90%) of stratum-adjusted correlations across the different chromosomes.

+
+
results <- group_by(df, j, dist) |> 
+    summarize(
+        mean = Rmisc::CI(scc.corr, ci = 0.90)[2], 
+        CI_up = Rmisc::CI(scc.corr, ci = 0.90)[1], 
+        CI_down = Rmisc::CI(scc.corr, ci = 0.90)[3]
+    )
+ggplot(results, aes(x = dist, y = mean, ymax = CI_up, ymin = CI_down)) + 
+    geom_line(aes(col = j)) + 
+    geom_ribbon(aes(fill = j), alpha = 0.2, col = NA) + 
+    theme_bw() + 
+    labs(x = "Stratum (genomic distance)", y = 'Stratum-corrected correlation')
+
+

+

+10.6 Differential interaction (DI) analysis with multiHiCcompare +

+

We will now focus on the chromosome XI and identify differentially interacting (DI) loci between WT and wpl1 mutant in G2/M.

+

To do this, we can use the multiHiCcompare package. The required input for the main make_hicexp() function is a list of raw counts for different samples/replicates, stored in data frames with four columns (chr, start1, start2, count).
+Although this data structure does not correspond to a standard HiC format, it is easy to manipulate a HiCExperiment object to coerce it into such structure.

+
+
library(multiHiCcompare)
+hics_list <- map(hics, ~ .x['XI'] |> 
+    zoom(2000) |> 
+    as.data.frame() |>
+    select(start1, start2, count) |> 
+    mutate(chr = 1) |> 
+    relocate(chr)
+)
+mhicc <- make_hicexp(
+    data_list = hics_list[c(3, 4, 5, 6)], 
+    groups = factor(c(1, 1, 2, 2)
+), A.min = 1)
+
+

The mhicc object contains data over the chromosome XI binned at 2kb for two pairs of replicates (WT or wpl1 G2/M HiC, each in duplicates):

+
    +
  • Group1 contains WT data
  • +
  • Group2 contains wpl1 data
  • +
+

To identify differential interactions, the actual statistical comparison is performed with the hic_exactTest() function.

+
+
results <- cyclic_loess(mhicc, span = 0.2) |> hic_exactTest()
+## |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s
+## |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=05s
+results 
+## Hi-C Experiment Object
+## 2 experimental groups
+## Group 1 has 2 samples
+## Group 2 has 2 samples
+## Data has been normalized
+
+

The results() output is not very informative as it is. It requires a little bit of reformating to be able to extract valuable insights from it.

+
+
df <- left_join(results@hic_table, results(results)) |> 
+    mutate(dist = region2 - region1) |> 
+    mutate(group = case_when(
+        region1 < 430000 & region2 > 450000 ~ 'inter_arms',
+        region1 >= 430000 & region2 <= 450000 ~ 'at_centro',
+        TRUE ~ 'arms'
+    )) |> 
+    filter(group %in% c('arms', 'inter_arms')) |> 
+    mutate(sign = p.value <= 0.05 & abs(logFC) >= 1)
+df
+## chr region1 region2 D   IF1   IF2   IF3   IF4   logFC  logCPM  p.value    p.adj dist group  sign
+##   1       1       1 0  6.16  2.09  7.96  5.43  0.5401 4.81329 5.38e-01 7.94e-01    0  arms FALSE
+##   1       1    2001 1 16.38 10.25 12.96 12.16 -0.2257 5.82484 7.00e-01 8.81e-01 2000  arms FALSE
+##   1       1    4001 2 41.41 40.72 84.41 45.14  0.5064 7.69885 5.94e-02 2.16e-01 4000  arms FALSE
+##   1       1    6001 3 22.26 30.51 73.83 48.48  1.2726 8.10243 6.48e-07 5.83e-05 6000  arms  TRUE
+##   1       1    8001 4 26.63 31.20 33.39 25.92  0.0998 7.55207 8.02e-01 9.34e-01 8000  arms FALSE
+## ...
+ggplot(df, aes(x = logFC, y = -log10(p.value), col = sign)) + 
+    geom_point(size = 0.2) + 
+    theme_bw() + 
+    facet_wrap(~group) + 
+    ylim(c(0, 6)) + 
+    theme(legend.position = 'none') + 
+    scale_color_manual(values = c('grey', 'black'))
+
+

+

In this volcano plot, we can visually appreciate the fold-change of interaction frequency in WT or wpl1, for interactions constrained within the chromosome XI arms (left) or spanning the chr. XI centromere (right). This clearly highlights that interactions within arms are increased in wpl1 mutant while those spanning the centromere strongly decreased.

+ +

One of the strengths of HiContacts is that it can be leveraged to visualize any quantification related to genomic interactions as a HiC heatmap, since plotMatrix can take a GInteractions object with any score saved in mcols as input.

+
+
gis <- rename(df, seqnames1 = chr, start1 = region1, start2 = region2) |> 
+    mutate(
+        seqnames2 = seqnames1, 
+        end1 = start1 + 1999, 
+        end2 = start2 + 1999
+    ) |> 
+    filter(abs(logFC) >= 1) |>
+    df2gi() 
+cowplot::plot_grid(
+    plotMatrix(merged_replicates[['WT_G2M']], use.scores = 'balanced', limits = c(-3.5, -1), caption = FALSE),
+    plotMatrix(merged_replicates[['wpl1_G2M']], use.scores = 'balanced', limits = c(-3.5, -1), caption = FALSE),
+    plotMatrix(gis, use.scores = 'logFC', scale = 'linear', limits = c(-2, 2), cmap = bgrColors()), 
+    align = "hv", axis = 'tblr', nrow = 1
+)
+
+

+

References

+ + +
Back to top
+
+ + + + \ No newline at end of file diff --git a/docs/devel/search.json b/docs/devel/search.json new file mode 100644 index 0000000..d89ce9a --- /dev/null +++ b/docs/devel/search.json @@ -0,0 +1,464 @@ +[ + { + "objectID": "index.html", + "href": "index.html", + "title": "Orchestrating Hi-C analysis with Bioconductor", + "section": "", + "text": "Welcome\nThis is the landing page of the β€œOrchestrating Hi-C analysis with Bioconductor” book. The primary aim of this book is to introduce the R user to Hi-C analysis. This book starts with key concepts important for the analysis of chromatin conformation capture and then presents Bioconductor tools that can be leveraged to process, analyze, explore and visualize Hi-C data." + }, + { + "objectID": "index.html#table-of-contents", + "href": "index.html#table-of-contents", + "title": "Orchestrating Hi-C analysis with Bioconductor", + "section": "Table of contents", + "text": "Table of contents\nThis book is divided in three parts:\nPart I: Introduction to Hi-C analysis\n\nChapter 1: General principles and Hi-C data pre-processing\nChapter 2: The different R classes implemented to analyze Hi-C\nChapter 3: Manipulating Hi-C data in R\nChapter 4: Hi-C data visualization\n\nPart II: In-depth Hi-C analysis\n\nChapter 5: Matrix-centric analysis\nChapter 6: Interactions-centric analysis\nChapter 7: Finding topological features from a Hi-C contact matrix\n\nPart III: Hi-C analysis workflows\n\nData gateways: accessing public Hi-C data portals\nInteroperability: Using HiCExperiment with other R packages\nWorkflow 1: Distance-dependent interactions across yeast mutants\nWorkflow 2: Chromosome compartment cohesion upon mitosis entry\nWorkflow 3: Inter-centromere interactions in yeast" + }, + { + "objectID": "index.html#general-audience", + "href": "index.html#general-audience", + "title": "Orchestrating Hi-C analysis with Bioconductor", + "section": "General audience", + "text": "General audience\nThis books aims to demonstrate how to pre-process, parse and investigate Hi-C data in R. For this reason, a significant portion of this book consists of executable R code chunks. To be able to reproduce the examples demonstrated in this book and go further in the analysis of your real datasets, you will need to rely on several dependencies.\n\n\nR >= 4.3 is required. You can check R version by typing version in an R console or in RStudio. If you do not have R >= 4.3 installed, you will need to update your R version, as most extra dependencies will require R >= 4.3.\n\n\n\n\n\n\n\nInstalling R 4.3 πŸ‘‡\n\n\n\n\n\nDetailed instructions are available here to install R 4.3 on a Linux machine (Ubuntu 22.04).\nBriefly, to install pre-compiled version of R 4.3.0:\n\n# This is adapted from Posit (https://docs.posit.co/resources/install-r/)\nexport R_VERSION=4.3.0\n\n# Install curl and gdebi-core\nsudo apt update -qq\nsudo apt install curl gdebi-core -y\n\n# Fetching the `.deb` install file from Posit repository\ncurl -O https://cdn.rstudio.com/r/ubuntu-2204/pkgs/r-${R_VERSION}_1_amd64.deb\n\n# Install R\nsudo gdebi r-${R_VERSION}_1_amd64.deb --non-interactive -q\n\n# Optional: create a symlink to add R to your PATH\nsudo ln -s /opt/R/${R_VERSION}/bin/R /usr/local/bin/R\n\nIf you have some issues when installing the Hi-C packages listed below, you may need to install the following system libraries:\n\nsudo apt update -qq\nsudo apt install -y \\\n automake make cmake fort77 gfortran \\\n bzip2 unzip ftp build-essential \\\n libc6 libreadline-dev \\\n libpng-dev libjpeg-dev libtiff-dev \\\n libx11-dev libxt-dev x11-common \\\n libharfbuzz-dev libfribidi-dev \\\n libfreetype6-dev libfontconfig1-dev \\\n libbz2-dev liblzma-dev libtool \\\n libxml2 libxml2-dev \\\n libzstd-dev zlib1g-dev \\\n libdb-dev libglu1-mesa-dev \\\n libncurses5-dev libghc-zlib-dev libncurses-dev \\\n libpcre3-dev libxml2-dev libblas-dev libzmq3-dev \\\n libssl-dev libcurl4-openssl-dev \\\n libgsl-dev libeigen3-dev libboost-all-dev \\\n libgtk2.0-dev xvfb xauth xfonts-base apt-transport-https \\\n libhdf5-dev libudunits2-dev libgdal-dev libgeos-dev \\\n libproj-dev libnode-dev libmagick++-dev\n\n\n\n\n\n\nBioconductor >= 3.18 is also required. You can check whether Bioconductor is available and its version in R by typing BiocManager::version(). If you do not have BiocManager >= 3.18 installed, you will need to update it as follows:\n\n\nif (!require(\"BiocManager\", quietly = TRUE))\n install.packages(\"BiocManager\")\nBiocManager::install(version = \"3.18\")\n\n\nYou will also need important packages, which will be described in length in this book. The following R code will set up most of the extra dependencies:\n\n\nBiocManager::install(\"HiCExperiment\", ask = FALSE)\nBiocManager::install(\"HiCool\", ask = FALSE)\nBiocManager::install(\"HiContacts\", ask = FALSE)\nBiocManager::install(\"HiContactsData\", ask = FALSE)\nBiocManager::install(\"fourDNData\", ask = FALSE)\nBiocManager::install(\"DNAZooData\", ask = FALSE)" + }, + { + "objectID": "index.html#developers", + "href": "index.html#developers", + "title": "Orchestrating Hi-C analysis with Bioconductor", + "section": "Developers", + "text": "Developers\nFor developers or advanced R users, the devel versions of these packages can be installed along with their dependencies:\n\ninstall.packages(\"pak\", repos = \"https://r-lib.github.io/p/pak/devel/\")\npak::pkg_install(\"js2264/HiCExperiment\", ask = FALSE, dependencies = c(\"Depends\", \"Imports\", \"Suggests\"))\npak::pkg_install(\"js2264/HiCool\", ask = FALSE, dependencies = c(\"Depends\", \"Imports\", \"Suggests\"))\npak::pkg_install(\"js2264/HiContacts\", ask = FALSE, dependencies = c(\"Depends\", \"Imports\", \"Suggests\"))\npak::pkg_install(\"js2264/HiContactsData\", ask = FALSE, dependencies = c(\"Depends\", \"Imports\", \"Suggests\"))\npak::pkg_install(\"js2264/fourDNData\", ask = FALSE, dependencies = c(\"Depends\", \"Imports\", \"Suggests\"))\npak::pkg_install(\"js2264/DNAZooData\", ask = FALSE, dependencies = c(\"Depends\", \"Imports\", \"Suggests\"))" + }, + { + "objectID": "index.html#docker-image", + "href": "index.html#docker-image", + "title": "Orchestrating Hi-C analysis with Bioconductor", + "section": "Docker image", + "text": "Docker image\nIf you have docker installed, the easiest approach would be to run the following command in a shell terminal:\n\ndocker run -it ghcr.io/js2264/ohca:latest R\n\nThis will fetch a docker image with the latest development versions of the aforementioned packages pre-installed, and initiate an interactive R session." + }, + { + "objectID": "index.html#building-book", + "href": "index.html#building-book", + "title": "Orchestrating Hi-C analysis with Bioconductor", + "section": "Building book", + "text": "Building book\nThe OHCA book has been rendered in R thanks to a number of packages, including but not only:\n\ndevtools\nquarto\nrebook\n\nTo build this book locally, you can run:\n\n\n\nbash\n\ngit clone git@github.com:js2264/OHCA.git && cd OHCA\nquarto render\n\n\n\n\n\n\n\n\nWarning\n\n\n\nAll dependencies listed above will be required!\n\n\nThe actual rendering of this book is done by GitHub Actions, and the rendered static website is hosted by GitHub Pages." + }, + { + "objectID": "pages/preamble.html", + "href": "pages/preamble.html", + "title": "Preamble", + "section": "", + "text": "Hi-C is an experimental method to quantify spatial interactions between any pair of genomic loci. While a number of command-line interfaces (CLI) exist to process and manipulate Hi-C data (e.g.Β cooler (Abdennur & Mirny (2019)), juicer (Durand et al. (2016)) and HiC-Pro (Servant et al. (2015))), they generally suffer from several limitations often found in emerging genomics techniques:\n\nNo genomic representation of Hi-C processed data: the existing CLIs can efficiently parse Hi-C data as a numerical matrix and perform a few standard quantitative operations (e.g.Β contact matrix binning and normalization, dimensionality reduction, etc). However, they systematically fail to represent a Hi-C contact matrix as a genomic object. Qualitative analyses (e.g.Β intersecting chromatin loops with genomic features, finding genes overlapping with domains, etc) therefore remain extremely tedious.\nNo format-agnostic analysis libraries. Three competing file format standards (.(m)cool, .hic and HiC-Pro files) currently exist to store Hi-C processed data and dedicated CLIs propose sets of tools specifically working with their corresponding Hi-C processed data file format. This has curbed the development of generic Hi-C data analysis libraries by favoring the emergence of several redundant tools.\nLack of integration within a biology-oriented community. While rapid development of Hi-C analysis methodology is ongoing, it is primarily driven by small-scale teams rather than by a community as a whole. This oriented development is less likely to fulfill the needs met by other investigators.\n\nIn this book, we provide an overview of a set of tools that enable processing, visualization and in-depth investigation of Hi-C data in R, ensuring intuitive integration of Hi-C data in the existing Bioconductor ecosystem. We introduce a high-level HiCExperiment data structure to represent Hi-C data, directly extending robust, pre-existing core genomic classes offered by Bioconductor. This guarantees a stable and intuitive Hi-C data representation in R as a genomic entity, which is highly interoperable and can be used by all existing analysis packages in R.\n\nOn top of the HiCExperiment data structure, the HiContacts package offers extended functionalities to perform matrix-centric and interaction-centric analysis directly on HiCExperiment objects and provides powerful visualization tools specifically designed for Hi-C data to facilitate exploratory data analysis. In addition, the HiCool package implements a processing workflow based on a lightweight library to process raw Hi-C data into binned Hi-C contact matrices ready to be imported as HiCExperiment objects. Finally, the fourDNData and DNAZooData packages offer a gateway to major public data repositories directly in R.\n\n\nPackage status\n\n\n\nGithub repo πŸ’Ύ\nDoc πŸ“˜\nGithub checks βœ…\nBioc builds πŸ—\nLifecycle 🌱\n\n\n\n\nHiCExperiment\nDoc\n\nBioc release: Bioc devel:\n\n\n\nHiContacts\nDoc\n\nBioc release: Bioc devel:\n\n\n\nHiCool\nDoc\n\nBioc release: Bioc devel:\n\n\n\nHiContactsData\nDoc\n\nBioc release: Bioc devel:\n\n\n\nDNAZooData\nDoc\n\nBioc release: Bioc devel:\n\n\n\nfourDNData\nDoc\n\nBioc release: Bioc devel:\n\n\n\n\n\n\nReferences\n\n\n\n\nAbdennur, N., & Mirny, L. A. (2019). Cooler: Scalable storage for hi-c data and other genomically labeled arrays. Bioinformatics, 36(1), 311–316. https://doi.org/10.1093/bioinformatics/btz540\n\n\nDurand, N. C., Shamim, M. S., Machol, I., Rao, S. S. P., Huntley, M. H., Lander, E. S., & Aiden, E. L. (2016). Juicer provides a one-click system for analyzing loop-resolution hi-c experiments. Cell Systems, 3(1), 95–98. https://doi.org/10.1016/j.cels.2016.07.002\n\n\nServant, N., Varoquaux, N., Lajoie, B. R., Viara, E., Chen, C.-J., Vert, J.-P., Heard, E., Dekker, J., & Barillot, E. (2015). HiC-pro: An optimized and flexible pipeline for hi-c data processing. Genome Biology, 16(1). https://doi.org/10.1186/s13059-015-0831-x\n\n\n\n\n Back to top" + }, + { + "objectID": "pages/principles.html", + "href": "pages/principles.html", + "title": "\n1Β  Hi-C pre-processing steps\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/principles.html#experimental-considerations", + "href": "pages/principles.html#experimental-considerations", + "title": "\n1Β  Hi-C pre-processing steps\n", + "section": "\n1.1 Experimental considerations", + "text": "1.1 Experimental considerations\n\n1.1.1 Experimental approach\nThe Hi-C procedure (Lieberman-Aiden et al. (2009)) stems from the clever combination of high-throughput sequencing and Chromatin Conformation Capture (3C) experimental approach (Dekker et al. (2002)).\nIn Hi-C, chromatin is crosslinked within intact nuclei and enzymatically digested (usually with one or several restriction enzymes, but Hi-C variants using MNase or DNase exist). End-repair introduces biotinylated dNTPs and is followed by religation, which generates chimeric DNA fragments consisting of genomic loci originally lying in spatial proximity, usually crosslinked to a shared protein complex. After religation, DNA fragments are sheared, biotin-containing fragments are pulled-down and converted into a sequencing library.\n\n\n1.1.2 C variants\nA number of C variants have been proposed since the publication of the original 3C method (reviewed by Davies et al. (2017)), the main ones being Capture-C and ChIA-PET (see procedure below).\n\nCapture-C is useful to quantify interactions between a set of regulatory elements of interest. ChIA-PET, on the other hand, can identify interactions mediated by a specific protein of interest. Finally, an increasing number of Hi-C approaches rely on long-read sequencing (e.g. Deshpande et al. (2022), Tavares-Cadete et al. (2020)) to identify clusters of 3D contacts.\n\n1.1.3 Sequencing\nHi-C libraries are traditionally sequenced with short-read technology, and are by essence paired-end libraries. For this reason, the end result of the experimental side of the Hi-C consists of two fastq files, each one containing sequences for one extremity of the DNA fragments purified during Hi-C. These are the two files we need to move on to the computational side of Hi-C.\nFastq files are plain text files (usually compressed, with the .gz extension). They are generated by the sequencing machine during a sequencing run, and for Hi-C, necessarily come in pairs, generally called *_R1.fq.gz and *_R2.fq.gz.\nHere is the first read listed in sample_R1.fq.gz file:\n\n\nsample-R1.fq.gz\n\n@SRR5399542.1.1 DH1DQQN1:393:H9GEWADXX:1:1101:1187:2211 length=24\nCAACTTCAATACCAGCAGCAGCAA\n+\nCCCFFFFFHHHHHJJJJJIJJJJJ\n\nAnd here is the first read listed in sample_R2.fq.gz file:\n\n\nsample-R2.fq.gz\n\n@SRR5399542.1.1 DH1DQQN1:393:H9GEWADXX:1:1101:1187:2211 length=24\nGCTGTTGTTGTTGTTGTATTTGCA\n+\n@@@FFFFFFHHHHIJJIJJHIIEH\n\nThese two reads are the first listed in their respective file. Notice how they bear the same name (first line): they form a pair. The second line corresponds to the sequence read by the sequencer, the third line is a single + separator, and the last line indicates the per-base sequencing quality following a nebulous cypher." + }, + { + "objectID": "pages/principles.html#hi-c-file-formats", + "href": "pages/principles.html#hi-c-file-formats", + "title": "\n1Β  Hi-C pre-processing steps\n", + "section": "\n1.2 Hi-C file formats", + "text": "1.2 Hi-C file formats\nTwo important output files are typically generated during Hi-C data pre-processing:\n\nA β€œpairs” file;\nA binned β€œcontact matrix” file\n\nWe will now describe the structure of these different types of files. Directly jump to the next chapter if you want to know more about importing data from a contact matrix or a pairs file in R.\n\n1.2.1 Pairs files\nA β€œpairs” file (optionally, but generally filtered and sorted) is the direct output of processing Hi-C fastq files. It stores information about putative proximity contacts identified by digestion/religation, in the lossless, human-readable, indexable format: the .pairs format.\nA .pairs file is organized in a header followed by a body:\n\n\nheader: starts with #\n\nRequired entries\n\nFirst line: ## pairs format v1.0\n\n\n#columns: column contents and ordering (e.g.Β #columns: readID chr1 pos1 chr2 pos2 strand1 strand2 <column_name> <column_name> ...)\n\n#chromsize: chromosome names and their size in bp, one chromosome per line, in the same order that defines ordering between mates (e.g.Β #chromsize: chr1 230218). Chromosome order is actually defined by this header, not by the order of pairs listed in the body!\n\n\nOptional entries with reserved header keys (sorted, shape, command, genome_assembly)\n\n\n#sorted: to indicate the sorting mechanism (e.g.Β #sorted: chr1-chr2-pos1-pos2, #sorted: chr1-pos1, #sorted: none)\n\n#shape: to specify whether the matrix is stored as upper triangle or lower triangle (#shape: upper triangle, #shape: lower triangle)\n\n#command: to specify any command, e.g.Β the command used to generate the pairs file (#command: bam2pairs mysample.bam mysample)\n\n#genome_assembly: to specify the genome assembly (e.g.Β #genome_assembly: hg38)\n\n\n\n\n\nbody: tab-separated columns\n\n7 reserved (4 of them required) columns:\n\nreadID, chr1, pos1, chr2, pos2, strand1, strand2\nColumns 2-5 (chr1, pos1, chr2, pos2) are required and cannot have missing values\nFor column 1, 6 & 7: missing values are annotated with a single-character dummy (.)\n\n\n2 extra reserved, optional column names:\n\n\nfrag1, frag2: restriction enzyme fragment index used by Juicer\n\n\n\nAny number of optional columns can be added\n\n\n\n\n\nsample.pairs\n\n## pairs format v1.0\n#sorted: chr1-chr2-pos1-pos2\n#shape: upper triangle\n#genome_assembly: hg38\n#chromsize: chr1 249250621\n#chromsize: chr2 243199373\n#chromsize: chr3 198022430\n...\n#columns: readID chr1 pos1 chr2 pos2 strand1 strand2\nEAS139:136:FC706VJ:2:2104:23462:197393 chr1 10000 chr1 20000 + +\nEAS139:136:FC706VJ:2:8762:23765:128766 chr1 50000 chr1 70000 + +\nEAS139:136:FC706VJ:2:2342:15343:9863 chr1 60000 chr2 10000 + +\nEAS139:136:FC706VJ:2:1286:25:275154 chr1 30000 chr3 40000 + -\n\nMore information about the conventions related to this text file are provided by the 4DN consortium, which originally formalized the specifications of this file format.\n\n1.2.2 Binned contact matrix files\n\n1.2.2.1 Binning pairs into a matrix\nThe action of β€œbinning” a .pairs file into a contact matrix consists in (1) discretizing a genome reference into genomic bins, (2) attributing bins for each pair’s extremity and (3) computing the interaction frequency between any pair of genomic bins, i.e.Β the β€œcontact matrix”.\nFor instance, here is a dummy .pairs file with a total of 5 pairs:\n\n\ndummy.pairs\n\n## pairs format v1.0\n#sorted: chr1-chr2-pos1-pos2\n#columns: readID chr1 pos1 chr2 pos2 strand1 strand2\n#chromsize: chr1 389\n. chr1 162 chr1 172 . . \n. chr1 180 chr1 192 . . \n. chr1 183 chr1 254 . .\n. chr1 221 chr1 273 . . \n. chr1 254 chr1 298 . . \n\nNote that this genome reference is made of a single chromosome (chr1), very short (length of 389). By binning this chromosome in 100bp-wide bins (100 bp is the resolution), one would optain the following four bins:\n\n\nbins.bed\n\n<chr> <pos> <bin>\nchr1 1 100\nchr1 101 200\nchr1 201 300\nchr1 301 389\n\nEach pair extremity can be changed to an integer indicating the position of the bin it falls in, e.g.Β for the left-hand extremity of the pairs file printed hereinabove (bin1):\n<chr1> <pos1> -> <bin1>\nchr1 162 -> 2\nchr1 180 -> 2\nchr1 183 -> 2\nchr1 221 -> 3\nchr1 254 -> 3\nSimilarly for the right-hand extremity of the pairs file (bin2):\n<chr2> <pos2> -> <bin2>\nchr1 172 -> chr1 2\nchr1 192 -> chr1 2\nchr1 254 -> chr1 3\nchr1 273 -> chr1 3\nchr1 298 -> chr1 3\nBy pasting side-to-side the left-hand and right-hand extremities of each pair, the .pairs file can be turned into something like:\n<bin1> <bin2>\n2 2\n2 2\n2 3\n3 3\n3 3\nAnd if we now count the number of each <bin1> <bin2> combinaison, adding a third <count> column, we end up with a count.matrix text file:\n\n\ncount.matrix\n\n<bin1> <bin2> <count>\n2 2 2\n2 3 1\n3 3 2\n\nThis count.matrix file lists a total of 5 pairs, and in which bin each extremity of each pair is contained. Thus, a count matrix is a lossy file format, as it β€œrounds up” the position of each pair’s extremity to the genomic bin containing it.\nThis β€œi-j-x” 3-column format, in which i-j relate to a pair of β€œcoordinates” indices (or a pair of genomic bin indices) in a matrix, and x relates to a score associated with the pair of indices, is generally called a β€œCOO sparse matrix”.\nIn this context, the regions.bed acts as a secondary β€œdictionary” describing the nature of i and j indices, i.e.Β the location of genomic bins.\n\n1.2.2.2 Plain-text matrices: HiC-Pro style\nThe HiC-Pro pipeline (Servant et al. (2015)) outputs 2 text files: a regions.bed file and a count.matrix file. They are generated by the exact process explained above.\nTogether, these two files can describe the interaction frequency between any pair of genomic loci. They are non-binarized text files, and as such are technically human-readable. However, it is relatively hard to get a grasp of these files compared to a plain .pairs file, as information regarding genomic bins and interaction frequencies are stored in separate files. Moreover, because they are non-binarized, these files often end up using a large disk space and cannot be easily indexed. This prevents easy subsetting of the data stored in these files.\n.(m)cool and .hic file formats are two standards addressing these limitations.\n\n1.2.2.3 .(m)cool matrices\nThe .cool format has been formally defined in Abdennur & Mirny (2019) and is a particular type of HDF5 (Hierarchical Data Format) file. It is an indexed archive file storing rectangular tables called:\n\n\nbins: containing the same information than the regions.bed file;\n\npixels: containing the same information than the count.matrix (each β€œpixel” is a pair of 2 bins and has one or several associated scores);\n\nchroms: summarizing the order and length of the chromosomes present in a Hi-C contact matrix;\n\nindexes: allowing random access, i.e.Β parsing of only a subset of the data without having to read through the entire set of data.\n\n\nA single .pairs file binned at different resolutions can also be saved into a single, multi-resolution .mcool file. .mcool essentially consists of nested .cool files.\nImportantly, as an HDF5-based format, .cool files are binarized, indexed and highly-compressed. This has two major benefits:\n\nSmaller disk storage footprint\n\nRapid subsetting of the data through random access\n\n\nMoreover, parsing .cool files is possible using HDF standard APIs.\n\n1.2.2.4 .hic matrices\nThe .hic format is another type of binarized, indexed and highly-compressed file (Durand et al. (2016)). It can store virtually the same information than a .cool file. However, parsing .hic files is not as straightforward as .cool files, as it does not rely on a generic file standard. Still, the straw library has been implemented in several computing languages to facilitate parsing of .hic files (Durand et al. (2016))." + }, + { + "objectID": "pages/principles.html#pre-processing-hi-c-data", + "href": "pages/principles.html#pre-processing-hi-c-data", + "title": "\n1Β  Hi-C pre-processing steps\n", + "section": "\n1.3 Pre-processing Hi-C data", + "text": "1.3 Pre-processing Hi-C data\n\n1.3.1 Processing workflow\nFundamentally, the main steps performed to pre-process Hi-C are:\n\nSeparate read mapping\nPairs parsing\nPairs sorting\nPairs filtering\nPairs binning into a contact matrix\nNormalization of contact matrix and multi-resolution matrix generation\n\n\nIn practice, a minimal workflow to pre-process Hi-C data is the following (adapted from Open2C et al. (2023)):\n\n## Note these fields have to be replaced by appropriate variables: \n## <index>\n## <input.R1.fq.gz>\n## <input.R2.fq.gz>\n## <chromsizes.txt>\n## <prefix>\nbwa mem2 -SP5M <index> <input.R1.fq.gz> <input.R2.fq.gz> \\\n | pairtools parse -c <chromsizes.txt> \\\n | pairtools sort \\\n | pairtools dedup \\\n | cooler cload pairs -c1 2 -p1 3 -c2 4 -p2 5 <chromsizes.txt>:10000 - <prefix>.cool\ncooler zoomify --balance --nproc 32 --resolutions 5000N --out <prefix>.mcool <prefix>.cool\n\nSeveral pipelines have been developed to facilitate Hi-C data pre-processing. A few of them stand out from the crowd:\n\n\nnf-distiller: a combination of an aligner + pairtools + cooler\n\n\nHiC-pro (Servant et al. (2015))\n\nJuicer (Durand et al. (2016))\n\n\n\n\n\n\n\nNote\n\n\n\nFor larger genomes (> 1Gb) with more than few tens of M of reads per fastq (e.g.Β > 100M), we recommend pre-processing data on an HPC cluster. Aligners, pairs processing and matrix binning can greatly benefit from parallelization over multiple CPUs (Open2C et al. (2023))).\nTo scale up data pre-processing, we recommend to rely on an efficient read mapper such as bwa, followed by pairs parsing, sorting and deduplication with pairtools and binning with cooler.\n\n\n\n1.3.2 hicstuff: lightweight Hi-C pipeline\nhicstuff is an integrated workflow to process Hi-C data. Some advantages compared to solutions mentioned above are its simplicity, flexibility and lightweight. For shallow sequencing or Hi-C on smaller genomes, it efficiently parses fastq reads and processes data into binned contact matrices with a single terminal command.\nhicstuff provides both a command-line interface (CLI) and a python API to process fastq reads into a binned contact matrix. A processing pipeline can be launched using the standard command pipeline as follows:\n\n## Note these fields have to be replaced by appropriate variables: \n## <hicstuff-options>\n## <genome.fa>\n## <input.R1.fq.gz>\n## <input.R2.fq.gz>\nhicstuff pipeline \\\n <hicstuff-options> \\\n --genome <genome.fa> \\\n <input.R1.fq.gz> \\\n <input.R2.fq.gz> \n\nhicstuff documentation website is available here: https://hicstuff.readthedocs.io/ to read more about available options and internal processing steps.\n\n1.3.3 HiCool: hicstuff within R\nhicstuff is available as a standalone (conda install -c bioconda hicstuff it!). It is also shipped in an R package: HiCool. Thus, HiCool can process fastq files directly within an R console.\n\n1.3.3.1 Executing HiCool\nTo demonstrate this, we first fetch example .fastq files:\n\nlibrary(HiContactsData)\nr1 <- HiContactsData(sample = 'yeast_wt', format = 'fastq_R1')\nr2 <- HiContactsData(sample = 'yeast_wt', format = 'fastq_R2')\n\nWe then load the HiCool library and execute the main HiCool function.\n\nlibrary(HiCool)\nHiCool(\n r1, \n r2, \n restriction = 'DpnII,HinfI', \n resolutions = c(4000, 8000, 16000), \n genome = 'R64-1-1', \n output = './HiCool/'\n)\n\n\n1.3.3.2 HiCool arguments\nSeveral arguments can be passed to HiCool and some are worth mentioning them:\n\n\nrestriction: (default: \"DpnII,HinfI\")\n\n\nresolutions: (default: NULL, automatically inferring resolutions based on genome size)\n\n\niterative: (default: TRUE)\n\n\nfilter: (default: TRUE)\n\n\nbalancing_args: (default: \" --cis-only --min-nnz 3 --mad-max 7 \")\n\n\nthreads: (default: 1L)\n\nOther HiCool arguments can be listed by checking HiCool documentation in R: ?HiCool::HiCool.\n\n1.3.3.3 HiCool outputs\nWe can check the generated output files placed in the HiCool/ directory.\n\nfs::dir_tree('HiCool/')\n\n\nThe *.pairs and *.mcool files are the pairs and contact matrix files, respectively. These are the output files the end-user is generally looking for.\n\nThe *.html file is a report summarizing pairs numbers, filtering, etc…\nThe *.log file contains all output and error messages, as well as the full list of commands that have been executed to pre-process the input dataset.\nThe *.pdf graphic files provide a visual representation of the distribution of informative/non-informative pairs.\n\n\n\n\n\n\n\nTip\n\n\n\nAll the files generated by a single HiCool pipeline execution contain the same 6-letter unique hash to make sure they are not overwritten if re-executing the same command." + }, + { + "objectID": "pages/principles.html#exploratory-data-analysis-of-processed-hi-c-files", + "href": "pages/principles.html#exploratory-data-analysis-of-processed-hi-c-files", + "title": "\n1Β  Hi-C pre-processing steps\n", + "section": "\n1.4 Exploratory data analysis of processed Hi-C files", + "text": "1.4 Exploratory data analysis of processed Hi-C files\nOnce Hi-C raw data has been transformed into a set of processed files, exploratory data analysis is typically conducted following two main routes:\n\nData visualization;\nData investigation.\n\nDuring the last decade, a number of softwares have been developed to unlock Hi-C data visualization and investigation. Here we provide a non-exhaustive list of notable tools developed throughout the recent years for downstream Hi-C analysis, selected from this longer list.\n\n\n2012-2015:\n\nHiTC (2012)\nHiCCUPS (2014)\nHiCseg (2014)\nFit-Hi-C (2014)\nHiC-Pro (2015)\ndiffHic (2015)\ncooltools (2015)\nHiCUP (2015)\nHiCPlotter (2015)\nHiFive (2015)\n\n\n\n2016-2019:\n\nCHiCAGO (2016)\nTADbit (2017)\nHiCRep (2017)\nHiC-DC (2017)\nGoTHIC (2017)\nHiCExplorer (2018)\nBoost-HiC (2018)\nHiCcompare (2018)\nHiPiler (2018)\ncoolpuppy (2019)\n\n\n\n2020-present:\n\nSerpentine (2020)\nCHESS (2020)\nDeepHiC (2020)\nChromosight (2020)\nMustache (2020)\nTADcompare (2020)\nPOSSUM (2021)\nCalder (2021)\nHICDCPlus (2021)\nplotgardener (2021)\nGENOVA (2021)\n\n\n\nAll references as well as many other softwares and references are available here." + }, + { + "objectID": "pages/data-representation.html", + "href": "pages/data-representation.html", + "title": "\n2Β  Hi-C data structures in R\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/data-representation.html#granges-class", + "href": "pages/data-representation.html#granges-class", + "title": "\n2Β  Hi-C data structures in R\n", + "section": "\n2.1 GRanges class", + "text": "2.1 GRanges class\nGRanges is a shorthand for GenomicRanges, a core class in Bioconductor. This class is primarily used to describe genomic ranges of any nature, e.g.Β  sets of promoters, SNPs, chromatin loop anchors, ….\nThe data structure has been published in the seminal 2015 publication by the Bioconductor team (Huber et al. (2015)).\n\n2.1.1 GRanges fundamentals\nThe easiest way to generate a GRanges object is to coerce it from a vector of genomic coordinates in the UCSC format (e.g.Β \"chr2:2004-4853\"):\n\nlibrary(GenomicRanges)\ngr <- GRanges(c(\n \"chr2:2004-7853:+\", \n \"chr4:4482-9873:-\", \n \"chr5:1943-4203:+\", \n \"chr5:4103-5004:+\" \n))\ngr\n## GRanges object with 4 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr2 2004-7853 +\n## [2] chr4 4482-9873 -\n## [3] chr5 1943-4203 +\n## [4] chr5 4103-5004 +\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\nA single GRanges object can contain one or several β€œranges”, or genomic intervals. To navigate between these ranges, GRanges can be subset using the standard R single bracket notation [:\n\ngr[1]\n## GRanges object with 1 range and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr2 2004-7853 +\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\ngr[1:3]\n## GRanges object with 3 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr2 2004-7853 +\n## [2] chr4 4482-9873 -\n## [3] chr5 1943-4203 +\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\nGenomicRanges objects aim to provide a natural description of genomic intervals (ranges) and are incredibly versatile. They extend the data.frame object and have four required pieces of information:\n\n\nseqnames (i.e.Β chromosome names) (accessible with seqnames())\n\nstart (accessible with start())\n\nend (accessible with end())\n\nstrand (accessible with strand())\n\n\nseqnames(gr)\n## factor-Rle of length 4 with 3 runs\n## Lengths: 1 1 2\n## Values : chr2 chr4 chr5\n## Levels(3): chr2 chr4 chr5\n\nstart(gr)\n## [1] 2004 4482 1943 4103\n\nend(gr)\n## [1] 7853 9873 4203 5004\n\nstrand(gr)\n## factor-Rle of length 4 with 3 runs\n## Lengths: 1 1 2\n## Values : + - +\n## Levels(3): + - *\n\nHere is a graphical representation of a GRanges object, taken from Bioconductor course material:\n\nWe will now delve into the detailed structure and operability of GRanges objects.\n\n2.1.2 GRanges metadata\nAn important aspect of GRanges objects is that each entry (range) can have extra optional metadata. This metadata is stored in a rectangular DataFrame. Each column can contain a different type of information, e.g.Β a numerical vector, a factor, a list, …\nOne can directly access this DataFrame using the mcols() function, and individual columns of metadata using the $ notation:\n\nmcols(gr)\n## DataFrame with 4 rows and 0 columns\nmcols(gr)$GC <- c(0.45, 0.43, 0.44, 0.42)\nmcols(gr)$annotation <- factor(c(NA, 'promoter', 'enhancer', 'centromere'))\nmcols(gr)$extended.info <- c(\n list(c(NA)), \n list(c(date = 2023, source = 'manual')), \n list(c(date = 2021, source = 'manual')), \n list(c(date = 2019, source = 'homology'))\n)\nmcols(gr)\n## DataFrame with 4 rows and 3 columns\n## GC annotation extended.info\n## <numeric> <factor> <list>\n## 1 0.45 NA NA\n## 2 0.43 promoter 2023,manual\n## 3 0.44 enhancer 2021,manual\n## 4 0.42 centromere 2019,homology\n\nWhen metadata columns are defined for a GRanges object, they are pasted next to the minimal 4 required GRanges fields, separated by a | character.\n\ngr\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2004-7853 + | 0.45 NA <NA>\n## [2] chr4 4482-9873 - | 0.43 promoter 2023,manual\n## [3] chr5 1943-4203 + | 0.44 enhancer 2021,manual\n## [4] chr5 4103-5004 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n\n2.1.3 Genomic arithmetics on individual GRanges objects\nA GRanges object primarily describes a set of genomic ranges (it is in the name!). Useful genomic-oriented methods have been implemented to investigate individual GRanges object from a genomic perspective.\n\n2.1.3.1 Intra-range methods\nStandard genomic arithmetics are possible with GRanges, e.g.Β  shifting ranges, resizing, trimming, … These methods are referred to as β€œintra-range” methods as they work β€œone-region-at-a-time”.\n\n\n\n\n\n\nNote\n\n\n\n\nEach range of the input GRanges object is modified independently from the other ranges in the following code chunks.\nIntra-range operations are endomorphisms: they all take GRanges inputs and always return GRanges objects.\n\n\n\n\nShifting each genomic range in a GRanges object by a certain number of bases:\n\n\ngr\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2004-7853 + | 0.45 NA <NA>\n## [2] chr4 4482-9873 - | 0.43 promoter 2023,manual\n## [3] chr5 1943-4203 + | 0.44 enhancer 2021,manual\n## [4] chr5 4103-5004 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n# ----- Shift all genomic ranges towards the \"right\" (downstream in `+` strand), by 1000bp:\nshift(gr, 1000)\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 3004-8853 + | 0.45 NA <NA>\n## [2] chr4 5482-10873 - | 0.43 promoter 2023,manual\n## [3] chr5 2943-5203 + | 0.44 enhancer 2021,manual\n## [4] chr5 5103-6004 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n# ----- Shift all genomic ranges towards the \"left\" (upstream in `+` strand), by 1000bp:\nshift(gr, -1000)\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 1004-6853 + | 0.45 NA <NA>\n## [2] chr4 3482-8873 - | 0.43 promoter 2023,manual\n## [3] chr5 943-3203 + | 0.44 enhancer 2021,manual\n## [4] chr5 3103-4004 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n\nNarrowing each genomic range in a GRanges object by a certain number of bases:\n\n\ngr\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2004-7853 + | 0.45 NA <NA>\n## [2] chr4 4482-9873 - | 0.43 promoter 2023,manual\n## [3] chr5 1943-4203 + | 0.44 enhancer 2021,manual\n## [4] chr5 4103-5004 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n# ----- Extract 21st-40th subrange for each range in `gr`:\nnarrow(gr, start = 21, end = 40)\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2024-2043 + | 0.45 NA <NA>\n## [2] chr4 4502-4521 - | 0.43 promoter 2023,manual\n## [3] chr5 1963-1982 + | 0.44 enhancer 2021,manual\n## [4] chr5 4123-4142 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\nwidth(narrow(gr, start = 21, end = 40))\n## [1] 20 20 20 20\n\n\nResizing each genomic range in a GRanges object to a certain number of bases:\n\n\ngr\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2004-7853 + | 0.45 NA <NA>\n## [2] chr4 4482-9873 - | 0.43 promoter 2023,manual\n## [3] chr5 1943-4203 + | 0.44 enhancer 2021,manual\n## [4] chr5 4103-5004 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n# ----- Resize `gr` entries to 100, fixed at the start of each range:\nresize(gr, 100, fix = \"start\")\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2004-2103 + | 0.45 NA <NA>\n## [2] chr4 9774-9873 - | 0.43 promoter 2023,manual\n## [3] chr5 1943-2042 + | 0.44 enhancer 2021,manual\n## [4] chr5 4103-4202 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n# ----- Resize `gr` entries to 100, fixed at the start of each range, disregarding strand information:\nresize(gr, 100, fix = \"start\", ignore.strand = TRUE)\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2004-2103 + | 0.45 NA <NA>\n## [2] chr4 4482-4581 - | 0.43 promoter 2023,manual\n## [3] chr5 1943-2042 + | 0.44 enhancer 2021,manual\n## [4] chr5 4103-4202 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n# ----- Resize `gr` entries to 1 bp, fixed at the center of each range:\nresize(gr, 1, fix = \"center\")\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 4928 + | 0.45 NA <NA>\n## [2] chr4 7177 - | 0.43 promoter 2023,manual\n## [3] chr5 3073 + | 0.44 enhancer 2021,manual\n## [4] chr5 4553 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n\nExtracting flanking coordinates for each entry in gr:\n\n\ngr\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2004-7853 + | 0.45 NA <NA>\n## [2] chr4 4482-9873 - | 0.43 promoter 2023,manual\n## [3] chr5 1943-4203 + | 0.44 enhancer 2021,manual\n## [4] chr5 4103-5004 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n# ----- Extract 100bp UPSTREAM of each genomic range, according to range strandness:\nflank(gr, 100, start = TRUE)\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 1904-2003 + | 0.45 NA <NA>\n## [2] chr4 9874-9973 - | 0.43 promoter 2023,manual\n## [3] chr5 1843-1942 + | 0.44 enhancer 2021,manual\n## [4] chr5 4003-4102 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n# ----- Extract 1bp DOWNSTREAM of each genomic range, according to range strandness:\nflank(gr, 1, start = FALSE)\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 7854 + | 0.45 NA <NA>\n## [2] chr4 4481 - | 0.43 promoter 2023,manual\n## [3] chr5 4204 + | 0.44 enhancer 2021,manual\n## [4] chr5 5005 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\nNote how here again, strand information is crucial and correctly leveraged to extract β€œupstream” or β€œdownstream” flanking regions in agreement with genomic range orientation.\n\nSeveral arithmetics operators can also directly work with GRanges:\n\n\ngr\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2004-7853 + | 0.45 NA <NA>\n## [2] chr4 4482-9873 - | 0.43 promoter 2023,manual\n## [3] chr5 1943-4203 + | 0.44 enhancer 2021,manual\n## [4] chr5 4103-5004 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\ngr + 100 # ----- Extend each side of the `GRanges` by a given number of bases\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 1904-7953 + | 0.45 NA <NA>\n## [2] chr4 4382-9973 - | 0.43 promoter 2023,manual\n## [3] chr5 1843-4303 + | 0.44 enhancer 2021,manual\n## [4] chr5 4003-5104 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\ngr - 200 # ----- Shrink each side of the `GRanges` by a given number of bases \n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 2204-7653 + | 0.45 NA <NA>\n## [2] chr4 4682-9673 - | 0.43 promoter 2023,manual\n## [3] chr5 2143-4003 + | 0.44 enhancer 2021,manual\n## [4] chr5 4303-4804 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\ngr * 1000 # ----- Zoom in by a given factor (effectively decreasing the `GRanges` width by the same factor)\n## GRanges object with 4 ranges and 3 metadata columns:\n## seqnames ranges strand | GC annotation extended.info\n## <Rle> <IRanges> <Rle> | <numeric> <factor> <list>\n## [1] chr2 4926-4930 + | 0.45 NA <NA>\n## [2] chr4 7175-7179 - | 0.43 promoter 2023,manual\n## [3] chr5 3072-3073 + | 0.44 enhancer 2021,manual\n## [4] chr5 4554-4553 + | 0.42 centromere 2019,homology\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n\n\n\n\n\n\nGoing further\n\n\n\nTo fully grasp how to operate GRanges objects, we highly recommend reading the detailed documentation for this class by typing ?GenomicRanges and ?GenomicRanges::`intra-range-methods`.\n\n\n\n2.1.3.2 Inter-range methods\nCompared to β€œintra-range” methods described above, inter-range methods involve comparisons between ranges in a single GRanges object.\n\n\n\n\n\n\nNote\n\n\n\nCompared to previous section, the result of each function described below depends on the entire set of ranges in the input GRanges object.\n\n\n\nComputing the β€œinverse” genomic ranges, i.e.Β ranges in-between the input ranges:\n\n\ngaps(gr)\n## GRanges object with 3 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr2 1-2003 +\n## [2] chr4 1-4481 -\n## [3] chr5 1-1942 +\n## -------\n## seqinfo: 3 sequences from an unspecified genome; no seqlengths\n\n\nFor each entry in a GRanges, finding the index of the preceding/following/nearest genomic range:\n\n\nprecede(gr)\n## [1] NA NA NA NA\n\nfollow(gr)\n## [1] NA NA NA NA\n\nnearest(gr)\n## [1] NA NA 4 3\n\n\nComputing a coverage over a genome, optionally indicated a β€œscore” column from metadata:\n\n\ncoverage(gr, weight = 'GC')\n## RleList of length 3\n## $chr2\n## numeric-Rle of length 7853 with 2 runs\n## Lengths: 2003 5850\n## Values : 0.00 0.45\n## \n## $chr4\n## numeric-Rle of length 9873 with 2 runs\n## Lengths: 4481 5392\n## Values : 0.00 0.43\n## \n## $chr5\n## numeric-Rle of length 5004 with 4 runs\n## Lengths: 1942 2160 101 801\n## Values : 0.00 0.44 0.86 0.42\n\n\n\n\n\n\n\nGoing further\n\n\n\nTo fully grasp how to operate GRanges objects, we highly recommend reading the detailed documentation for this class by typing ?GenomicRanges::`inter-range-methods`.\n\n\n\n2.1.4 Comparing multiple GRanges objects\nGenomic analysis typically requires intersection of two sets of genomic ranges, e.g.Β to find which ranges from one set overlap with those from another set.\nIn the next examples, we will use two GRanges:\n\n\npeaks represents dummy 8 ChIP-seq peaks\n\n\npeaks <- GRanges(c(\n 'chr1:320-418',\n 'chr1:512-567',\n 'chr1:843-892',\n 'chr1:1221-1317', \n 'chr1:1329-1372', \n 'chr1:1852-1909', \n 'chr1:2489-2532', \n 'chr1:2746-2790'\n))\npeaks\n## GRanges object with 8 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 320-418 *\n## [2] chr1 512-567 *\n## [3] chr1 843-892 *\n## [4] chr1 1221-1317 *\n## [5] chr1 1329-1372 *\n## [6] chr1 1852-1909 *\n## [7] chr1 2489-2532 *\n## [8] chr1 2746-2790 *\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\n\n\nTSSs represents dummy 3 gene promoters (Β± 10bp around the TSS)\n\n\ngenes <- GRanges(c(\n 'chr1:358-1292:+',\n 'chr1:1324-2343:+', \n 'chr1:2732-2751:+'\n))\nTSSs <- resize(genes, width = 1, fix = 'start') + 10\nTSSs\n## GRanges object with 3 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 348-368 +\n## [2] chr1 1314-1334 +\n## [3] chr1 2722-2742 +\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\nLet’s see how they overlap by plotting them:\n\nlibrary(ggplot2)\npeaks$type <- 'peaks'\nTSSs$type <- 'TSSs'\nggplot() + \n ggbio::geom_rect(c(peaks, TSSs), aes(fill = type), facets = type~.) + \n ggbio::theme_alignment() + \n coord_fixed(ratio = 300)\n## Registered S3 method overwritten by 'GGally':\n## method from \n## +.gg ggplot2\n## Warning: The `facets` argument of `facet_grid()` is deprecated as of ggplot2 2.2.0.\n## β„Ή Please use the `rows` argument instead.\n## β„Ή The deprecated feature was likely used in the ggbio package.\n## Please report the issue at <https://github.com/lawremi/ggbio/issues>.\n## Scale for y is already present.\n## Adding another scale for y, which will replace the existing scale.\n\n\n\n\n\n\n\n\n2.1.4.1 Finding overlaps between two GRanges sets\n\nFinding overlaps between a query and a subject\n\nIn our case, we want to identify which ChIP-seq peaks overlap with a TSS: the query is the set of peaks and the subject is the set of TSSs.\nfindOverlaps returns a Hits object listing which query ranges overlap with which subject ranges.\n\nov <- findOverlaps(query = peaks, subject = TSSs)\nov\n## Hits object with 3 hits and 0 metadata columns:\n## queryHits subjectHits\n## <integer> <integer>\n## [1] 1 1\n## [2] 4 2\n## [3] 5 2\n## -------\n## queryLength: 8 / subjectLength: 3\n\nThe Hits output clearly describes what overlaps with what:\n\nThe query (peak) #1 overlaps with subject (TSS) #1\n\nThe query (peak) #5 overlaps with subject (TSS) #2\n\n\n\n\n\n\n\n\nNote\n\n\n\nBecause no other query index or subject index is listed in the ov output, none of the remaining ranges from query overlap with ranges from subject.\n\n\n\nSubsetting by overlaps between a query and a subject\n\nTo directly subset ranges from query overlapping with ranges from a subject (e.g.Β to only keep peaks overlapping a TSS), we can use the subsetByOverlaps function. The output of subsetByOverlaps is a subset of the original GRanges object provided as a query, with retained ranges being unmodified.\n\nsubsetByOverlaps(peaks, TSSs)\n## GRanges object with 3 ranges and 1 metadata column:\n## seqnames ranges strand | type\n## <Rle> <IRanges> <Rle> | <character>\n## [1] chr1 320-418 * | peaks\n## [2] chr1 1221-1317 * | peaks\n## [3] chr1 1329-1372 * | peaks\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\n\nCounting overlaps between a query and a subject\n\nFinally, the countOverlaps is used to count, for each range in a query, how many ranges in the subject it overlaps with.\n\ncountOverlaps(query = peaks, subject = TSSs)\n## [1] 1 0 0 1 1 0 0 0\n\n\n\n\n\n\n\nNote\n\n\n\nNote that which GRanges goes in query or subject is crucial! Counting for each peak, the number of TSSs it overlaps with is very different from for each TSS, how many peaks it overlaps with.\nIn our case example, it would also be informative to count how many peaks overlap with each TSS, so we’d need to swap query and subject:\n\ncountOverlaps(query = TSSs, subject = peaks)\n## [1] 1 2 0\n\nWe can add these counts to the original query object:\n\nTSSs$n_peaks <- countOverlaps(query = TSSs, subject = peaks)\nTSSs\n## GRanges object with 3 ranges and 2 metadata columns:\n## seqnames ranges strand | type n_peaks\n## <Rle> <IRanges> <Rle> | <character> <integer>\n## [1] chr1 348-368 + | TSSs 1\n## [2] chr1 1314-1334 + | TSSs 2\n## [3] chr1 2722-2742 + | TSSs 0\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\n\n\n\n\n%over%, %within%, %outside% : handy operators\n\nHandy operators exist that return logical vectors (same length as the query). They essentially are short-hands for specific findOverlaps() cases.\n<query> %over% <subject>:\n\npeaks %over% TSSs\n## [1] TRUE FALSE FALSE TRUE TRUE FALSE FALSE FALSE\n\npeaks[peaks %over% TSSs] # ----- Equivalent to `subsetByOverlaps(peaks, TSSs)`\n## GRanges object with 3 ranges and 1 metadata column:\n## seqnames ranges strand | type\n## <Rle> <IRanges> <Rle> | <character>\n## [1] chr1 320-418 * | peaks\n## [2] chr1 1221-1317 * | peaks\n## [3] chr1 1329-1372 * | peaks\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\n<query> %within% <subject>:\n\npeaks %within% TSSs\n## [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE\n\nTSSs %within% peaks\n## [1] TRUE FALSE FALSE\n\n<query> %outside% <subject>:\n\npeaks %outside% TSSs\n## [1] FALSE TRUE TRUE FALSE FALSE TRUE TRUE TRUE\n\n\n\n\n\n\n\nGoing further\n\n\n\nTo fully grasp how to find overlaps between GRanges objects, we highly recommend reading the detailed documentation by typing ?IRanges::`findOverlaps-methods`.\n\n\n\n2.1.4.2 Find nearest range from a subject for each range in a query\n*Overlaps methods are not always enough to match a query to a subject. For instance, some peaks in the query might be very near to some TSSs in the subject, but not quite overlapping.\n\npeaks[8]\n## GRanges object with 1 range and 1 metadata column:\n## seqnames ranges strand | type\n## <Rle> <IRanges> <Rle> | <character>\n## [1] chr1 2746-2790 * | peaks\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\nTSSs[3]\n## GRanges object with 1 range and 2 metadata columns:\n## seqnames ranges strand | type n_peaks\n## <Rle> <IRanges> <Rle> | <character> <integer>\n## [1] chr1 2722-2742 + | TSSs 0\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\n\nnearest()\n\nRather than finding the overlapping range in a subject for each range in a query, we can find the nearest range.\nFor each range in the query, this returns the index of the range in the subject to which the query is the nearest.\n\nnearest(peaks, TSSs)\n## [1] 1 1 2 2 2 2 3 3\n\nTSSs[nearest(peaks, TSSs)]\n## GRanges object with 8 ranges and 2 metadata columns:\n## seqnames ranges strand | type n_peaks\n## <Rle> <IRanges> <Rle> | <character> <integer>\n## [1] chr1 348-368 + | TSSs 1\n## [2] chr1 348-368 + | TSSs 1\n## [3] chr1 1314-1334 + | TSSs 2\n## [4] chr1 1314-1334 + | TSSs 2\n## [5] chr1 1314-1334 + | TSSs 2\n## [6] chr1 1314-1334 + | TSSs 2\n## [7] chr1 2722-2742 + | TSSs 0\n## [8] chr1 2722-2742 + | TSSs 0\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\n\ndistance()\n\nAlternatively, one can simply ask to calculate the distanceToNearest between ranges in a query and ranges in a subject.\n\ndistanceToNearest(peaks, TSSs)\n## Hits object with 8 hits and 1 metadata column:\n## queryHits subjectHits | distance\n## <integer> <integer> | <integer>\n## [1] 1 1 | 0\n## [2] 2 1 | 143\n## [3] 3 2 | 421\n## [4] 4 2 | 0\n## [5] 5 2 | 0\n## [6] 6 2 | 517\n## [7] 7 3 | 189\n## [8] 8 3 | 3\n## -------\n## queryLength: 8 / subjectLength: 3\n\npeaks$distance_to_nearest_TSS <- mcols(distanceToNearest(peaks, TSSs))$distance\n\nNote how close from a TSS the 8th peak was. It could be worth considering this as an overlap!" + }, + { + "objectID": "pages/data-representation.html#ginteractions-class", + "href": "pages/data-representation.html#ginteractions-class", + "title": "\n2Β  Hi-C data structures in R\n", + "section": "\n2.2 GInteractions class", + "text": "2.2 GInteractions class\nGRanges describe genomic ranges and hence are of general use to study 1D genome organization. To study chromatin interactions, we need a way to link pairs of GRanges. This is exactly what the GInteractions class does. This data structure is defined in the InteractionSet package and has been published in the 2016 paper by Lun et al. (Lun et al. (2016)).\n\n\n2.2.1 Building a GInteractions object from scratch\nLet’s first define two parallel GRanges objects (i.e.Β two GRanges of same length). Each GRanges will contain 5 ranges.\n\ngr_first <- GRanges(c(\n 'chr1:1-100', \n 'chr1:1001-2000', \n 'chr1:5001-6000', \n 'chr1:8001-9000', \n 'chr1:7001-8000' \n))\ngr_second <- GRanges(c(\n 'chr1:1-100', \n 'chr1:3001-4000', \n 'chr1:8001-9000', \n 'chr1:7001-8000', \n 'chr2:13000-14000' \n))\n\nBecause these two GRanges objects are of same length (5), one can β€œbind” them together by using the GInteractionsfunction. This effectively associate each entry from one GRanges to the entry aligned in the other GRanges object.\n\nlibrary(InteractionSet)\ngi <- GInteractions(gr_first, gr_second)\ngi\n## GInteractions object with 5 interactions and 0 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2\n## <Rle> <IRanges> <Rle> <IRanges>\n## [1] chr1 1-100 --- chr1 1-100\n## [2] chr1 1001-2000 --- chr1 3001-4000\n## [3] chr1 5001-6000 --- chr1 8001-9000\n## [4] chr1 8001-9000 --- chr1 7001-8000\n## [5] chr1 7001-8000 --- chr2 13000-14000\n## -------\n## regions: 7 ranges and 0 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\nThe way GInteractions objects are printed in an R console mimics that of GRanges, but pairs two β€œends” (a.k.a. anchors) of an interaction together, each end being represented as a separate GRanges range.\n\nNote that it is possible to have interactions joining two identical anchors.\n\n\ngi[1]\n## GInteractions object with 1 interaction and 0 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2\n## <Rle> <IRanges> <Rle> <IRanges>\n## [1] chr1 1-100 --- chr1 1-100\n## -------\n## regions: 7 ranges and 0 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n\nIt is also technically possible (though not advised) to have interactions for which the β€œfirst” end is located after the β€œsecond” end along the chromosome.\n\n\ngi[4]\n## GInteractions object with 1 interaction and 0 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2\n## <Rle> <IRanges> <Rle> <IRanges>\n## [1] chr1 8001-9000 --- chr1 7001-8000\n## -------\n## regions: 7 ranges and 0 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n\nFinally, it is possible to define inter-chromosomal interactions (a.k.a. trans interactions).\n\n\ngi[5]\n## GInteractions object with 1 interaction and 0 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2\n## <Rle> <IRanges> <Rle> <IRanges>\n## [1] chr1 7001-8000 --- chr2 13000-14000\n## -------\n## regions: 7 ranges and 0 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n\n2.2.2 GInteractions specific slots\nCompared to GRanges, extra slots are available for GInteractions objects, e.g. anchors and regions.\n\n2.2.2.1 Anchors\nβ€œAnchors” of a single genomic interaction refer to the two ends of this interaction. These anchors can be extracted from a GInteractions object using the anchors() function. This outputs a list of two GRanges, the first corresponding to the β€œleft” end of interactions (when printed to the console) and the second corresponding to the β€œright” end of interactions (when printed to the console).\n\n# ----- This extracts the two sets of anchors (\"first\" and \"second\") from a GInteractions object\nanchors(gi)\n## $first\n## GRanges object with 5 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 1-100 *\n## [2] chr1 1001-2000 *\n## [3] chr1 5001-6000 *\n## [4] chr1 8001-9000 *\n## [5] chr1 7001-8000 *\n## -------\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n## \n## $second\n## GRanges object with 5 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 1-100 *\n## [2] chr1 3001-4000 *\n## [3] chr1 8001-9000 *\n## [4] chr1 7001-8000 *\n## [5] chr2 13000-14000 *\n## -------\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n# ----- We can query for the \"first\" or \"second\" set of anchors directly\nanchors(gi, \"first\")\n## GRanges object with 5 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 1-100 *\n## [2] chr1 1001-2000 *\n## [3] chr1 5001-6000 *\n## [4] chr1 8001-9000 *\n## [5] chr1 7001-8000 *\n## -------\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\nanchors(gi, \"second\")\n## GRanges object with 5 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 1-100 *\n## [2] chr1 3001-4000 *\n## [3] chr1 8001-9000 *\n## [4] chr1 7001-8000 *\n## [5] chr2 13000-14000 *\n## -------\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n\n2.2.2.2 Regions\nβ€œRegions” of a set of interactions refer to the universe of unique anchors represented in a set of interactions. Therefore, the length of the regions can only be equal to or strictly lower than twice the length of anchors.\nThe regions function returns the regions associated with a GInteractions object, stored as a GRanges object.\n\nregions(gi)\n## GRanges object with 7 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 1-100 *\n## [2] chr1 1001-2000 *\n## [3] chr1 3001-4000 *\n## [4] chr1 5001-6000 *\n## [5] chr1 7001-8000 *\n## [6] chr1 8001-9000 *\n## [7] chr2 13000-14000 *\n## -------\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\nlength(regions(gi))\n## [1] 7\n\nlength(anchors(gi, \"first\"))\n## [1] 5\n\n\n2.2.3 GInteractions methods\nGInteractions behave as an extension of GRanges. For this reason, many methods that work with GRanges will work seamlessly with GInteractions.\n\n2.2.3.1 Metadata\nOne can add metadata columns directly to a GInteractions object.\n\nmcols(gi)\n## DataFrame with 5 rows and 0 columns\nmcols(gi) <- data.frame(\n idx = seq(1, length(gi)),\n type = c(\"cis\", \"cis\", \"cis\", \"trans\", \"cis\")\n)\ngi\n## GInteractions object with 5 interactions and 2 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | idx type\n## <Rle> <IRanges> <Rle> <IRanges> | <integer> <character>\n## [1] chr1 1-100 --- chr1 1-100 | 1 cis\n## [2] chr1 1001-2000 --- chr1 3001-4000 | 2 cis\n## [3] chr1 5001-6000 --- chr1 8001-9000 | 3 cis\n## [4] chr1 8001-9000 --- chr1 7001-8000 | 4 trans\n## [5] chr1 7001-8000 --- chr2 13000-14000 | 5 cis\n## -------\n## regions: 7 ranges and 0 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\ngi$type\n## [1] \"cis\" \"cis\" \"cis\" \"trans\" \"cis\"\n\nImportantly, metadata columns can also be directly added to regions of a GInteractions object, since these regions are a GRanges object themselves!\n\nregions(gi)\n## GRanges object with 7 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 1-100 *\n## [2] chr1 1001-2000 *\n## [3] chr1 3001-4000 *\n## [4] chr1 5001-6000 *\n## [5] chr1 7001-8000 *\n## [6] chr1 8001-9000 *\n## [7] chr2 13000-14000 *\n## -------\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\nregions(gi)$binID <- seq_along(regions(gi))\nregions(gi)$type <- c(\"P\", \"P\", \"P\", \"E\", \"E\", \"P\", \"P\")\nregions(gi)\n## GRanges object with 7 ranges and 2 metadata columns:\n## seqnames ranges strand | binID type\n## <Rle> <IRanges> <Rle> | <integer> <character>\n## [1] chr1 1-100 * | 1 P\n## [2] chr1 1001-2000 * | 2 P\n## [3] chr1 3001-4000 * | 3 P\n## [4] chr1 5001-6000 * | 4 E\n## [5] chr1 7001-8000 * | 5 E\n## [6] chr1 8001-9000 * | 6 P\n## [7] chr2 13000-14000 * | 7 P\n## -------\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n\n2.2.3.2 Sorting GInteractions\n\nThe sort function works seamlessly with GInteractions objects. It sorts the interactions using a similar approach to that performed by pairtools sort ... for disk-stored .pairs files, sorting on the β€œfirst” anchor first, then for interactions with the same β€œfirst” anchors, sorting on the β€œsecond” anchor.\n\ngi\n## GInteractions object with 5 interactions and 2 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | idx type\n## <Rle> <IRanges> <Rle> <IRanges> | <integer> <character>\n## [1] chr1 1-100 --- chr1 1-100 | 1 cis\n## [2] chr1 1001-2000 --- chr1 3001-4000 | 2 cis\n## [3] chr1 5001-6000 --- chr1 8001-9000 | 3 cis\n## [4] chr1 8001-9000 --- chr1 7001-8000 | 4 trans\n## [5] chr1 7001-8000 --- chr2 13000-14000 | 5 cis\n## -------\n## regions: 7 ranges and 2 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\nsort(gi)\n## GInteractions object with 5 interactions and 2 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | idx type\n## <Rle> <IRanges> <Rle> <IRanges> | <integer> <character>\n## [1] chr1 1-100 --- chr1 1-100 | 1 cis\n## [2] chr1 1001-2000 --- chr1 3001-4000 | 2 cis\n## [3] chr1 5001-6000 --- chr1 8001-9000 | 3 cis\n## [4] chr1 7001-8000 --- chr2 13000-14000 | 5 cis\n## [5] chr1 8001-9000 --- chr1 7001-8000 | 4 trans\n## -------\n## regions: 7 ranges and 2 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n\n2.2.3.3 Swapping GInteractions anchors\nFor an individual interaction contained in a GInteractions object, the β€œfirst” and β€œsecond” anchors themselves can be sorted as well. This is called β€œpairs swapping”, and it is performed similarly to pairtools flip ... for disk-stored .pairs files. This ensures that interactions, when represented as a contact matrix, generate an upper-triangular matrix.\n\ngi\n## GInteractions object with 5 interactions and 2 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | idx type\n## <Rle> <IRanges> <Rle> <IRanges> | <integer> <character>\n## [1] chr1 1-100 --- chr1 1-100 | 1 cis\n## [2] chr1 1001-2000 --- chr1 3001-4000 | 2 cis\n## [3] chr1 5001-6000 --- chr1 8001-9000 | 3 cis\n## [4] chr1 8001-9000 --- chr1 7001-8000 | 4 trans\n## [5] chr1 7001-8000 --- chr2 13000-14000 | 5 cis\n## -------\n## regions: 7 ranges and 2 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\nswapAnchors(gi)\n## GInteractions object with 5 interactions and 2 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | idx type\n## <Rle> <IRanges> <Rle> <IRanges> | <integer> <character>\n## [1] chr1 1-100 --- chr1 1-100 | 1 cis\n## [2] chr1 1001-2000 --- chr1 3001-4000 | 2 cis\n## [3] chr1 5001-6000 --- chr1 8001-9000 | 3 cis\n## [4] chr1 7001-8000 --- chr1 8001-9000 | 4 trans\n## [5] chr1 7001-8000 --- chr2 13000-14000 | 5 cis\n## -------\n## regions: 7 ranges and 2 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n\n\n\n\n\n\nNote\n\n\n\nβ€œSorting” and β€œswapping” a GInteractions object are two entirely different actions:\n\nβ€œsorting” reorganizes all rows (interactions);\nβ€œswapping” anchors reorganizes β€œfirst” and β€œsecond” anchors for each interaction independently.\n\n\n\n\n2.2.3.4 GInteractions distance method\nβ€œDistance”, when applied to genomic interactions, typically refers to the genomic distance between the two anchors of a single interaction. For GInteractions, this is computed using the pairdist function.\n\ngi\n## GInteractions object with 5 interactions and 2 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | idx type\n## <Rle> <IRanges> <Rle> <IRanges> | <integer> <character>\n## [1] chr1 1-100 --- chr1 1-100 | 1 cis\n## [2] chr1 1001-2000 --- chr1 3001-4000 | 2 cis\n## [3] chr1 5001-6000 --- chr1 8001-9000 | 3 cis\n## [4] chr1 8001-9000 --- chr1 7001-8000 | 4 trans\n## [5] chr1 7001-8000 --- chr2 13000-14000 | 5 cis\n## -------\n## regions: 7 ranges and 2 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\npairdist(gi)\n## [1] 0 2000 3000 1000 NA\n\nNote that for β€œtrans” inter-chromosomal interactions, i.e.Β interactions with anchors on different chromosomes, the notion of genomic distance is meaningless and for this reason, pairdist returns a NA value.\nThe type argument of the pairdist() function can be tweaked to specify which type of β€œdistance” should be computed:\n\n\nmid: The distance between the midpoints of the two regions (rounded down to the nearest integer) is returned (Default).\n\ngap: The length of the gap between the closest points of the two regions is computed - negative lengths are returned for overlapping regions, indicating the length of the overlap.\n\nspan: The distance between the furthermost points of the two regions is computed.\n\ndiag: The difference between the anchor indices is returned. This corresponds to a diagonal on the interaction space when bins are used in the β€˜regions’ slot of β€˜x’.\n\n2.2.3.5 GInteractions overlap methods\nβ€œOverlaps” for genomic interactions could be computed in different contexts:\n\nCase 1: Overlap between any of the two anchors of an interaction with a genomic range\nCase 2: Overlap between anchors of an interaction with anchors of another interaction\nCase 3: Spanning of the interaction β€œacross” a genomic range\n\n\nCase 1: Overlap between any of the two anchors of an interaction with a genomic range\n\nThis is the default behavior of findOverlaps when providing a GInteractions object as query and a GRanges as a subject.\n\ngr <- GRanges(c(\"chr1:7501-7600\", \"chr1:8501-8600\"))\nfindOverlaps(query = gi, subject = gr)\n## Hits object with 4 hits and 0 metadata columns:\n## queryHits subjectHits\n## <integer> <integer>\n## [1] 3 2\n## [2] 4 1\n## [3] 4 2\n## [4] 5 1\n## -------\n## queryLength: 5 / subjectLength: 2\n\ncountOverlaps(gi, gr)\n## [1] 0 0 1 2 1\n\nsubsetByOverlaps(gi, gr)\n## GInteractions object with 3 interactions and 2 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | idx type\n## <Rle> <IRanges> <Rle> <IRanges> | <integer> <character>\n## [1] chr1 5001-6000 --- chr1 8001-9000 | 3 cis\n## [2] chr1 8001-9000 --- chr1 7001-8000 | 4 trans\n## [3] chr1 7001-8000 --- chr2 13000-14000 | 5 cis\n## -------\n## regions: 7 ranges and 2 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\nHere again, the order matters!\n\ncountOverlaps(gr, gi)\n## [1] 2 2\n\nAnd again, the %over% operator can be used here:\n\ngi %over% gr\n## [1] FALSE FALSE TRUE TRUE TRUE\n\ngi[gi %over% gr] # ----- Equivalent to `subsetByOverlaps(gi, gr)`\n## GInteractions object with 3 interactions and 2 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | idx type\n## <Rle> <IRanges> <Rle> <IRanges> | <integer> <character>\n## [1] chr1 5001-6000 --- chr1 8001-9000 | 3 cis\n## [2] chr1 8001-9000 --- chr1 7001-8000 | 4 trans\n## [3] chr1 7001-8000 --- chr2 13000-14000 | 5 cis\n## -------\n## regions: 7 ranges and 2 metadata columns\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\n\nCase 2: Overlap between anchors of an interaction with anchors of another interaction\n\nThis slightly different scenario involves overlapping two sets of interactions, to see whether any interaction in Set-1 has its two anchors overlapping anchors from an interaction in Set-2.\n\ngi2 <- GInteractions(\n GRanges(\"chr1:1081-1090\"), \n GRanges(\"chr1:3401-3501\")\n)\ngi %over% gi2\n## [1] FALSE TRUE FALSE FALSE FALSE\n\nNote that both anchors of an interaction from a query have to overlap to a pair of anchors of a single interaction from a subject with this method!\n\ngi3 <- GInteractions(\n GRanges(\"chr1:1-1000\"), \n GRanges(\"chr1:3401-3501\")\n)\ngi %over% gi3\n## [1] FALSE FALSE FALSE FALSE FALSE\n\n\nCase 3 : Spanning of the interaction β€œaccross” a genomic range\n\nThis requires a bit of wrangling, to mimic an overlap between two GRanges objects:\n\ngi <- swapAnchors(gi) # ----- Make sure anchors are correctly sorted\ngi <- sort(gi) # ----- Make sure interactions are correctly sorted\ngi <- gi[!is.na(pairdist(gi))] # ----- Remove inter-chromosomal interactions\nspanning_gi <- GRanges(\n seqnames = seqnames(anchors(gi)[[1]]), \n ranges = IRanges(\n start(anchors(gi)[[1]]), \n end(anchors(gi)[[2]])\n )\n)\nspanning_gi \n## GRanges object with 4 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] chr1 1-100 *\n## [2] chr1 1001-4000 *\n## [3] chr1 5001-9000 *\n## [4] chr1 7001-9000 *\n## -------\n## seqinfo: 2 sequences from an unspecified genome; no seqlengths\n\nspanning_gi %over% gr\n## [1] FALSE FALSE TRUE TRUE\n\n\n\n\n\n\n\nGoing further\n\n\n\nA detailed manual of overlap methods available for GInteractions object can be read by typing ?`Interaction-overlaps` in R." + }, + { + "objectID": "pages/data-representation.html#contactfile-class", + "href": "pages/data-representation.html#contactfile-class", + "title": "\n2Β  Hi-C data structures in R\n", + "section": "\n2.3 ContactFile class", + "text": "2.3 ContactFile class\nHi-C contacts can be stored in four different formats (see previous chapter):\n\nAs a .(m)cool matrix (multi-scores, multi-resolution, indexed)\nAs a .hic matrix (multi-scores, multi-resolution, indexed)\nAs a HiC-pro derived matrix (single-score, single-resolution, non-indexed)\nUnbinned, Hi-C contacts can be stored in .pairs files\n\n\n2.3.1 Accessing example Hi-C files\nExample contact files can be downloaded using HiContactsData function.\n\nlibrary(HiContactsData)\ncoolf <- HiContactsData('yeast_wt', 'mcool')\n\nThis fetches files from the cloud, download them locally and returns the path of the local file.\n\ncoolf\n## EH7702 \n## \"/root/.cache/R/ExperimentHub/1701a09a86_7752\"\n\nSimilarly, example files are available for other file formats:\n\nhicf <- HiContactsData('yeast_wt', 'hic')\nhicpromatrixf <- HiContactsData('yeast_wt', 'hicpro_matrix')\nhicproregionsf <- HiContactsData('yeast_wt', 'hicpro_bed')\npairsf <- HiContactsData('yeast_wt', 'pairs.gz')\n\nWe can even check the content of some of these files to make sure they are actually what they are:\n\n# ---- HiC-Pro generates a tab-separated `regions.bed` file\nreadLines(hicproregionsf, 25)\n## [1] \"I\\t0\\t1000\" \"I\\t1000\\t2000\" \"I\\t2000\\t3000\" \"I\\t3000\\t4000\" \n## [5] \"I\\t4000\\t5000\" \"I\\t5000\\t6000\" \"I\\t6000\\t7000\" \"I\\t7000\\t8000\" \n## [9] \"I\\t8000\\t9000\" \"I\\t9000\\t10000\" \"I\\t10000\\t11000\" \"I\\t11000\\t12000\"\n## [13] \"I\\t12000\\t13000\" \"I\\t13000\\t14000\" \"I\\t14000\\t15000\" \"I\\t15000\\t16000\"\n## [17] \"I\\t16000\\t17000\" \"I\\t17000\\t18000\" \"I\\t18000\\t19000\" \"I\\t19000\\t20000\"\n## [21] \"I\\t20000\\t21000\" \"I\\t21000\\t22000\" \"I\\t22000\\t23000\" \"I\\t23000\\t24000\"\n## [25] \"I\\t24000\\t25000\"\n\n# ---- Pairs are also tab-separated \nreadLines(pairsf, 25)\n## [1] \"## pairs format v1.0\" \n## [2] \"#sorted: chr1-pos1-chr2-pos2\" \n## [3] \"#columns: readID chr1 pos1 chr2 pos2 strand1 strand2 frag1 frag2\" \n## [4] \"#chromsize: I 230218\" \n## [5] \"#chromsize: II 813184\" \n## [6] \"#chromsize: III 316620\" \n## [7] \"#chromsize: IV 1531933\" \n## [8] \"#chromsize: V 576874\" \n## [9] \"#chromsize: VI 270161\" \n## [10] \"#chromsize: VII 1090940\" \n## [11] \"#chromsize: VIII 562643\" \n## [12] \"#chromsize: IX 439888\" \n## [13] \"#chromsize: X 745751\" \n## [14] \"#chromsize: XI 666816\" \n## [15] \"#chromsize: XII 1078177\" \n## [16] \"#chromsize: XIII 924431\" \n## [17] \"#chromsize: XIV 784333\" \n## [18] \"#chromsize: XV 1091291\" \n## [19] \"#chromsize: XVI 948066\" \n## [20] \"#chromsize: Mito 85779\" \n## [21] \"NS500150:527:HHGYNBGXF:3:21611:19085:3986\\tII\\t105\\tII\\t48548\\t+\\t-\\t1358\\t1681\" \n## [22] \"NS500150:527:HHGYNBGXF:4:13604:19734:2406\\tII\\t113\\tII\\t45003\\t-\\t+\\t1358\\t1658\" \n## [23] \"NS500150:527:HHGYNBGXF:2:11108:25178:11036\\tII\\t119\\tII\\t687251\\t-\\t+\\t1358\\t5550\"\n## [24] \"NS500150:527:HHGYNBGXF:1:22301:8468:1586\\tII\\t160\\tII\\t26124\\t+\\t-\\t1358\\t1510\" \n## [25] \"NS500150:527:HHGYNBGXF:4:23606:24037:2076\\tII\\t169\\tII\\t39052\\t+\\t+\\t1358\\t1613\"\n\n\n2.3.2 ContactFile fundamentals\nA ContactFile object establishes a connection with a disk-stored Hi-C file (e.g.Β a .cool file, or a .pairs file, …). ContactFile classes are defined in the HiCExperiment package.\nContactFiles come in four different flavors:\n\n\nCoolFile: connection to a .(m)cool file\n\nHicFile: connection to a .hic file\n\nHicproFile: connection to output files generated by HiC-Pro\n\nPairsFile: connection to a .pairs file\n\nTo create each flavor of ContactFile, one can use the corresponding function:\n\nlibrary(HiCExperiment)\n\n# ----- This creates a connection to a `.(m)cool` file (path stored in `coolf`)\nCoolFile(coolf)\n## CoolFile object\n## .mcool file: /root/.cache/R/ExperimentHub/1701a09a86_7752 \n## resolution: 1000 \n## pairs file: \n## metadata(0):\n\n# ----- This creates a connection to a `.hic` file (path stored in `hicf`)\nHicFile(hicf)\n## HicFile object\n## .hic file: /root/.cache/R/ExperimentHub/1702b65c0b7_7836 \n## resolution: 1000 \n## pairs file: \n## metadata(0):\n\n# ----- This creates a connection to output files from HiC-Pro\nHicproFile(hicpromatrixf, hicproregionsf)\n## HicproFile object\n## HiC-Pro files:\n## $ matrix: /root/.cache/R/ExperimentHub/1707968a6f0_7837 \n## $ regions: /root/.cache/R/ExperimentHub/17073053091_7838 \n## resolution: 1000 \n## pairs file: \n## metadata(0):\n\n# ----- This creates a connection to a pairs file\nPairsFile(pairsf)\n## PairsFile object\n## resource: /root/.cache/R/ExperimentHub/1702dcdfa3b_7753\n\n\n2.3.3 ContactFile slots\nSeveral β€œslots” (i.e.Β pieces of information) are attached to a ContactFile object:\n\nThe path to the disk-stored contact matrix;\nThe active resolution (by default, the finest resolution available in a multi-resolution contact matrix);\nOptionally, the path to a matching pairs file (see below);\nSome metadata.\n\nSlots of a CoolFile object can be accessed as follow:\n\ncf <- CoolFile(coolf)\ncf\n## CoolFile object\n## .mcool file: /root/.cache/R/ExperimentHub/1701a09a86_7752 \n## resolution: 1000 \n## pairs file: \n## metadata(0):\n\nresolution(cf)\n## [1] 1000\n\npairsFile(cf)\n## NULL\n\nmetadata(cf)\n## list()\n\n\n\n\n\n\n\nImportant!\n\n\n\nContactFile objects are only connections to a disk-stored HiC file. Although metadata is available, they do not contain actual data!\n\n\n\n2.3.4 ContactFile methods\nTwo useful methods are available for ContactFiles:\n\n\navailableResolutions checks which resolutions are available in a ContactFile.\n\n\navailableResolutions(cf)\n## resolutions(5): 1000 2000 4000 8000 16000\n## \n\n\n\navailableChromosomes checks which chromosomes are available in a ContactFile, along with their length.\n\n\navailableChromosomes(cf)\n## Seqinfo object with 16 sequences from an unspecified genome:\n## seqnames seqlengths isCircular genome\n## I 230218 <NA> <NA>\n## II 813184 <NA> <NA>\n## III 316620 <NA> <NA>\n## IV 1531933 <NA> <NA>\n## V 576874 <NA> <NA>\n## ... ... ... ...\n## XII 1078177 <NA> <NA>\n## XIII 924431 <NA> <NA>\n## XIV 784333 <NA> <NA>\n## XV 1091291 <NA> <NA>\n## XVI 948066 <NA> <NA>" + }, + { + "objectID": "pages/data-representation.html#hicexperiment-class", + "href": "pages/data-representation.html#hicexperiment-class", + "title": "\n2Β  Hi-C data structures in R\n", + "section": "\n2.4 HiCExperiment class", + "text": "2.4 HiCExperiment class\nBased on the previous sections, we have different Bioconductor classes relevant for Hi-C:\n\n\nGInteractions which can be used to represent genomic interactions in R\n\nContactFiles which can be used to establish a connection with disk-stored Hi-C files\n\nHiCExperiment objects are created when parsing a ContactFile in R. The HiCExperiment class reads a ContactFile in memory and store genomic interactions as GInteractions. The HiCExperiment class is, quite obviously, defined in the HiCExperiment package.\n\n2.4.1 Creating a HiCExperiment object\n\n2.4.1.1 Importing a ContactFile\n\nIn practice, to create a HiCExperiment object from a ContactFile, one can use the import method.\n\n\n\n\n\n\nCaution\n\n\n\n\nCreating a HiCExperiment object means importing data from a Hi-C matrix (e.g.Β  from a ContactFile) in memory in R.\n\nCreating a HiCExperiment object from large disk-stored contact matrices can potentially take a long time.\n\n\n\n\ncf <- CoolFile(coolf)\nhic <- import(cf)\nhic\n## `HiCExperiment` object with 8,757,906 contacts over 12,079 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"whole genome\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 1000 \n## interactions: 2945692 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\nPrinting a HiCExperiment to the console will not reveal the actual data stored in the object (it would most likely crash your R session!). Instead, it gives a summary of the data stored in the object:\n\nThe fileName, i.e.Β the path to the disk-stored data file\nThe focus, i.e.Β the genomic location for which data has been imported (in the example above, \"whole genome\" implies that all the data has been imported in R)\n\nresolutions available in the disk-stored data file (this will be identical to availableResolutions(cf))\n\nactive resolution indicates at which resolution the data is currently imported\n\ninteractions refers to the actual GInteractions imported in R and β€œhidden” (for now!) in the HiCExperiment object\n\nscores refer to different interaction frequency estimates. These can be raw counts, balanced (if the contact matrix has been previously normalized), or whatever score the end-user want to attribute to each interaction (e.g.Β ratio of counts between two Hi-C maps, …)\n\ntopologicalFeatures is a list of GRanges or GInteractions objects to describe important topological features.\n\npairsFile is a pointer to an optional disk-stored .pairs file from which the contact matrix has been created. This is often useful to estimate some Hi-C metrics.\n\nmetadata is a list to further describe the experiment.\n\nThese pieces of information are called slots. They can be directly accessed using getter functions, bearing the same name than the slot.\n\nfileName(hic)\n## [1] \"/root/.cache/R/ExperimentHub/1701a09a86_7752\"\n\nfocus(hic)\n## NULL\n\nresolutions(hic)\n## [1] 1000 2000 4000 8000 16000\n\nresolution(hic)\n## [1] 1000\n\ninteractions(hic)\n## GInteractions object with 2945692 interactions and 4 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | bin_id1\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric>\n## [1] I 1-1000 --- I 1-1000 | 0\n## [2] I 1-1000 --- I 1001-2000 | 0\n## [3] I 1-1000 --- I 2001-3000 | 0\n## [4] I 1-1000 --- I 3001-4000 | 0\n## [5] I 1-1000 --- I 4001-5000 | 0\n## ... ... ... ... ... ... . ...\n## [2945688] XVI 940001-941000 --- XVI 942001-943000 | 12070\n## [2945689] XVI 940001-941000 --- XVI 943001-944000 | 12070\n## [2945690] XVI 941001-942000 --- XVI 941001-942000 | 12071\n## [2945691] XVI 941001-942000 --- XVI 942001-943000 | 12071\n## [2945692] XVI 941001-942000 --- XVI 943001-944000 | 12071\n## bin_id2 count balanced\n## <numeric> <numeric> <numeric>\n## [1] 0 15 0.0663491\n## [2] 1 21 0.1273505\n## [3] 2 21 0.0738691\n## [4] 3 38 0.0827051\n## [5] 4 17 0.0591984\n## ... ... ... ...\n## [2945688] 12072 11 0.0575550\n## [2945689] 12073 1 NaN\n## [2945690] 12071 74 0.0504615\n## [2945691] 12072 39 0.1624599\n## [2945692] 12073 1 NaN\n## -------\n## regions: 12079 ranges and 4 metadata columns\n## seqinfo: 16 sequences from an unspecified genome\n\nscores(hic)\n## List of length 2\n## names(2): count balanced\n\ntopologicalFeatures(hic)\n## List of length 4\n## names(4): compartments borders loops viewpoints\n\npairsFile(hic)\n## NULL\n\nmetadata(hic)\n## list()\n\nimport also works for other types of ContactFile (HicFile, HicproFile, PairsFile), e.g.Β \n\nFor HicFile and HicproFile, import seamlessly returns a HiCExperiment as well:\n\n\nhf <- HicFile(hicf)\nhic <- import(hf)\nhic\n## `HiCExperiment` object with 13,681,280 contacts over 12,165 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1702b65c0b7_7836\" \n## focus: \"whole genome\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 1000 \n## interactions: 2965693 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nFor PairsFile, the returned object is a representation of Hi-C β€œpairs” in R, i.e.Β GInteractions\n\n\n\npf <- PairsFile(pairsf)\npairs <- import(pf)\npairs\n## GInteractions object with 471364 interactions and 3 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | frag1 frag2\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric> <numeric>\n## [1] II 105 --- II 48548 | 1358 1681\n## [2] II 113 --- II 45003 | 1358 1658\n## [3] II 119 --- II 687251 | 1358 5550\n## [4] II 160 --- II 26124 | 1358 1510\n## [5] II 169 --- II 39052 | 1358 1613\n## ... ... ... ... ... ... . ... ...\n## [471360] II 808605 --- II 809683 | 6316 6320\n## [471361] II 808609 --- II 809917 | 6316 6324\n## [471362] II 808617 --- II 809506 | 6316 6319\n## [471363] II 809447 --- II 809685 | 6319 6321\n## [471364] II 809472 --- II 809675 | 6319 6320\n## distance\n## <integer>\n## [1] 48443\n## [2] 44890\n## [3] 687132\n## [4] 25964\n## [5] 38883\n## ... ...\n## [471360] 1078\n## [471361] 1308\n## [471362] 889\n## [471363] 238\n## [471364] 203\n## -------\n## regions: 549331 ranges and 0 metadata columns\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\n\n2.4.1.2 Customizing the import\n\nTo reduce the import to only parse the data that is relevant to the study, two arguments can be passed to import, along with a ContactFile.\n\n\n\n\n\n\nKey import arguments:\n\n\n\n\n\nfocus: This can be used to only parse data for a specific genomic location.\n\nresolution: This can be used to choose which resolution to parse the contact matrix at (this is ignored if the ContactFile is not multi-resolution, e.g.Β .cool or HiC-Pro generated matrices)\n\n\n\n\nImport interactions within a single chromosome:\n\n\nhic <- import(cf, focus = 'II', resolution = 2000)\n\nregions(hic) # ---- `regions()` work on `HiCExperiment` the same way than on `GInteractions`\n## GRanges object with 407 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## II_1_2000 II 1-2000 * | 116 NaN II\n## II_2001_4000 II 2001-4000 * | 117 NaN II\n## II_4001_6000 II 4001-6000 * | 118 NaN II\n## II_6001_8000 II 6001-8000 * | 119 NaN II\n## II_8001_10000 II 8001-10000 * | 120 0.0461112 II\n## ... ... ... ... . ... ... ...\n## II_804001_806000 II 804001-806000 * | 518 0.0493107 II\n## II_806001_808000 II 806001-808000 * | 519 0.0611355 II\n## II_808001_810000 II 808001-810000 * | 520 NaN II\n## II_810001_812000 II 810001-812000 * | 521 NaN II\n## II_812001_813184 II 812001-813184 * | 522 NaN II\n## center\n## <integer>\n## II_1_2000 1000\n## II_2001_4000 3000\n## II_4001_6000 5000\n## II_6001_8000 7000\n## II_8001_10000 9000\n## ... ...\n## II_804001_806000 805000\n## II_806001_808000 807000\n## II_808001_810000 809000\n## II_810001_812000 811000\n## II_812001_813184 812592\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\ntable(seqnames(regions(hic)))\n## \n## I II III IV V VI VII VIII IX X XI XII XIII XIV XV \n## 0 407 0 0 0 0 0 0 0 0 0 0 0 0 0 \n## XVI \n## 0\n\nanchors(hic) # ---- `anchors()` work on `HiCExperiment` the same way than on `GInteractions`\n## $first\n## GRanges object with 34063 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## [1] II 1-2000 * | 116 NaN II\n## [2] II 1-2000 * | 116 NaN II\n## [3] II 1-2000 * | 116 NaN II\n## [4] II 1-2000 * | 116 NaN II\n## [5] II 1-2000 * | 116 NaN II\n## ... ... ... ... . ... ... ...\n## [34059] II 804001-806000 * | 518 0.0493107 II\n## [34060] II 806001-808000 * | 519 0.0611355 II\n## [34061] II 806001-808000 * | 519 0.0611355 II\n## [34062] II 806001-808000 * | 519 0.0611355 II\n## [34063] II 808001-810000 * | 520 NaN II\n## center\n## <integer>\n## [1] 1000\n## [2] 1000\n## [3] 1000\n## [4] 1000\n## [5] 1000\n## ... ...\n## [34059] 805000\n## [34060] 807000\n## [34061] 807000\n## [34062] 807000\n## [34063] 809000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n## \n## $second\n## GRanges object with 34063 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## [1] II 1-2000 * | 116 NaN II\n## [2] II 4001-6000 * | 118 NaN II\n## [3] II 6001-8000 * | 119 NaN II\n## [4] II 8001-10000 * | 120 0.0461112 II\n## [5] II 10001-12000 * | 121 0.0334807 II\n## ... ... ... ... . ... ... ...\n## [34059] II 810001-812000 * | 521 NaN II\n## [34060] II 806001-808000 * | 519 0.0611355 II\n## [34061] II 808001-810000 * | 520 NaN II\n## [34062] II 810001-812000 * | 521 NaN II\n## [34063] II 808001-810000 * | 520 NaN II\n## center\n## <integer>\n## [1] 1000\n## [2] 5000\n## [3] 7000\n## [4] 9000\n## [5] 11000\n## ... ...\n## [34059] 811000\n## [34060] 807000\n## [34061] 809000\n## [34062] 811000\n## [34063] 809000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\n\nImport interactions within a segment of a chromosome:\n\n\nhic <- import(cf, focus = 'II:40000-60000', resolution = 1000)\n\nregions(hic) \n## GRanges object with 21 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## II_39001_40000 II 39001-40000 * | 270 0.0220798 II\n## II_40001_41000 II 40001-41000 * | 271 0.0246775 II\n## II_41001_42000 II 41001-42000 * | 272 0.0269232 II\n## II_42001_43000 II 42001-43000 * | 273 0.0341849 II\n## II_43001_44000 II 43001-44000 * | 274 0.0265386 II\n## ... ... ... ... . ... ... ...\n## II_55001_56000 II 55001-56000 * | 286 0.0213532 II\n## II_56001_57000 II 56001-57000 * | 287 0.0569839 II\n## II_57001_58000 II 57001-58000 * | 288 0.0338612 II\n## II_58001_59000 II 58001-59000 * | 289 0.0294531 II\n## II_59001_60000 II 59001-60000 * | 290 0.0306662 II\n## center\n## <integer>\n## II_39001_40000 39500\n## II_40001_41000 40500\n## II_41001_42000 41500\n## II_42001_43000 42500\n## II_43001_44000 43500\n## ... ...\n## II_55001_56000 55500\n## II_56001_57000 56500\n## II_57001_58000 57500\n## II_58001_59000 58500\n## II_59001_60000 59500\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\nanchors(hic)\n## $first\n## GRanges object with 210 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr center\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle> <integer>\n## [1] II 40001-41000 * | 271 0.0246775 II 40500\n## [2] II 40001-41000 * | 271 0.0246775 II 40500\n## [3] II 40001-41000 * | 271 0.0246775 II 40500\n## [4] II 40001-41000 * | 271 0.0246775 II 40500\n## [5] II 40001-41000 * | 271 0.0246775 II 40500\n## ... ... ... ... . ... ... ... ...\n## [206] II 57001-58000 * | 288 0.0338612 II 57500\n## [207] II 57001-58000 * | 288 0.0338612 II 57500\n## [208] II 58001-59000 * | 289 0.0294531 II 58500\n## [209] II 58001-59000 * | 289 0.0294531 II 58500\n## [210] II 59001-60000 * | 290 0.0306662 II 59500\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n## \n## $second\n## GRanges object with 210 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr center\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle> <integer>\n## [1] II 40001-41000 * | 271 0.0246775 II 40500\n## [2] II 41001-42000 * | 272 0.0269232 II 41500\n## [3] II 42001-43000 * | 273 0.0341849 II 42500\n## [4] II 43001-44000 * | 274 0.0265386 II 43500\n## [5] II 44001-45000 * | 275 0.0488968 II 44500\n## ... ... ... ... . ... ... ... ...\n## [206] II 58001-59000 * | 289 0.0294531 II 58500\n## [207] II 59001-60000 * | 290 0.0306662 II 59500\n## [208] II 58001-59000 * | 289 0.0294531 II 58500\n## [209] II 59001-60000 * | 290 0.0306662 II 59500\n## [210] II 59001-60000 * | 290 0.0306662 II 59500\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\n\nImport interactions between two chromosomes:\n\n\nhic2 <- import(cf, focus = 'II|XV', resolution = 4000)\n\nregions(hic2)\n## GRanges object with 477 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight\n## <Rle> <IRanges> <Rle> | <numeric> <numeric>\n## II_1_4000 II 1-4000 * | 58 NaN\n## II_4001_8000 II 4001-8000 * | 59 NaN\n## II_8001_12000 II 8001-12000 * | 60 0.0274474\n## II_12001_16000 II 12001-16000 * | 61 0.0342116\n## II_16001_20000 II 16001-20000 * | 62 0.0195128\n## ... ... ... ... . ... ...\n## XV_1072001_1076000 XV 1072001-1076000 * | 2783 0.041763\n## XV_1076001_1080000 XV 1076001-1080000 * | 2784 NaN\n## XV_1080001_1084000 XV 1080001-1084000 * | 2785 NaN\n## XV_1084001_1088000 XV 1084001-1088000 * | 2786 NaN\n## XV_1088001_1091291 XV 1088001-1091291 * | 2787 NaN\n## chr center\n## <Rle> <integer>\n## II_1_4000 II 2000\n## II_4001_8000 II 6000\n## II_8001_12000 II 10000\n## II_12001_16000 II 14000\n## II_16001_20000 II 18000\n## ... ... ...\n## XV_1072001_1076000 XV 1074000\n## XV_1076001_1080000 XV 1078000\n## XV_1080001_1084000 XV 1082000\n## XV_1084001_1088000 XV 1086000\n## XV_1088001_1091291 XV 1089646\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\nanchors(hic2)\n## $first\n## GRanges object with 18032 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## [1] II 1-4000 * | 58 NaN II\n## [2] II 1-4000 * | 58 NaN II\n## [3] II 1-4000 * | 58 NaN II\n## [4] II 1-4000 * | 58 NaN II\n## [5] II 1-4000 * | 58 NaN II\n## ... ... ... ... . ... ... ...\n## [18028] II 808001-812000 * | 260 NaN II\n## [18029] II 808001-812000 * | 260 NaN II\n## [18030] II 808001-812000 * | 260 NaN II\n## [18031] II 808001-812000 * | 260 NaN II\n## [18032] II 808001-812000 * | 260 NaN II\n## center\n## <integer>\n## [1] 2000\n## [2] 2000\n## [3] 2000\n## [4] 2000\n## [5] 2000\n## ... ...\n## [18028] 810000\n## [18029] 810000\n## [18030] 810000\n## [18031] 810000\n## [18032] 810000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n## \n## $second\n## GRanges object with 18032 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## [1] XV 48001-52000 * | 2527 0.0185354 XV\n## [2] XV 348001-352000 * | 2602 0.0233750 XV\n## [3] XV 468001-472000 * | 2632 0.0153615 XV\n## [4] XV 472001-476000 * | 2633 0.0189624 XV\n## [5] XV 584001-588000 * | 2661 0.0167715 XV\n## ... ... ... ... . ... ... ...\n## [18028] XV 980001-984000 * | 2760 0.0187827 XV\n## [18029] XV 984001-988000 * | 2761 0.0250094 XV\n## [18030] XV 992001-996000 * | 2763 0.0185599 XV\n## [18031] XV 1004001-1008000 * | 2766 0.0196942 XV\n## [18032] XV 1064001-1068000 * | 2781 0.0208220 XV\n## center\n## <integer>\n## [1] 50000\n## [2] 350000\n## [3] 470000\n## [4] 474000\n## [5] 586000\n## ... ...\n## [18028] 982000\n## [18029] 986000\n## [18030] 994000\n## [18031] 1006000\n## [18032] 1066000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\n\nImport interactions between segments of two chromosomes:\n\n\nhic3 <- import(cf, focus = 'III:10000-40000|XV:10000-40000', resolution = 2000)\n\nregions(hic3)\n## GRanges object with 32 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## III_8001_10000 III 8001-10000 * | 527 NaN III\n## III_10001_12000 III 10001-12000 * | 528 NaN III\n## III_12001_14000 III 12001-14000 * | 529 NaN III\n## III_14001_16000 III 14001-16000 * | 530 0.0356351 III\n## III_16001_18000 III 16001-18000 * | 531 0.0230693 III\n## ... ... ... ... . ... ... ...\n## XV_30001_32000 XV 30001-32000 * | 5039 0.0482465 XV\n## XV_32001_34000 XV 32001-34000 * | 5040 0.0241580 XV\n## XV_34001_36000 XV 34001-36000 * | 5041 0.0273166 XV\n## XV_36001_38000 XV 36001-38000 * | 5042 0.0542235 XV\n## XV_38001_40000 XV 38001-40000 * | 5043 0.0206849 XV\n## center\n## <integer>\n## III_8001_10000 9000\n## III_10001_12000 11000\n## III_12001_14000 13000\n## III_14001_16000 15000\n## III_16001_18000 17000\n## ... ...\n## XV_30001_32000 31000\n## XV_32001_34000 33000\n## XV_34001_36000 35000\n## XV_36001_38000 37000\n## XV_38001_40000 39000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\nanchors(hic3)\n## $first\n## GRanges object with 11 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr center\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle> <integer>\n## [1] III 14001-16000 * | 530 0.0356351 III 15000\n## [2] III 16001-18000 * | 531 0.0230693 III 17000\n## [3] III 16001-18000 * | 531 0.0230693 III 17000\n## [4] III 20001-22000 * | 533 0.0343250 III 21000\n## [5] III 22001-24000 * | 534 0.0258604 III 23000\n## [6] III 24001-26000 * | 535 0.0290757 III 25000\n## [7] III 28001-30000 * | 537 0.0290713 III 29000\n## [8] III 30001-32000 * | 538 0.0266373 III 31000\n## [9] III 32001-34000 * | 539 0.0201137 III 33000\n## [10] III 32001-34000 * | 539 0.0201137 III 33000\n## [11] III 36001-38000 * | 541 0.0220603 III 37000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n## \n## $second\n## GRanges object with 11 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr center\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle> <integer>\n## [1] XV 16001-18000 * | 5032 0.0187250 XV 17000\n## [2] XV 16001-18000 * | 5032 0.0187250 XV 17000\n## [3] XV 20001-22000 * | 5034 0.0247973 XV 21000\n## [4] XV 14001-16000 * | 5031 0.0379727 XV 15000\n## [5] XV 10001-12000 * | 5029 0.0296913 XV 11000\n## [6] XV 32001-34000 * | 5040 0.0241580 XV 33000\n## [7] XV 16001-18000 * | 5032 0.0187250 XV 17000\n## [8] XV 38001-40000 * | 5043 0.0206849 XV 39000\n## [9] XV 22001-24000 * | 5035 0.0613856 XV 23000\n## [10] XV 30001-32000 * | 5039 0.0482465 XV 31000\n## [11] XV 10001-12000 * | 5029 0.0296913 XV 11000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\n\n2.4.2 Interacting with HiCExperiment data\n\nAn HiCExperiment object allows parsing of a disk-stored contact matrix.\nAn HiCExperiment object operates by wrapping together (1) a ContactFile (i.e.Β a connection to a disk-stored data file) and (2) a GInteractions generated by parsing the data file.\n\nWe will use the yeast_hic HiCExperiment object to demonstrate how to parse information from a HiCExperiment object.\n\nyeast_hic <- contacts_yeast()\n\n\nyeast_hic\n## `HiCExperiment` object with 8,757,906 contacts over 763 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"whole genome\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 16000 \n## interactions: 267709 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) \n## pairsFile: /root/.cache/R/ExperimentHub/1702dcdfa3b_7753 \n## metadata(3): ID org date\n\n\n2.4.2.1 Interactions\nThe imported genomic interactions can be directly exposed using the interactions function and are returned as a GInteractions object.\n\ninteractions(yeast_hic)\n## GInteractions object with 267709 interactions and 4 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | bin_id1\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric>\n## [1] I 1-16000 --- I 1-16000 | 0\n## [2] I 1-16000 --- I 16001-32000 | 0\n## [3] I 1-16000 --- I 32001-48000 | 0\n## [4] I 1-16000 --- I 48001-64000 | 0\n## [5] I 1-16000 --- I 64001-80000 | 0\n## ... ... ... ... ... ... . ...\n## [267705] XVI 896001-912000 --- XVI 912001-928000 | 759\n## [267706] XVI 896001-912000 --- XVI 928001-944000 | 759\n## [267707] XVI 912001-928000 --- XVI 912001-928000 | 760\n## [267708] XVI 912001-928000 --- XVI 928001-944000 | 760\n## [267709] XVI 928001-944000 --- XVI 928001-944000 | 761\n## bin_id2 count balanced\n## <numeric> <numeric> <numeric>\n## [1] 0 2836 1.0943959\n## [2] 1 2212 0.9592069\n## [3] 2 1183 0.4385242\n## [4] 3 831 0.2231192\n## [5] 4 310 0.0821255\n## ... ... ... ...\n## [267705] 760 3565 1.236371\n## [267706] 761 1359 0.385016\n## [267707] 760 3534 2.103988\n## [267708] 761 3055 1.485794\n## [267709] 761 4308 1.711565\n## -------\n## regions: 763 ranges and 4 metadata columns\n## seqinfo: 16 sequences from an unspecified genome\n\nBecause genomic interactions are actually stored as GInteractions, regions and anchors work on HiCExperiment objects just as they work with GInteractions!\n\nregions(yeast_hic)\n## GRanges object with 763 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight\n## <Rle> <IRanges> <Rle> | <numeric> <numeric>\n## I_1_16000 I 1-16000 * | 0 0.0196442\n## I_16001_32000 I 16001-32000 * | 1 0.0220746\n## I_32001_48000 I 32001-48000 * | 2 0.0188701\n## I_48001_64000 I 48001-64000 * | 3 0.0136679\n## I_64001_80000 I 64001-80000 * | 4 0.0134860\n## ... ... ... ... . ... ...\n## XVI_880001_896000 XVI 880001-896000 * | 758 0.00910873\n## XVI_896001_912000 XVI 896001-912000 * | 759 0.01421350\n## XVI_912001_928000 XVI 912001-928000 * | 760 0.02439992\n## XVI_928001_944000 XVI 928001-944000 * | 761 0.01993237\n## XVI_944001_948066 XVI 944001-948066 * | 762 NaN\n## chr center\n## <Rle> <integer>\n## I_1_16000 I 8000\n## I_16001_32000 I 24000\n## I_32001_48000 I 40000\n## I_48001_64000 I 56000\n## I_64001_80000 I 72000\n## ... ... ...\n## XVI_880001_896000 XVI 888000\n## XVI_896001_912000 XVI 904000\n## XVI_912001_928000 XVI 920000\n## XVI_928001_944000 XVI 936000\n## XVI_944001_948066 XVI 946033\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\nanchors(yeast_hic)\n## $first\n## GRanges object with 267709 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## [1] I 1-16000 * | 0 0.0196442 I\n## [2] I 1-16000 * | 0 0.0196442 I\n## [3] I 1-16000 * | 0 0.0196442 I\n## [4] I 1-16000 * | 0 0.0196442 I\n## [5] I 1-16000 * | 0 0.0196442 I\n## ... ... ... ... . ... ... ...\n## [267705] XVI 896001-912000 * | 759 0.0142135 XVI\n## [267706] XVI 896001-912000 * | 759 0.0142135 XVI\n## [267707] XVI 912001-928000 * | 760 0.0243999 XVI\n## [267708] XVI 912001-928000 * | 760 0.0243999 XVI\n## [267709] XVI 928001-944000 * | 761 0.0199324 XVI\n## center\n## <integer>\n## [1] 8000\n## [2] 8000\n## [3] 8000\n## [4] 8000\n## [5] 8000\n## ... ...\n## [267705] 904000\n## [267706] 904000\n## [267707] 920000\n## [267708] 920000\n## [267709] 936000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n## \n## $second\n## GRanges object with 267709 ranges and 4 metadata columns:\n## seqnames ranges strand | bin_id weight chr\n## <Rle> <IRanges> <Rle> | <numeric> <numeric> <Rle>\n## [1] I 1-16000 * | 0 0.0196442 I\n## [2] I 16001-32000 * | 1 0.0220746 I\n## [3] I 32001-48000 * | 2 0.0188701 I\n## [4] I 48001-64000 * | 3 0.0136679 I\n## [5] I 64001-80000 * | 4 0.0134860 I\n## ... ... ... ... . ... ... ...\n## [267705] XVI 912001-928000 * | 760 0.0243999 XVI\n## [267706] XVI 928001-944000 * | 761 0.0199324 XVI\n## [267707] XVI 912001-928000 * | 760 0.0243999 XVI\n## [267708] XVI 928001-944000 * | 761 0.0199324 XVI\n## [267709] XVI 928001-944000 * | 761 0.0199324 XVI\n## center\n## <integer>\n## [1] 8000\n## [2] 24000\n## [3] 40000\n## [4] 56000\n## [5] 72000\n## ... ...\n## [267705] 920000\n## [267706] 936000\n## [267707] 920000\n## [267708] 936000\n## [267709] 936000\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\n\n2.4.2.2 Bins and seqinfo\nAdditional useful information can be recovered from a HiCExperiment object. This includes:\n\nThe seqinfo of the HiCExperiment:\n\n\nseqinfo(yeast_hic)\n## Seqinfo object with 16 sequences from an unspecified genome:\n## seqnames seqlengths isCircular genome\n## I 230218 <NA> <NA>\n## II 813184 <NA> <NA>\n## III 316620 <NA> <NA>\n## IV 1531933 <NA> <NA>\n## V 576874 <NA> <NA>\n## ... ... ... ...\n## XII 1078177 <NA> <NA>\n## XIII 924431 <NA> <NA>\n## XIV 784333 <NA> <NA>\n## XV 1091291 <NA> <NA>\n## XVI 948066 <NA> <NA>\n\nThis lists the different chromosomes available to parse along with their length.\n\nThe bins of the HiCExperiment:\n\n\nbins(yeast_hic)\n## GRanges object with 763 ranges and 2 metadata columns:\n## seqnames ranges strand | bin_id weight\n## <Rle> <IRanges> <Rle> | <numeric> <numeric>\n## I_1_16000 I 1-16000 * | 0 0.0196442\n## I_16001_32000 I 16001-32000 * | 1 0.0220746\n## I_32001_48000 I 32001-48000 * | 2 0.0188701\n## I_48001_64000 I 48001-64000 * | 3 0.0136679\n## I_64001_80000 I 64001-80000 * | 4 0.0134860\n## ... ... ... ... . ... ...\n## XVI_880001_896000 XVI 880001-896000 * | 758 0.00910873\n## XVI_896001_912000 XVI 896001-912000 * | 759 0.01421350\n## XVI_912001_928000 XVI 912001-928000 * | 760 0.02439992\n## XVI_928001_944000 XVI 928001-944000 * | 761 0.01993237\n## XVI_944001_948066 XVI 944001-948066 * | 762 NaN\n## -------\n## seqinfo: 16 sequences from an unspecified genome\n\n\n\n\n\n\n\nDifference between bins and regions\n\n\n\nbins are not equivalent to regions of an HiCExperiment.\n\n\nbins refer to all the possible regions of a HiCExperiment. For instance, for a HiCExperiment with a total genome size of 1,000,000 and a resolution of 2000, bins will always return a GRanges object with 500 ranges.\n\nregions, on the opposite, refer to the union of anchors of all the interactions imported in a HiCExperiment object.\n\nThus, all the regions will necessarily be a subset of the HiCExperiment bins, or equal to bins if no focus has been specified when importing a ContactFile.\n\n\n\n2.4.2.3 Scores\nOf course, what the end-user would be looking for is the frequency for each genomic interaction. Such frequency scores are available using the scores function. scores returns a list with a number of different types of scores.\n\nhead(scores(yeast_hic))\n## List of length 2\n## names(2): count balanced\n\nhead(scores(yeast_hic, \"count\"))\n## [1] 2836 2212 1183 831 310 159\n\nhead(scores(yeast_hic, \"balanced\"))\n## [1] 1.09439586 0.95920688 0.43852417 0.22311917 0.08212549 0.03345221\n\nCalling interactions(hic) returns a GInteractions with scores already stored in extra columns. This short-hand allows one to dynamically check scores directly from the interactions output.\n\ninteractions(yeast_hic)\n## GInteractions object with 267709 interactions and 4 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | bin_id1\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric>\n## [1] I 1-16000 --- I 1-16000 | 0\n## [2] I 1-16000 --- I 16001-32000 | 0\n## [3] I 1-16000 --- I 32001-48000 | 0\n## [4] I 1-16000 --- I 48001-64000 | 0\n## [5] I 1-16000 --- I 64001-80000 | 0\n## ... ... ... ... ... ... . ...\n## [267705] XVI 896001-912000 --- XVI 912001-928000 | 759\n## [267706] XVI 896001-912000 --- XVI 928001-944000 | 759\n## [267707] XVI 912001-928000 --- XVI 912001-928000 | 760\n## [267708] XVI 912001-928000 --- XVI 928001-944000 | 760\n## [267709] XVI 928001-944000 --- XVI 928001-944000 | 761\n## bin_id2 count balanced\n## <numeric> <numeric> <numeric>\n## [1] 0 2836 1.0943959\n## [2] 1 2212 0.9592069\n## [3] 2 1183 0.4385242\n## [4] 3 831 0.2231192\n## [5] 4 310 0.0821255\n## ... ... ... ...\n## [267705] 760 3565 1.236371\n## [267706] 761 1359 0.385016\n## [267707] 760 3534 2.103988\n## [267708] 761 3055 1.485794\n## [267709] 761 4308 1.711565\n## -------\n## regions: 763 ranges and 4 metadata columns\n## seqinfo: 16 sequences from an unspecified genome\n\nhead(interactions(yeast_hic)$count)\n## [1] 2836 2212 1183 831 310 159\n\n\n2.4.2.4 topologicalFeatures\nIn Hi-C studies, β€œtopological features” refer to genomic structures identified (usually from a Hi-C map, but not necessarily). For instance, one may want to study known structural loops anchored at CTCF sites, or interactions around or over centromeres, or simply specific genomic β€œviewpoints”.\nHiCExperiment objects can store topologicalFeatures to facilitate this analysis. By default, four empty topologicalFeatures are stored in a list:\n\ncompartments\nborders\nloops\nviewpoints\n\nAdditional topologicalFeatures can be added to this list (read next chapter for more detail).\n\ntopologicalFeatures(yeast_hic)\n## List of length 5\n## names(5): compartments borders loops viewpoints centromeres\n\ntopologicalFeatures(yeast_hic, 'centromeres')\n## GRanges object with 16 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] I 151583-151641 +\n## [2] II 238361-238419 +\n## [3] III 114322-114380 +\n## [4] IV 449879-449937 +\n## [5] V 152522-152580 +\n## ... ... ... ...\n## [12] XII 151366-151424 +\n## [13] XIII 268222-268280 +\n## [14] XIV 628588-628646 +\n## [15] XV 326897-326955 +\n## [16] XVI 556255-556313 +\n## -------\n## seqinfo: 17 sequences (1 circular) from R64-1-1 genome\n\n\n2.4.2.5 pairsFile\nAs a contact matrix is typically obtained from binning a .pairs file, it is often the case that the matching .pairs file is available to then end-user. A PairsFile can thus be created and associated to the corresponding HiCExperiment object. This allows more accurate estimation of contact distribution, e.g.Β when calculating distance-dependent genomic interaction frequency.\n\npairsFile(yeast_hic) <- pairsf\n\npairsFile(yeast_hic)\n## EH7703 \n## \"/root/.cache/R/ExperimentHub/1702dcdfa3b_7753\"\n\nreadLines(pairsFile(yeast_hic), 25)\n## [1] \"## pairs format v1.0\" \n## [2] \"#sorted: chr1-pos1-chr2-pos2\" \n## [3] \"#columns: readID chr1 pos1 chr2 pos2 strand1 strand2 frag1 frag2\" \n## [4] \"#chromsize: I 230218\" \n## [5] \"#chromsize: II 813184\" \n## [6] \"#chromsize: III 316620\" \n## [7] \"#chromsize: IV 1531933\" \n## [8] \"#chromsize: V 576874\" \n## [9] \"#chromsize: VI 270161\" \n## [10] \"#chromsize: VII 1090940\" \n## [11] \"#chromsize: VIII 562643\" \n## [12] \"#chromsize: IX 439888\" \n## [13] \"#chromsize: X 745751\" \n## [14] \"#chromsize: XI 666816\" \n## [15] \"#chromsize: XII 1078177\" \n## [16] \"#chromsize: XIII 924431\" \n## [17] \"#chromsize: XIV 784333\" \n## [18] \"#chromsize: XV 1091291\" \n## [19] \"#chromsize: XVI 948066\" \n## [20] \"#chromsize: Mito 85779\" \n## [21] \"NS500150:527:HHGYNBGXF:3:21611:19085:3986\\tII\\t105\\tII\\t48548\\t+\\t-\\t1358\\t1681\" \n## [22] \"NS500150:527:HHGYNBGXF:4:13604:19734:2406\\tII\\t113\\tII\\t45003\\t-\\t+\\t1358\\t1658\" \n## [23] \"NS500150:527:HHGYNBGXF:2:11108:25178:11036\\tII\\t119\\tII\\t687251\\t-\\t+\\t1358\\t5550\"\n## [24] \"NS500150:527:HHGYNBGXF:1:22301:8468:1586\\tII\\t160\\tII\\t26124\\t+\\t-\\t1358\\t1510\" \n## [25] \"NS500150:527:HHGYNBGXF:4:23606:24037:2076\\tII\\t169\\tII\\t39052\\t+\\t+\\t1358\\t1613\"\n\n\n2.4.2.6 Importing a PairsFile\n\nThe .pairs file linked to a HiCExperiment object can itself be imported in a GInteractions object:\n\nimport(pairsFile(yeast_hic), format = 'pairs')\n## GInteractions object with 471364 interactions and 3 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | frag1 frag2\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric> <numeric>\n## [1] II 105 --- II 48548 | 1358 1681\n## [2] II 113 --- II 45003 | 1358 1658\n## [3] II 119 --- II 687251 | 1358 5550\n## [4] II 160 --- II 26124 | 1358 1510\n## [5] II 169 --- II 39052 | 1358 1613\n## ... ... ... ... ... ... . ... ...\n## [471360] II 808605 --- II 809683 | 6316 6320\n## [471361] II 808609 --- II 809917 | 6316 6324\n## [471362] II 808617 --- II 809506 | 6316 6319\n## [471363] II 809447 --- II 809685 | 6319 6321\n## [471364] II 809472 --- II 809675 | 6319 6320\n## distance\n## <integer>\n## [1] 48443\n## [2] 44890\n## [3] 687132\n## [4] 25964\n## [5] 38883\n## ... ...\n## [471360] 1078\n## [471361] 1308\n## [471362] 889\n## [471363] 238\n## [471364] 203\n## -------\n## regions: 549331 ranges and 0 metadata columns\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\nNote that these GInteractions are not binned, contrary to interactions extracted from a HiCExperiment. Anchors of the interactions listed in the GInteractions imported from a disk-stored .pairs file are all of width 1." + }, + { + "objectID": "pages/data-representation.html#visual-summary-of-the-hicexperiment-data-structure", + "href": "pages/data-representation.html#visual-summary-of-the-hicexperiment-data-structure", + "title": "\n2Β  Hi-C data structures in R\n", + "section": "\n2.5 Visual summary of the HiCExperiment data structure", + "text": "2.5 Visual summary of the HiCExperiment data structure\nThe HiCExperiment data structure provided by the HiCExperiment package inherits methods from core GInteractions and BiocFile classes to provide a flexible representation of Hi-C data in R. It allows random access-based queries to seamlessly import parts or all the data contained in disk-stored Hi-C contact matrices in a variety of formats." + }, + { + "objectID": "pages/parsing.html", + "href": "pages/parsing.html", + "title": "\n3Β  Manipulating Hi-C data in R\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/parsing.html#subsetting-a-contact-matrix", + "href": "pages/parsing.html#subsetting-a-contact-matrix", + "title": "\n3Β  Manipulating Hi-C data in R\n", + "section": "\n3.1 Subsetting a contact matrix", + "text": "3.1 Subsetting a contact matrix\nTwo entirely different approaches are possible to subset of a Hi-C contact matrix:\n\nSubsetting before importing: leveraging random access to a disk-stored contact matrix to only import interactions overlapping with a genomic locus of interest.\nSubsetting after importing: parsing the entire contact matrix in memory, and subsequently subset interactions overlapping with a genomic locus of interest.\n\n\n\n3.1.1 Subsetting before import: with focus\n\nSpecifying a focus when importing a dataset in R (i.e.Β \"Subset first, then parse\") is generally the recommended approach to import Hi-C data in R.\nThe focus argument can be set when importing a ContactFile in R, as follows:\n\nimport(cf, focus = \"...\")\n\nThis ensures that only the needed data is parsed in R, reducing memory load and accelerating the import. Thus, this should be the preferred way of parsing HiCExperiment data, as disk-stored contact matrices allow efficient random access to indexed data.\nfocus can be any of the following string types:\n\n# \"II\" --> import contacts over an entire chromosome\n# \"II:300001-800000\" --> import on-diagonal contacts within a chromosome\n# \"II:300001-400000|II:600001-700000\" --> import off-diagonal contacts within a chromosome\n# \"II|III\" --> import contacts between two chromosomes\n# \"II:300001-800000|V:1-500000\" --> import contacts between segments of two chromosomes\n\n\n\n\n\n\n\nMore examples for import with focus argument πŸ‘‡\n\n\n\n\n\n\nSubsetting to a specific on-diagonal genomic location using standard UCSC coordinates query:\n\n\nimport(cf, focus = 'II:300001-800000', resolution = 2000)\n## `HiCExperiment` object with 301,018 contacts over 250 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300,001-800,000\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 17974 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting to a specific off-diagonal genomic location using pairs of coordinates query:\n\n\nimport(cf, focus = 'II:300001-400000|II:600001-700000', resolution = 2000)\n## `HiCExperiment` object with 402 contacts over 100 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300001-400000|II:600001-700000\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 357 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting interactions to retain those constrained within a single chromosome:\n\n\nimport(cf, focus = 'II', resolution = 2000)\n## `HiCExperiment` object with 471,364 contacts over 407 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 34063 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting interactions to retain those between two chromosomes:\n\n\nimport(cf, focus = 'II|III', resolution = 2000)\n## `HiCExperiment` object with 9,092 contacts over 566 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II|III\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 7438 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting interactions to retain those between parts of two chromosomes:\n\n\nimport(cf, focus = 'II:300001-800000|V:1-500000', resolution = 2000)\n## `HiCExperiment` object with 7,147 contacts over 500 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300001-800000|V:1-500000\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 6523 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\n\n\n\n\n3.1.2 Subsetting after import\nIt may sometimes be desirable to import a full dataset from disk first, and only then perform in-memory subsetting of the HiCExperiment object (i.e.Β \"Parse first, then subset\"). This is for example necessary when the end user aims to investigate subsets of interactions across a large number of different areas of a contact matrix.\nSeveral strategies are possible to allow subsetting of imported data, either with subsetByOverlaps or [.\n\n3.1.2.1 subsetByOverlaps(<HiCExperiment>, <GRanges>)\n\nsubsetByOverlaps can take a HiCExperiment as a query and a GRanges as a query. In this case, the GRanges is used to extract a subset of a HiCExperiment constrained within a specific genomic location.\n\ntelomere <- GRanges(\"II:700001-813184\")\nsubsetByOverlaps(hic, telomere) |> interactions()\n## GInteractions object with 1540 interactions and 4 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | bin_id1\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric>\n## [1] II 700001-702000 --- II 700001-702000 | 466\n## [2] II 700001-702000 --- II 702001-704000 | 466\n## [3] II 700001-702000 --- II 704001-706000 | 466\n## [4] II 700001-702000 --- II 706001-708000 | 466\n## [5] II 700001-702000 --- II 708001-710000 | 466\n## ... ... ... ... ... ... . ...\n## [1536] II 804001-806000 --- II 810001-812000 | 518\n## [1537] II 806001-808000 --- II 806001-808000 | 519\n## [1538] II 806001-808000 --- II 808001-810000 | 519\n## [1539] II 806001-808000 --- II 810001-812000 | 519\n## [1540] II 808001-810000 --- II 808001-810000 | 520\n## bin_id2 count balanced\n## <numeric> <numeric> <numeric>\n## [1] 466 30 0.0283618\n## [2] 467 145 0.0709380\n## [3] 468 124 0.0704979\n## [4] 469 59 0.0510221\n## [5] 470 59 0.0384004\n## ... ... ... ...\n## [1536] 521 1 NaN\n## [1537] 519 15 0.0560633\n## [1538] 520 25 NaN\n## [1539] 521 1 NaN\n## [1540] 520 10 NaN\n## -------\n## regions: 57 ranges and 4 metadata columns\n## seqinfo: 16 sequences from an unspecified genome\n\nBy default, subsetByOverlaps(hic, telomere) will only recover interactions constrained within telomere, i.e.Β interactions for which both ends are in telomere.\nAlternatively, type = \"any\" can be specified to get all interactions with at least one of their anchors within telomere.\n\nsubsetByOverlaps(hic, telomere, type = \"any\") |> interactions()\n## GInteractions object with 6041 interactions and 4 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | bin_id1\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric>\n## [1] II 300001-302000 --- II 702001-704000 | 266\n## [2] II 300001-302000 --- II 704001-706000 | 266\n## [3] II 300001-302000 --- II 768001-770000 | 266\n## [4] II 300001-302000 --- II 784001-786000 | 266\n## [5] II 302001-304000 --- II 740001-742000 | 267\n## ... ... ... ... ... ... . ...\n## [6037] II 804001-806000 --- II 810001-812000 | 518\n## [6038] II 806001-808000 --- II 806001-808000 | 519\n## [6039] II 806001-808000 --- II 808001-810000 | 519\n## [6040] II 806001-808000 --- II 810001-812000 | 519\n## [6041] II 808001-810000 --- II 808001-810000 | 520\n## bin_id2 count balanced\n## <numeric> <numeric> <numeric>\n## [1] 467 1 0.000590999\n## [2] 468 1 0.000686799\n## [3] 500 1 0.000728215\n## [4] 508 1 0.000923092\n## [5] 486 1 0.000382222\n## ... ... ... ...\n## [6037] 521 1 NaN\n## [6038] 519 15 0.0560633\n## [6039] 520 25 NaN\n## [6040] 521 1 NaN\n## [6041] 520 10 NaN\n## -------\n## regions: 257 ranges and 4 metadata columns\n## seqinfo: 16 sequences from an unspecified genome\n\n\n3.1.2.2 <HiCExperiment>[\"...\"]\n\nThe square bracket operator [ allows for more advanced textual queries, similarly to focus arguments that can be used when importing contact matrices in memory.\nThis ensures that only the needed data is parsed in R, reducing memory load and accelerating the import. Thus, this should be the preferred way of parsing HiCExperiment data, as disk-stored contact matrices allow efficient random access to indexed data.\nThe following string types can be used to subset a HiCExperiment object with the [ notation:\n\n# \"II\" --> import contacts over an entire chromosome\n# \"II:300001-800000\" --> import on-diagonal contacts within a chromosome\n# \"II:300001-400000|II:600001-700000\" --> import off-diagonal contacts within a chromosome\n# \"II|III\" --> import contacts between two chromosomes\n# \"II:300001-800000|V:1-500000\" --> import contacts between segments of two chromosomes\n# c(\"II\", \"III\", \"IV\") --> import contacts within and between several chromosomes\n\n\n\n\n\n\n\nMore examples for subsetting with [ πŸ‘‡\n\n\n\n\n\n\nSubsetting to a specific on-diagonal genomic location using standard UCSC coordinates query:\n\n\nhic[\"II:800001-813184\"]\n## `HiCExperiment` object with 1,040 contacts over 6 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:800,001-813,184\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 19 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting to a specific off-diagonal genomic location using pairs of coordinates query:\n\n\nhic[\"II:300001-320000|II:800001-813184\"]\n## `HiCExperiment` object with 3 contacts over 6 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300001-320000|II:800001-813184\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 3 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting interactions to retain those constrained within a single chromosome:\n\n\nhic[\"II\"]\n## `HiCExperiment` object with 306,212 contacts over 257 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 18513 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting interactions to retain those between two chromosomes:\n\n\nhic[\"II|IV\"]\n## `HiCExperiment` object with 0 contacts over 0 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:1-813184|IV:1-1531933\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 0 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting interactions to retain those between segments of two chromosomes:\n\n\nhic[\"II:300001-320000|IV:1-100000\"]\n## `HiCExperiment` object with 0 contacts over 0 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300001-320000|IV:1-100000\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 0 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\nSubsetting interactions to retain those constrained within several chromosomes:\n\n\nhic[c('II', 'III', 'IV')]\n## `HiCExperiment` object with 306,212 contacts over 257 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II, III, IV\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 18513 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\nSome notes:\n\nThis last example (subsetting for a vector of several chromosomes) is the only scenario for which [-based in-memory subsetting of pre-imported data is the only way to go, as such subsetting is not possible with focus from disk-stored data.\nAll the other [ subsetting scenarii illustrated above can be achieved more efficiently using the focus argument when importing data into a HiCExperiment object.\nHowever, keep in mind that subsetting preserves extra data, e.g.Β added scores, topologicalFeatures, metadata or pairsFile, whereas this information is lost using focus with import.\n\n\n\n\n\n3.1.3 Zooming on a HiCExperiment\n\nβ€œZooming” refers to dynamically changing the resolution of a HiCExperiment. By zooming a HiCExperiment, one can refine or coarsen the contact matrix. This operation takes aContactFile and focus from an existing HiCExperiment input and re-generates a new HiCExperiment with updated resolution, interactions and scores. Note that zoom will preserve existing metadata, topologicalFeatures and pairsFile information.\n\nhic\n## `HiCExperiment` object with 306,212 contacts over 257 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300,001-813,184\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 18513 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\nzoom(hic, 4000)\n## `HiCExperiment` object with 306,212 contacts over 129 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300,001-813,184\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 4000 \n## interactions: 6800 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\nzoom(hic, 1000)\n## `HiCExperiment` object with 306,212 contacts over 514 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300,001-813,184\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 1000 \n## interactions: 44363 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\n\n\n\n\n\n\nNote\n\n\n\nThe sum of raw counts do not change after zooming, however the number of individual interactions and regions changes.\n\nlength(hic)\n## [1] 18513\nlength(zoom(hic, 1000))\n## [1] 44363\nlength(zoom(hic, 4000))\n## [1] 6800\nsum(scores(hic, \"count\"))\n## [1] 306212\nsum(scores(zoom(hic, 1000), \"count\"))\n## [1] 306212\nsum(scores(zoom(hic, 4000), \"count\"))\n## [1] 306212\n\n\n\n\n\n\n\n\n\nImportant\n\n\n\n\n\nzoom does not change the focus! It only affects the resolution (and consequently, the interactions).\n\nzoom will only work for multi-resolution contact matrices, e.g.Β .mcool or .hic." + }, + { + "objectID": "pages/parsing.html#updating-an-hicexperiment-object", + "href": "pages/parsing.html#updating-an-hicexperiment-object", + "title": "\n3Β  Manipulating Hi-C data in R\n", + "section": "\n3.2 Updating an HiCExperiment object", + "text": "3.2 Updating an HiCExperiment object\n\n\n\n\n\n\nTL;DR: Which HiCExperiment slots are mutable (βœ…) / immutable (⛔️)?\n\n\n\n\n\nfileName(hic): ⛔️ (obtained from disk-stored file)\n\nfocus(hic): πŸ€” (see subsetting section)\n\nresolutions(hic): ⛔️ (obtained from disk-stored file)\n\nresolution(hic): πŸ€” (see zooming section)\n\ninteractions(hic): ⛔️ (obtained from disk-stored file)\n\nscores(hic): βœ…\n\ntopologicalFeatures(hic): βœ…\n\npairsFile(hic): βœ…\n\nmetadata(hic): βœ…\n\n\n\n\n3.2.1 Immutable slots\nAn HiCExperiment object acts as an interface exposing disk-stored data. This implies that the fileName slot itself is immutable (i.e.Β cannot be changed). This should be obvious, as a HiCExperiment has to be associated with a disk-stored contact matrix to properly function (except in some advanced cases developed in next chapters).\nFor this reason, methods to manually modify interactions and resolutions slots are also not exposed in the HiCExperiment package.\nA corollary of this is that the associated regions and anchors of an HiCExperiment should not be modified by hand either, since they are directly linked to interactions.\n\n3.2.2 Mutable slots\nThat being said, HiCExperiment objects are flexible and can be partially modified in memory without having to change/overwrite the original, disk-stored contact matrix.\nSeveral slots can be modified in memory: slots, topologicalFeatures, pairsFile and metadata.\n\n3.2.2.1 scores\n\nWe have seen in the previous chapter that scores are stored in a list and are available using the scores function.\n\nscores(hic)\n## List of length 2\n## names(2): count balanced\n\nhead(scores(hic, \"count\"))\n## [1] 7 92 75 61 38 43\n\nhead(scores(hic, \"balanced\"))\n## [1] 0.009657438 0.076622340 0.054101992 0.042940512 0.040905212 0.029293930\n\nExtra scores can be added to this list, e.g.Β to describe the β€œexpected” interaction frequency for each interaction stored in the HiCExperiment object). This can be achieved using the scores()<- function.\n\nscores(hic, \"random\") <- runif(length(hic))\n\nscores(hic)\n## List of length 3\n## names(3): count balanced random\n\nhead(scores(hic, \"random\"))\n## [1] 0.54008758 0.94741632 0.58497023 0.01735713 0.86688684 0.10343547\n\n\n3.2.2.2 topologicalFeatures\n\nThe end-user can create additional topologicalFeatures or modify the existing ones using the topologicalFeatures()<- function.\n\ntopologicalFeatures(hic, 'CTCF') <- GRanges(c(\n \"II:340-352\", \n \"II:3520-3532\", \n \"II:7980-7992\", \n \"II:9240-9252\" \n))\ntopologicalFeatures(hic, 'CTCF')\n## GRanges object with 4 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] II 340-352 *\n## [2] II 3520-3532 *\n## [3] II 7980-7992 *\n## [4] II 9240-9252 *\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\ntopologicalFeatures(hic, 'loops') <- GInteractions(\n topologicalFeatures(hic, 'CTCF')[rep(1:3, each = 3)],\n topologicalFeatures(hic, 'CTCF')[rep(1:3, 3)]\n)\ntopologicalFeatures(hic, 'loops')\n## GInteractions object with 9 interactions and 0 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2\n## <Rle> <IRanges> <Rle> <IRanges>\n## [1] II 340-352 --- II 340-352\n## [2] II 340-352 --- II 3520-3532\n## [3] II 340-352 --- II 7980-7992\n## [4] II 3520-3532 --- II 340-352\n## [5] II 3520-3532 --- II 3520-3532\n## [6] II 3520-3532 --- II 7980-7992\n## [7] II 7980-7992 --- II 340-352\n## [8] II 7980-7992 --- II 3520-3532\n## [9] II 7980-7992 --- II 7980-7992\n## -------\n## regions: 3 ranges and 0 metadata columns\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\nhic\n## `HiCExperiment` object with 306,212 contacts over 257 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300,001-813,184\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 18513 \n## scores(3): count balanced random \n## topologicalFeatures: compartments(0) borders(0) loops(9) viewpoints(0) CTCF(4) \n## pairsFile: N/A \n## metadata(0):\n\nAll these objects can be used in *Overlap methods, as they all extend the GRanges class of objects.\n\n# ---- This counts the number of times `CTCF` anchors are being used in the \n# `loops` `GInteractions` object\ncountOverlaps(\n query = topologicalFeatures(hic, 'CTCF'), \n subject = topologicalFeatures(hic, 'loops')\n)\n## [1] 5 5 5 0\n\n\n3.2.2.3 pairsFile\n\nIf pairsFile is not specified when importing the ContactFile into a HiCExperiment object, one can add it later.\n\npairsf <- HiContactsData('yeast_wt', 'pairs.gz')\n\n\npairsFile(hic) <- pairsf\nhic\n## `HiCExperiment` object with 306,212 contacts over 257 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:300,001-813,184\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 18513 \n## scores(3): count balanced random \n## topologicalFeatures: compartments(0) borders(0) loops(9) viewpoints(0) CTCF(4) \n## pairsFile: /root/.cache/R/ExperimentHub/1702dcdfa3b_7753 \n## metadata(0):\n\n\n3.2.2.4 metadata\n\nMetadata associated with a HiCExperiment can be updated at any point.\n\nmetadata(hic) <- list(\n info = \"HiCExperiment created from an example .mcool file from `HiContactsData`\", \n date = date()\n)\nmetadata(hic)\n## $info\n## [1] \"HiCExperiment created from an example .mcool file from `HiContactsData`\"\n## \n## $date\n## [1] \"Tue Nov 7 12:45:27 2023\"" + }, + { + "objectID": "pages/parsing.html#coercing-hicexperiment-objects", + "href": "pages/parsing.html#coercing-hicexperiment-objects", + "title": "\n3Β  Manipulating Hi-C data in R\n", + "section": "\n3.3 Coercing HiCExperiment objects", + "text": "3.3 Coercing HiCExperiment objects\nConvenient coercing functions exist to transform data stored as a HiCExperiment into another class.\n\n\nas.matrix(): allows to coerce the HiCExperiment into a sparse or dense matrix (using the sparse logical argument, TRUE by default) and choosing specific scores of interest (using the use.scores argument, \"balanced\" by default).\n\n\n# ----- `as.matrix` coerces a `HiCExperiment` into a `sparseMatrix` by default \nas.matrix(hic) |> class()\n## [1] \"dgTMatrix\"\n## attr(,\"package\")\n## [1] \"Matrix\"\n\nas.matrix(hic) |> dim()\n## [1] 257 257\n\n# ----- One can specify which scores should be used when coercing into a matrix\nas.matrix(hic, use.scores = \"balanced\")[1:5, 1:5]\n## 5 x 5 sparse Matrix of class \"dgTMatrix\"\n## \n## [1,] 0.009657438 0.07662234 0.05410199 0.04294051 0.04090521\n## [2,] 0.076622340 0.05128277 0.09841564 0.06926737 0.05263611\n## [3,] 0.054101992 0.09841564 0.05657589 0.08723160 0.07316890\n## [4,] 0.042940512 0.06926737 0.08723160 0.03699543 0.08403496\n## [5,] 0.040905212 0.05263611 0.07316890 0.08403496 0.04787415\n\nas.matrix(hic, use.scores = \"count\")[1:5, 1:5]\n## 5 x 5 sparse Matrix of class \"dgTMatrix\"\n## \n## [1,] 7 92 75 61 38\n## [2,] 92 102 226 163 81\n## [3,] 75 226 150 237 130\n## [4,] 61 163 237 103 153\n## [5,] 38 81 130 153 57\n\n# ----- If **expressly required**, one can coerce a HiCExperiment into a dense matrix\nas.matrix(hic, use.scores = \"count\", sparse = FALSE)[1:5, 1:5]\n## [,1] [,2] [,3] [,4] [,5]\n## [1,] 7 92 75 61 38\n## [2,] 92 102 226 163 81\n## [3,] 75 226 150 237 130\n## [4,] 61 163 237 103 153\n## [5,] 38 81 130 153 57\n\n\n\nas.data.frame(): simply coercing interactions into a rectangular data frame\n\n\nas.data.frame(hic) |> head()\n## seqnames1 start1 end1 width1 strand1 bin_id1 weight1 center1\n## 1 II 300001 302000 2000 * 266 0.03714342 301000\n## 2 II 300001 302000 2000 * 266 0.03714342 301000\n## 3 II 300001 302000 2000 * 266 0.03714342 301000\n## 4 II 300001 302000 2000 * 266 0.03714342 301000\n## 5 II 300001 302000 2000 * 266 0.03714342 301000\n## 6 II 300001 302000 2000 * 266 0.03714342 301000\n## seqnames2 start2 end2 width2 strand2 bin_id2 weight2 center2 count\n## 1 II 300001 302000 2000 * 266 0.03714342 301000 7\n## 2 II 302001 304000 2000 * 267 0.02242258 303000 92\n## 3 II 304001 306000 2000 * 268 0.01942093 305000 75\n## 4 II 306001 308000 2000 * 269 0.01895202 307000 61\n## 5 II 308001 310000 2000 * 270 0.02898098 309000 38\n## 6 II 310001 312000 2000 * 271 0.01834118 311000 43\n## balanced random\n## 1 0.009657438 0.54008758\n## 2 0.076622340 0.94741632\n## 3 0.054101992 0.58497023\n## 4 0.042940512 0.01735713\n## 5 0.040905212 0.86688684\n## 6 0.029293930 0.10343547\n\n\n\n\n\n\n\nWarning\n\n\n\nThese coercing methods only operate on interactions and scores, and discard all other information, e.g.Β regarding genomic regions, available resolutions, associated metadata, pairsFile or topologicalFeatures." + }, + { + "objectID": "pages/visualization.html", + "href": "pages/visualization.html", + "title": "\n4Β  Hi-C data visualization\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/visualization.html#visualizing-hi-c-contact-maps", + "href": "pages/visualization.html#visualizing-hi-c-contact-maps", + "title": "\n4Β  Hi-C data visualization\n", + "section": "\n4.1 Visualizing Hi-C contact maps", + "text": "4.1 Visualizing Hi-C contact maps\nVisualizing Hi-C contact maps is often a necessary step in exploratory data analysis. A Hi-C contact map is usually displayed as a heatmap, in which:\n\nEach axis represents a section of the genome of interest (either a segment of a chromosome, or several chromosomes, …).\nThe color code aims to represent β€œinteraction frequency”, which can be expressed in β€œraw” counts or normalized (balanced).\nOther metrics can also be displayed in Hi-C heatmaps, e.g.Β ratios of interaction frequency between two Hi-C experiments, p-values of differential interaction analysis, …\nAxes are often identical, representing interactions constrained within a single genomic window, a.k.a. on-diagonal matrices.\nHowever, axes can be different: this is the case when off-diagonal matrices are displayed.\n\n\n4.1.1 Single map\nSimple visualization of disk-stored Hi-C contact matrices can be done by:\n\nImporting the interactions over the genomic location of interest into a HiCExperiment object;\nUsing plotMatrix function (provided by HiContacts) to generate a plot.\n\n\nlibrary(HiContacts)\nplotMatrix(hic)\n\n\n\n\n\n\n\n\n\n\n\n\n\nNote\n\n\n\nA caption summarizing the plotting parameters is added below the heatmap. This can be removed with caption = FALSE.\n\n\n\n4.1.2 Horizontal map\nHi-C maps are sometimes visualized in a β€œhorizontal” style, where a square on-diagonal heatmap is tilted by 45˚ and truncated to only show interactions up to a certain distance from the main diagonal.\nWhen a maxDistance argument is provided to plotMatrix, it automatically generates a horizontal-style heatmap.\n\nplotMatrix(hic, maxDistance = 200000)\n\n\n\n\n\n\n\n\n4.1.3 Side-by-side maps\nSometimes, one may want to visually plot 2 Hi-C samples side by side to compare the interaction landscapes over the same genomic locus. This can be done by adding a second HiCExperiment (imported with the same focus) with the compare.to argument.\nHere, we are importing a second .mcool file corresponding to a Hi-C experiment performed in a eco1 yeast mutant:\n\nhic2 <- import(\n CoolFile(HiContactsData('yeast_eco1', 'mcool')), \n focus = 'V', \n resolution = 2000\n)\n\nWe then plot the 2 matrices side by side. The first will be displayed in the top right corner and the second (provided with compare.to) will be in the bottom left corner.\n\nplotMatrix(hic, compare.to = hic2)\n\n\n\n\n\n\n\n\n4.1.4 Plotting multiple chromosomes\nInteractions from multiple chromosomes can be visualized in a Hi-C heatmap. One needs to (1) first parse the entire contact matrix in R, (2) then subset interactions over chromosomes of interest with [ and (3) use plotMatrix to generate the multi-chromosome plot.\n\nfull_hic <- import(cf, resolution = 4000)\nplotMatrix(full_hic)\n\n\n\n\n\n\nhic_subset <- full_hic[c(\"II\", \"III\", \"IV\")]\nplotMatrix(hic_subset)" + }, + { + "objectID": "pages/visualization.html#hi-c-maps-customization-options", + "href": "pages/visualization.html#hi-c-maps-customization-options", + "title": "\n4Β  Hi-C data visualization\n", + "section": "\n4.2 Hi-C maps customization options", + "text": "4.2 Hi-C maps customization options\nA number of customization options are available for the plotMatrix function. The next subsections focus on how to:\n\nPick the scores of interest to represent in a Hi-C heatmap;\nChange the numeric scale and boundaries;\nChange the color map;\nExtra customization options\n\n\n4.2.1 Choosing scores\nBy default, plotMatrix will attempt to plot balanced (coverage normalized) Hi-C matrices. However, extra scores may be associated with interactions in a HiCExperiment object (more on this in the next chapter)\nFor instance, we can plot the count scores, which are un-normalized raw contact counts directly obtained when binning a .pairs file:\n\nplotMatrix(hic, use.scores = 'count')\n\n\n\n\n\n\n\n\n4.2.2 Choosing scale\nThe color scale is automatically adjusted to range from the minimum to the maximum scores of the HiCExperiment being plotted. This can be adjusted using the limits argument.\n\nplotMatrix(hic, limits = c(-3.5, -1))\n\n\n\n\n\n\n\n\n4.2.3 Choosing color map\n?HiContacts::palettes returns a list of available color maps to use with plotMatrix. Any custom color map can also be used by manually specifying a vector of colors.\n\n# ----- `afmhotr` color map is shipped in the `HiContacts` package\nafmhotrColors() \n## [1] \"#ffffff\" \"#f8f5c3\" \"#f4ee8d\" \"#f6be35\" \"#ee7d32\" \"#c44228\" \"#821d19\"\n## [8] \"#381211\" \"#050606\"\nplotMatrix(\n hic, \n use.scores = 'balanced',\n limits = c(-4, -1),\n cmap = afmhotrColors()\n)" + }, + { + "objectID": "pages/visualization.html#advanced-visualization", + "href": "pages/visualization.html#advanced-visualization", + "title": "\n4Β  Hi-C data visualization\n", + "section": "\n4.3 Advanced visualization", + "text": "4.3 Advanced visualization\n\n4.3.1 Overlaying topological features\nTopological features (e.g.Β chromatin loops, domain borders, A/B compartments, e.g. …) are often displayed over a Hi-C heatmap.\nTo illustrate how to do this, let’s import pre-computed chromatin loops in R. These loops have been identified using chromosight (Matthey-Doret et al. (2020)) on the contact matrix which we imported interactions from.\n\nlibrary(rtracklayer)\nlibrary(InteractionSet)\nloops <- system.file('extdata', 'S288C-loops.bedpe', package = 'HiCExperiment') |> \n import() |> \n makeGInteractionsFromGRangesPairs()\nloops\n## GInteractions object with 162 interactions and 0 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2\n## <Rle> <IRanges> <Rle> <IRanges>\n## [1] I 3001-4000 --- I 29001-30000\n## [2] I 29001-30000 --- I 50001-51000\n## [3] I 95001-96000 --- I 128001-129000\n## [4] I 133001-134000 --- I 157001-158000\n## [5] II 8001-9000 --- II 46001-47000\n## ... ... ... ... ... ...\n## [158] XVI 773001-774000 --- XVI 803001-804000\n## [159] XVI 834001-835000 --- XVI 859001-860000\n## [160] XVI 860001-861000 --- XVI 884001-885000\n## [161] XVI 901001-902000 --- XVI 940001-941000\n## [162] XVI 917001-918000 --- XVI 939001-940000\n## -------\n## regions: 316 ranges and 0 metadata columns\n## seqinfo: 16 sequences from an unspecified genome; no seqlengths\n\nSimilarly, borders have also been mapped with chromosight. We can also import them in R.\n\nborders <- system.file('extdata', 'S288C-borders.bed', package = 'HiCExperiment') |> \n import()\nborders\n## GRanges object with 814 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] I 73001-74000 *\n## [2] I 108001-109000 *\n## [3] I 181001-182000 *\n## [4] II 90001-91000 *\n## [5] II 119001-120000 *\n## ... ... ... ...\n## [810] XVI 777001-778000 *\n## [811] XVI 796001-797000 *\n## [812] XVI 811001-812000 *\n## [813] XVI 890001-891000 *\n## [814] XVI 933001-934000 *\n## -------\n## seqinfo: 16 sequences from an unspecified genome; no seqlengths\n\nChromatin loops are stored in GInteractions while borders are GRanges. The former will be displayed as off-diagonal circles and the later as on-diagonal diamonds on the Hi-C heatmap.\n\nplotMatrix(hic, loops = loops, borders = borders)\n\n\n\n\n\n\n\n\n4.3.2 Aggregated Hi-C maps\nFinally, Hi-C map β€œsnippets” (i.e.Β extracts) are often aggregated together to show an average signal. This analysis is sometimes referred to as APA (Aggregated Plot Analysis).\nAggregated Hi-C maps can be computed over a collection of targets using the aggregate function. These targets can be GRanges (to extract on-diagonal snippets) or GInteractions (to extract off-diagonal snippets). The flankingBins specifies how many matrix bins should be extracted on each side of the targets of interest.\nHere, we compute the aggregated Hi-C snippets of Β± 15kb around each chromatin loop listed in loops.\n\nhic <- zoom(hic, 1000)\naggr_loops <- aggregate(hic, targets = loops, flankingBins = 15)\n## Going through preflight checklist...\n## Parsing the entire contact matrice as a sparse matrix...\n## Modeling distance decay...\n## Filtering for contacts within provided targets...\naggr_loops\n## `AggrHiCExperiment` object over 148 targets \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: 148 targets \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 1000 \n## interactions: 961 \n## scores(4): count balanced expected detrended \n## slices(4): count balanced expected detrended \n## topologicalFeatures: targets(148) compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) \n## pairsFile: N/A \n## metadata(0):\n\naggregate generates a AggrHiCExperiment object, a flavor of HiCExperiment class of objects.\n\n\nAggrHiCExperiment objects have an extra slices slot. This stores a list of arrays, one per scores. Each array is of 3 dimensions, x and y representing the heatmap axes, and z representing the index of the target.\n\nAggrHiCExperiment objects also have a mandatory topologicalFeatures element named targets, storing the genomic loci provided in aggregate.\n\n\nslices(aggr_loops)\n## List of length 4\n## names(4): count balanced expected detrended\ndim(slices(aggr_loops, 'count'))\n## [1] 31 31 148\ntopologicalFeatures(aggr_loops, 'targets')\n## Pairs object with 148 pairs and 0 metadata columns:\n## first second\n## <GRanges> <GRanges>\n## [1] I:14501-44500 I:35501-65500\n## [2] I:80501-110500 I:113501-143500\n## [3] I:118501-148500 I:142501-172500\n## [4] II:33501-63500 II:63501-93500\n## [5] II:134501-164500 II:159501-189500\n## ... ... ...\n## [144] XVI:586501-616500 XVI:606501-636500\n## [145] XVI:733501-763500 XVI:754501-784500\n## [146] XVI:758501-788500 XVI:788501-818500\n## [147] XVI:819501-849500 XVI:844501-874500\n## [148] XVI:845501-875500 XVI:869501-899500\n\nThe resulting AggrHiCExperiment can be plotted using the same plotMatrix function with the arguments described above.\n\nplotMatrix(\n aggr_loops, \n use.scores = 'detrended', \n scale = 'linear', \n limits = c(-1, 1), \n cmap = bgrColors()\n)" + }, + { + "objectID": "pages/matrix-centric.html", + "href": "pages/matrix-centric.html", + "title": "\n5Β  Matrix-centric analysis\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/matrix-centric.html#operations-in-an-individual-matrix", + "href": "pages/matrix-centric.html#operations-in-an-individual-matrix", + "title": "\n5Β  Matrix-centric analysis\n", + "section": "\n5.1 Operations in an individual matrix", + "text": "5.1 Operations in an individual matrix\n\n5.1.1 Balancing a raw interaction count map\nHi-C sequencing coverage is systematically affected by multiple confounding factors, e.g.Β  density of restriction sites, GC%, genome mappability, etc.. Overall, it generally ends up not homogenous throughout the entire genome and this leads to artifacts in un-normalized count matrices.\nTo correct for sequencing coverage heterogeneity of raw count maps, Hi-C data can be normalized using matrix balancing approaches (Cournac et al. (2012), Imakaev et al. (2012)). This is generally done directly on the disk-stored matrices using out-of-memory strategies (e.g.Β with cooler balance <.cool>). However, if contact matrix files are imported into a HiCExperiment object but no balanced scores are available, in-memory balancing can be performed using the normalize function. This adds an extra ICE element in scores list (while the interactions themselves are unmodified).\n\nnormalized_hic <- normalize(hic)\nnormalized_hic\n## `HiCExperiment` object with 471,364 contacts over 407 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 34063 \n## scores(3): count balanced ICE \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) \n## pairsFile: N/A \n## metadata(0):\n\nIt is possible to plot the different scores of the resulting object to visualize the newly computed scores. In this example, ICE scores should be nearly identical to balanced scores, which were originally imported from the disk-stored contact matrix.\n\n\npatchwork::wrap_plots(\n plotMatrix(normalized_hic, use.scores = 'count', caption = FALSE),\n plotMatrix(normalized_hic, use.scores = 'balanced', caption = FALSE),\n plotMatrix(normalized_hic, use.scores = 'ICE', caption = FALSE), \n nrow = 1\n)\n\n\n\n\n\n\n\n\n\n5.1.2 Computing observed/expected (O/E) map\nThe most prominent feature of a balanced Hi-C matrix is the strong main diagonal. This main diagonal is observed because interactions between immediate adjacent genomic loci are more prone to happen than interactions spanning longer genomic distances. This β€œexpected” behavior is due to the polymer nature of the chromosomes being studied, and can be locally estimated using the distance-dependent interaction frequency (a.k.a. the β€œdistance law”, or P(s)). It can be used to compute an expected matrix on interactions.\nWhen it is desirable to β€œmask” this polymer behavior to emphasize topological structures formed by chromosomes, one can divide a given balanced matrix by its expected matrix, i.e.Β calculate the observed/expected (O/E) map. This is sometimes called β€œdetrending”, as it effectively removes the average polymer behavior from the balanced matrix.\nThe detrend function performs this operation on a given HiCExperiment object. It adds two extra elements in scores list: expected and detrended metrics (while the interactions themselves are unmodified).\n\ndetrended_hic <- detrend(hic)\ndetrended_hic\n## `HiCExperiment` object with 471,364 contacts over 407 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 34063 \n## scores(4): count balanced expected detrended \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) \n## pairsFile: N/A \n## metadata(0):\n\nTopological features will be visually more prominent in the O/E detrended Hi-C map.\n\n\npatchwork::wrap_plots(\n plotMatrix(detrended_hic, use.scores = 'balanced', scale = 'log10', limits = c(-3.5, -1.2), caption = FALSE),\n plotMatrix(detrended_hic, use.scores = 'expected', scale = 'log10', limits = c(-3.5, -1.2), caption = FALSE),\n plotMatrix(detrended_hic, use.scores = 'detrended', scale = 'linear', limits = c(-1, 1), cmap = bwrColors(), caption = FALSE), \n nrow = 1\n)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nScale for detrended scores\n\n\n\n\n\nexpected scores are in linear scale and Β± in the same amplitude than balanced scores;\n\ndetrended scores are in log2 scale, in general approximately centered around 0. When plotting detrended scores, scale = linear should be set to prevent the default log10 scaling.\n\n\n\n\n5.1.3 Computing autocorrelated map\nCorrelation matrices are often calculated from balanced Hi-C matrices. For instance, in genomes composed of eu- and heterochromatin, a correlation matrix can be used to reveal a checkerboard pattern emphasizing the segregation of chromatin into two A/B compartments (Lieberman-Aiden et al. (2009)).\nThe autocorrelate function is used to compute a correlation matrix of a HiCExperiment object. For each pair of interacting loci, the autocorrelated score represents the correlation between their respective interaction profiles with the rest of the genome.\n\nautocorr_hic <- autocorrelate(hic)\n## \nautocorr_hic\n## `HiCExperiment` object with 471,364 contacts over 407 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 34063 \n## scores(5): count balanced expected detrended autocorrelated \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) \n## pairsFile: N/A \n## metadata(0):\n\nSince these metrics represent correlation scores, they range between -1 and 1. Two loci with an autocorrelated score close to -1 have anti-correlated interaction profiles, while two loci with a autocorrelated score close to 1 are likely to interact with shared targets.\n\nsummary(scores(autocorr_hic, 'autocorrelated'))\n## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's \n## -0.4156 0.0025 0.0504 0.0645 0.1036 1.0000 564\n\nCorrelated and anti-correlated loci will be visually represented in the autocorrelated Hi-C map in red and blue pixels, respectively.\n\n\n\n\n\n\nNote\n\n\n\nHere we have illustrated how to compute an autocorrelation matrix from a HiCExperiment object using the example yeast Hi-C experiment. Bear in mind that this is unusual and not very useful, as yeast chromatin is not segregated in two compartments but rather follows a Rabl conformation (Duan et al. (2010)). An example of autocorrelation map from a vertebrate Hi-C experiment (for which chromatin is segregated in A/B compartments) is shown in Chapter 10.\n\n\n\nplotMatrix(\n autocorr_hic, \n use.scores = 'autocorrelated', \n scale = 'linear', \n limits = c(-0.4, 0.4), \n cmap = bgrColors()\n)\n\n\n\n\n\n\n\n\n\n\n\n\n\nScale for autocorrelated scores\n\n\n\n\n\nautocorrelated scores are in linear scale, in general approximately centered around 0. When plotting autocorrelated scores, scale = linear should be set to prevent the default log10 scaling.\n\nlimits should be manually set to c(-x, x) (0 < x <= 1) to ensure that the color range is effectively centered on 0.\n\n\n\n\n5.1.4 Despeckling (smoothing out) a contact map\nShallow-sequenced Hi-C libraries or matrices binned with an overly small bin size sometimes produce β€œgrainy” Hi-C maps with noisy backgrounds. A grainy map may also be obtained when dividing two matrices, e.g.Β when computing the O/E ratio with detrend. This is particularly true for sparser long-range interactions. To overcome such limitations, HiCExperiment objects can be β€œdespeckled” to smooth out focal speckles.\n\nhic2 <- detrend(hic['II:400000-700000'])\nhic2 <- despeckle(hic2, use.scores = 'detrended', focal.size = 2)\nhic2\n## `HiCExperiment` object with 168,785 contacts over 150 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II:400,000-700,000\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 2000 \n## interactions: 11325 \n## scores(5): count balanced expected detrended detrended.despeckled \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) centromeres(16) \n## pairsFile: N/A \n## metadata(0):\n\nThe added <use.scores>.despeckled scores correspond to scores averaged using a window, whose width is provided with the focal.size argument. This results in a smoother Hi-C heatmap, effectively removing the β€œspeckles” observed at longer range.\n\n\nlibrary(InteractionSet)\nloops <- system.file('extdata', 'S288C-loops.bedpe', package = 'HiCExperiment') |> \n import() |> \n makeGInteractionsFromGRangesPairs()\nborders <- system.file('extdata', 'S288C-borders.bed', package = 'HiCExperiment') |> \n import()\npatchwork::wrap_plots(\n plotMatrix(hic2, caption = FALSE),\n plotMatrix(hic2, use.scores = 'detrended', scale = 'linear', limits = c(-1, 1), caption = FALSE),\n plotMatrix(\n hic2, \n use.scores = 'detrended.despeckled', \n scale = 'linear', \n limits = c(-1, 1), \n caption = FALSE, \n loops = loops, \n borders = borders\n ),\n nrow = 1\n)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nScale for despeckled scores\n\n\n\ndespeckled scores are in the same scale than the scores they were computed from." + }, + { + "objectID": "pages/matrix-centric.html#operations-between-multiple-matrices", + "href": "pages/matrix-centric.html#operations-between-multiple-matrices", + "title": "\n5Β  Matrix-centric analysis\n", + "section": "\n5.2 Operations between multiple matrices", + "text": "5.2 Operations between multiple matrices\n\n5.2.1 Merging maps\nHi-C libraries are often sequenced in multiple rounds, for example when high genome coverage is required. This results in multiple contact matrix files being generated. The merge function can be used to bind several HiCExperiment objects into a single one.\nThe different HiCExperiment objects do not need to all have identical regions, as shown in the following example.\n\nhic_sub1 <- subsetByOverlaps(hic, GRanges(\"II:100001-200000\"))\nhic_sub2 <- subsetByOverlaps(hic, GRanges(\"II:300001-400000\"))\nbound_hic <- merge(hic_sub1, hic_sub2)\nplotMatrix(bound_hic)\n\n\n\n\n\n\n\n\n5.2.2 Computing ratio between two maps\nComparing two Hi-C maps can be useful to infer which genomic loci are differentially interacting between experimental conditions. Comparing two HiCExperiment objects can be done in R using the divide function.\nFor example, we can divide the eco1 mutant Hi-C data by wild-type Hi-C dataset using the divide function.\n\nhic_eco1 <- import(\n CoolFile(HiContactsData('yeast_eco1', 'mcool')), \n focus = 'II', \n resolution = 2000\n)\n\n\ndiv_contacts <- divide(hic_eco1, by = hic) \ndiv_contacts\n## `HiCExperiment` object with 996,154 contacts over 407 regions \n## -------\n## fileName: N/A \n## focus: \"II\" \n## resolutions(1): 2000\n## active resolution: 2000 \n## interactions: 60894 \n## scores(6): count.x balanced.x count.by balanced.by balanced.fc balanced.l2fc \n## topologicalFeatures: () \n## pairsFile: N/A \n## metadata(2): hce_list operation\n\nWe can visually compare wild-type and eco1 maps side by side (left) and their ratio map (right). This highlights the depletion of short-range and increase of long-range interactions in the eco1 dataset.\n\ncowplot::plot_grid(\n plotMatrix(hic_eco1, compare.to = hic, limits = c(-4, -1)), \n plotMatrix(\n div_contacts, \n use.scores = 'balanced.fc', \n scale = 'log2', \n limits = c(-1, 1),\n cmap = bwrColors()\n )\n)" + }, + { + "objectID": "pages/interactions-centric.html", + "href": "pages/interactions-centric.html", + "title": "\n6Β  Interactions-centric analysis\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/interactions-centric.html#distance-laws", + "href": "pages/interactions-centric.html#distance-laws", + "title": "\n6Β  Interactions-centric analysis\n", + "section": "\n6.1 Distance law(s)", + "text": "6.1 Distance law(s)\n\n6.1.1 P(s) from a single .pairs file\nDistance laws are generally computed directly from .pairs files. This is because the .pairs files are at 1-bp resolution whereas the contact matrices (for example from .cool files) are binned at a minimum resolution.\nAn example .pairs file can be fetched from the ExperimentHub database using the HiContactsData package.\n\nlibrary(HiCExperiment)\nlibrary(HiContactsData)\npairsf <- HiContactsData('yeast_wt', 'pairs.gz')\npf <- PairsFile(pairsf)\n\n\npf\n## PairsFile object\n## resource: /root/.cache/R/ExperimentHub/1702dcdfa3b_7753\n\nIf needed, PairsFile connections can be imported directly into a GInteractions object with import().\n\nimport(pf)\n## GInteractions object with 471364 interactions and 3 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | frag1 frag2\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric> <numeric>\n## [1] II 105 --- II 48548 | 1358 1681\n## [2] II 113 --- II 45003 | 1358 1658\n## [3] II 119 --- II 687251 | 1358 5550\n## [4] II 160 --- II 26124 | 1358 1510\n## [5] II 169 --- II 39052 | 1358 1613\n## ... ... ... ... ... ... . ... ...\n## [471360] II 808605 --- II 809683 | 6316 6320\n## [471361] II 808609 --- II 809917 | 6316 6324\n## [471362] II 808617 --- II 809506 | 6316 6319\n## [471363] II 809447 --- II 809685 | 6319 6321\n## [471364] II 809472 --- II 809675 | 6319 6320\n## distance\n## <integer>\n## [1] 48443\n## [2] 44890\n## [3] 687132\n## [4] 25964\n## [5] 38883\n## ... ...\n## [471360] 1078\n## [471361] 1308\n## [471362] 889\n## [471363] 238\n## [471364] 203\n## -------\n## regions: 549331 ranges and 0 metadata columns\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\nWe can compute a P(s) per chromosome from this .pairs file using the distanceLaw function.\n\nlibrary(HiContacts)\nps <- distanceLaw(pf, by_chr = TRUE) \n## Importing pairs file /root/.cache/R/ExperimentHub/1702dcdfa3b_7753 in memory. This may take a while...\nps\n## # A tibble: 115 Γ— 6\n## chr binned_distance p norm_p norm_p_unity slope\n## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>\n## 1 II 14 0.00000212 0.00000106 2.27 0 \n## 2 II 16 0.0000170 0.0000170 36.4 1.56\n## 3 II 17 0.0000361 0.0000180 38.6 1.55\n## 4 II 19 0.0000424 0.0000212 45.5 1.55\n## 5 II 21 0.0000467 0.0000233 50.0 1.54\n## 6 II 23 0.0000870 0.0000290 62.1 1.53\n## # β„Ή 109 more rows\n\nThe plotPs() and plotPsSlope() functions are convenient ggplot2-based functions with pre-configured settings optimized for P(s) visualization.\n\nlibrary(ggplot2)\nplotPs(ps, aes(x = binned_distance, y = norm_p, color = chr))\n## Warning: Removed 67 rows containing missing values (`geom_line()`).\n\n\n\n\n\n\nplotPsSlope(ps, aes(x = binned_distance, y = slope, color = chr))\n## Warning: Removed 67 rows containing missing values (`geom_line()`).\n\n\n\n\n\n\n\n\n6.1.2 P(s) for multiple .pairs files\nLet’s first import a second example dataset. We’ll import pairs identified in a eco1 yeast mutant.\n\neco1_pairsf <- HiContactsData('yeast_eco1', 'pairs.gz')\neco1_pf <- PairsFile(eco1_pairsf)\n\n\neco1_ps <- distanceLaw(eco1_pf, by_chr = TRUE) \n## Importing pairs file /root/.cache/R/ExperimentHub/f9346a45c35_7755 in memory. This may take a while...\neco1_ps\n## # A tibble: 115 Γ— 6\n## chr binned_distance p norm_p norm_p_unity slope\n## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>\n## 1 II 14 0.00000201 0.00000100 0.660 0 \n## 2 II 16 0.0000221 0.0000221 14.5 1.46\n## 3 II 17 0.0000492 0.0000246 16.2 1.46\n## 4 II 19 0.0000412 0.0000206 13.5 1.45\n## 5 II 21 0.0000653 0.0000326 21.5 1.45\n## 6 II 23 0.0000803 0.0000268 17.6 1.44\n## # β„Ή 109 more rows\n\nA little data wrangling can help plotting the distance laws for 2 different samples in the same plot.\n\nlibrary(dplyr)\nmerged_ps <- rbind(\n ps |> mutate(sample = 'WT'), \n eco1_ps |> mutate(sample = 'eco1')\n)\nplotPs(merged_ps, aes(x = binned_distance, y = norm_p, color = sample, linetype = chr)) + \n scale_color_manual(values = c('#c6c6c6', '#ca0000'))\n## Warning: Removed 134 rows containing missing values (`geom_line()`).\n\n\n\n\n\n\nplotPsSlope(merged_ps, aes(x = binned_distance, y = slope, color = sample, linetype = chr)) + \n scale_color_manual(values = c('#c6c6c6', '#ca0000'))\n## Warning: Removed 135 rows containing missing values (`geom_line()`).\n\n\n\n\n\n\n\n\n6.1.3 P(s) from HiCExperiment objects\nAlternatively, distance laws can be computed from binned matrices directly by providing HiCExperiment objects. For deeply sequenced datasets, this can be significantly faster than when using original .pairs files, but the smoothness of the resulting curves will be greatly impacted, notably at short distances.\n\nps_from_hic <- distanceLaw(hic, by_chr = TRUE) \n## pairsFile not specified. The P(s) curve will be an approximation.\nplotPs(ps_from_hic, aes(x = binned_distance, y = norm_p))\n## Warning: Removed 9 rows containing missing values (`geom_line()`).\n\n\n\n\n\n\nplotPsSlope(ps_from_hic, aes(x = binned_distance, y = slope))\n## Warning: Removed 8 rows containing missing values (`geom_line()`)." + }, + { + "objectID": "pages/interactions-centric.html#cistrans-ratios", + "href": "pages/interactions-centric.html#cistrans-ratios", + "title": "\n6Β  Interactions-centric analysis\n", + "section": "\n6.2 Cis/trans ratios", + "text": "6.2 Cis/trans ratios\nThe ratio between cis interactions and trans interactions is often used to assess the overall quality of a Hi-C dataset. It can be computed per chromosome using the cisTransRatio() function. You will need to provide a genome-wide HiCExperiment to estimate cis/trans ratios!\n\nfull_hic <- import(cf, resolution = 2000)\nct <- cisTransRatio(full_hic) \nct\n## # A tibble: 16 Γ— 6\n## # Groups: chr [16]\n## chr cis trans n_total cis_pct trans_pct\n## <fct> <dbl> <dbl> <dbl> <dbl> <dbl>\n## 1 I 186326 96738 283064 0.658 0.342\n## 2 II 942728 273966 1216694 0.775 0.225\n## 3 III 303980 127087 431067 0.705 0.295\n## 4 IV 1858062 418218 2276280 0.816 0.184\n## 5 V 607090 220873 827963 0.733 0.267\n## 6 VI 280282 127771 408053 0.687 0.313\n## # β„Ή 10 more rows\n\nIt can be plotted using ggplot2-based visualization functions.\n\nggplot(ct, aes(x = chr, y = cis_pct)) + \n geom_col(position = position_stack()) + \n theme_bw() + \n guides(x=guide_axis(angle = 90)) + \n scale_y_continuous(labels = scales::percent) + \n labs(x = 'Chromosomes', y = '% of cis contacts')\n\n\n\n\n\n\n\nCis/trans contact ratios will greatly vary depending on the cell cycle phase the sample is in! For instance, chromosomes during the mitosis phase of the cell cycle have very little trans contacts, due to their structural organization and individualization." + }, + { + "objectID": "pages/interactions-centric.html#virtual-4c-profiles", + "href": "pages/interactions-centric.html#virtual-4c-profiles", + "title": "\n6Β  Interactions-centric analysis\n", + "section": "\n6.3 Virtual 4C profiles", + "text": "6.3 Virtual 4C profiles\nInteraction profile of a genomic locus of interest with its surrounding environment or the rest of the genome is frequently generated. In some cases, this can help in identifying and/or comparing regulatory or structural interactions.\nFor instance, we can compute the genome-wide virtual 4C profile of interactions anchored at the centromere in chromosome II (located at ~ 238kb).\n\nlibrary(GenomicRanges)\nv4C <- virtual4C(full_hic, viewpoint = GRanges(\"II:230001-240000\"))\nv4C\n## GRanges object with 6045 ranges and 4 metadata columns:\n## seqnames ranges strand | score viewpoint\n## <Rle> <IRanges> <Rle> | <numeric> <character>\n## [1] I 1-2000 * | 0.00000000 II:230001-240000\n## [2] I 2001-4000 * | 0.00000000 II:230001-240000\n## [3] I 4001-6000 * | 0.00129049 II:230001-240000\n## [4] I 6001-8000 * | 0.00000000 II:230001-240000\n## [5] I 8001-10000 * | 0.00000000 II:230001-240000\n## ... ... ... ... . ... ...\n## [6041] XVI 940001-942000 * | 0.000775721 II:230001-240000\n## [6042] XVI 942001-944000 * | 0.000000000 II:230001-240000\n## [6043] XVI 944001-946000 * | 0.000000000 II:230001-240000\n## [6044] XVI 946001-948000 * | 0.000000000 II:230001-240000\n## [6045] XVI 948001-948066 * | 0.000000000 II:230001-240000\n## center in_viewpoint\n## <numeric> <logical>\n## [1] 1000.5 FALSE\n## [2] 3000.5 FALSE\n## [3] 5000.5 FALSE\n## [4] 7000.5 FALSE\n## [5] 9000.5 FALSE\n## ... ... ...\n## [6041] 941000 FALSE\n## [6042] 943000 FALSE\n## [6043] 945000 FALSE\n## [6044] 947000 FALSE\n## [6045] 948034 FALSE\n## -------\n## seqinfo: 16 sequences from an unspecified genome; no seqlengths\n\nggplot2 can be used to visualize the 4C-like profile over multiple chromosomes.\n\n\ndf <- as_tibble(v4C)\nggplot(df, aes(x = center, y = score)) + \n geom_area(position = \"identity\", alpha = 0.5) + \n theme_bw() + \n labs(x = \"Position\", y = \"Contacts with viewpoint\") +\n scale_x_continuous(labels = scales::unit_format(unit = \"M\", scale = 1e-06)) + \n facet_wrap(~seqnames, scales = 'free_y')\n\n\n\n\n\n\n\n\nThis clearly highlights trans interactions of the chromosome II centromere with the centromeres from other chromosomes." + }, + { + "objectID": "pages/interactions-centric.html#scalograms", + "href": "pages/interactions-centric.html#scalograms", + "title": "\n6Β  Interactions-centric analysis\n", + "section": "\n6.4 Scalograms", + "text": "6.4 Scalograms\nScalograms were introduced in Lioy et al. (2018) to investigate distance-dependent contact frequencies for individual genomic bins along chromosomes.\nTo generate a scalogram, one needs to provide a HiCExperiment object with a valid associated pairsFile.\n\npairsFile(hic) <- pairsf\nscalo <- scalogram(hic) \n## Importing pairs file /root/.cache/R/ExperimentHub/1702dcdfa3b_7753 in memory. This may take a while...\nplotScalogram(scalo |> filter(chr == 'II'), ylim = c(1e3, 1e5))\n\n\n\n\n\n\n\nSeveral scalograms can be plotted together to compare distance-dependent contact frequencies along a given chromosome in different samples.\n\n\neco1_hic <- import(\n CoolFile(HiContactsData('yeast_eco1', 'mcool')), \n focus = 'II', \n resolution = 2000\n)\n## see ?HiContactsData and browseVignettes('HiContactsData') for documentation\n## loading from cache\neco1_pairsf <- HiContactsData('yeast_eco1', 'pairs.gz')\n## see ?HiContactsData and browseVignettes('HiContactsData') for documentation\n## loading from cache\npairsFile(eco1_hic) <- eco1_pairsf\neco1_scalo <- scalogram(eco1_hic) \n## Importing pairs file /root/.cache/R/ExperimentHub/f9346a45c35_7755 in memory. This may take a while...\nmerged_scalo <- rbind(\n scalo |> mutate(sample = 'WT'), \n eco1_scalo |> mutate(sample = 'eco1')\n)\nplotScalogram(merged_scalo |> filter(chr == 'II'), ylim = c(1e3, 1e5)) + \n facet_grid(~sample)\n\n\n\n\n\n\n\n\nThis example points out the overall longer interactions within the long arm of the chromosome II in an eco1 mutant." + }, + { + "objectID": "pages/topological-features.html", + "href": "pages/topological-features.html", + "title": "\n7Β  Finding topological features in Hi-C\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/topological-features.html#chromosome-compartments", + "href": "pages/topological-features.html#chromosome-compartments", + "title": "\n7Β  Finding topological features in Hi-C\n", + "section": "\n7.1 Chromosome compartments", + "text": "7.1 Chromosome compartments\nChromosome compartments refer to the segregation of the chromatin into active euchromatin (A compartments) and regulated heterochromatin (B compartment).\n\n7.1.1 Importing Hi-C data\nTo investigate chromosome compartments, we will fetch a contact matrix generated from a micro-C experiment (from Krietenstein et al. (2020)). A subset of the genome-wide dataset is provided in the OHCA package. It contains intra-chromosomal interactions within chr17, binned at 5000, 100000 and 250000 bp.\n\nlibrary(HiCExperiment)\nlibrary(OHCA)\ncf <- fs::path_package('OHCA', 'extdata', 'chr17.mcool')\nmicroC <- import(cf, resolution = 250000)\nmicroC\n## `HiCExperiment` object with 10,086,710 contacts over 334 regions \n## -------\n## fileName: \"/tmp/RtmpixmP1F/Rinst529f91dd/OHCA/extdata/chr17.mcool\" \n## focus: \"whole genome\" \n## resolutions(3): 5000 100000 250000\n## active resolution: 250000 \n## interactions: 52755 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\nseqinfo(microC)\n## Seqinfo object with 1 sequence from an unspecified genome:\n## seqnames seqlengths isCircular genome\n## chr17 83257441 NA <NA>\n\n\n7.1.2 Annotating A/B compartments\nThe consensus approach to annotate A/B compartments is to compute the eigenvectors of a Hi-C contact matrix and identify the eigenvector representing the chromosome-wide bi-partite segmentation of the genome.\nThe getCompartments() function performs several internal operations to achieve this:\n\nObtains cis interactions per chromosome\nComputes O/E contact matrix scores\nComputes 3 first eigenvectors of this Hi-C contact matrix\nNormalizes eigenvectors\nPicks the eigenvector that has the greatest absolute correlation with a phasing track (e.g.Β a GC% track automatically computed from a genome reference sequence, or a gene density track)\nSigns this eigenvector so that positive values represent the A compartment\n\n\nphasing_track <- BSgenome.Hsapiens.UCSC.hg38::BSgenome.Hsapiens.UCSC.hg38\nmicroC_compts <- getCompartments(microC, genome = phasing_track)\n## Going through preflight checklist...\n## Parsing intra-chromosomal contacts for each chromosome...\n## Computing eigenvectors for each chromosome...\n\nmicroC_compts\n## `HiCExperiment` object with 10,086,710 contacts over 334 regions \n## -------\n## fileName: \"/tmp/RtmpixmP1F/Rinst529f91dd/OHCA/extdata/chr17.mcool\" \n## focus: \"whole genome\" \n## resolutions(3): 5000 100000 250000\n## active resolution: 250000 \n## interactions: 52755 \n## scores(2): count balanced \n## topologicalFeatures: compartments(41) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(1): eigens\n\ngetCompartments() is an endomorphism: it returns the original object, enriched with two new pieces of information:\n\nA compartments topologicalFeatures:\n\n\ntopologicalFeatures(microC_compts, \"compartments\")\n## GRanges object with 41 ranges and 1 metadata column:\n## seqnames ranges strand | compartment\n## <Rle> <IRanges> <Rle> | <character>\n## [1] chr17 250001-3000000 * | A\n## [2] chr17 3000001-3500000 * | B\n## [3] chr17 3500001-5500000 * | A\n## [4] chr17 5500001-6500000 * | B\n## [5] chr17 6500001-8500000 * | A\n## ... ... ... ... . ...\n## [37] chr17 72750001-73250000 * | A\n## [38] chr17 73250001-74750000 * | B\n## [39] chr17 74750001-79250000 * | A\n## [40] chr17 79250001-79750000 * | B\n## [41] chr17 79750001-83250000 * | A\n## -------\n## seqinfo: 1 sequence from an unspecified genome\n\n\nThe calculated eigenvectors stored in metadata:\n\n\nmetadata(microC_compts)$eigens\n## GRanges object with 334 ranges and 9 metadata columns:\n## seqnames ranges strand |\n## <Rle> <IRanges> <Rle> |\n## chr17.chr17_1_250000 chr17 1-250000 * |\n## chr17.chr17_250001_500000 chr17 250001-500000 * |\n## chr17.chr17_500001_750000 chr17 500001-750000 * |\n## chr17.chr17_750001_1000000 chr17 750001-1000000 * |\n## chr17.chr17_1000001_1250000 chr17 1000001-1250000 * |\n## ... ... ... ... .\n## chr17.chr17_82250001_82500000 chr17 82250001-82500000 * |\n## chr17.chr17_82500001_82750000 chr17 82500001-82750000 * |\n## chr17.chr17_82750001_83000000 chr17 82750001-83000000 * |\n## chr17.chr17_83000001_83250000 chr17 83000001-83250000 * |\n## chr17.chr17_83250001_83257441 chr17 83250001-83257441 * |\n## bin_id weight chr center\n## <numeric> <numeric> <Rle> <integer>\n## chr17.chr17_1_250000 0 NaN chr17 125000\n## chr17.chr17_250001_500000 1 0.00626903 chr17 375000\n## chr17.chr17_500001_750000 2 0.00567190 chr17 625000\n## chr17.chr17_750001_1000000 3 0.00528588 chr17 875000\n## chr17.chr17_1000001_1250000 4 0.00464628 chr17 1125000\n## ... ... ... ... ...\n## chr17.chr17_82250001_82500000 329 0.00463044 chr17 82375000\n## chr17.chr17_82500001_82750000 330 0.00486910 chr17 82625000\n## chr17.chr17_82750001_83000000 331 0.00561269 chr17 82875000\n## chr17.chr17_83000001_83250000 332 0.00546433 chr17 83125000\n## chr17.chr17_83250001_83257441 333 NaN chr17 83253721\n## E1 E2 E3 phasing\n## <numeric> <numeric> <numeric> <numeric>\n## chr17.chr17_1_250000 0.000000 0.000000 0.000000 0.383084\n## chr17.chr17_250001_500000 0.450991 0.653287 0.615300 0.433972\n## chr17.chr17_500001_750000 0.716784 0.707461 0.845033 0.465556\n## chr17.chr17_750001_1000000 0.904423 0.414952 0.864288 0.503592\n## chr17.chr17_1000001_1250000 0.913023 0.266287 0.759016 0.547712\n## ... ... ... ... ...\n## chr17.chr17_82250001_82500000 1.147060 0.239112 1.133498 0.550872\n## chr17.chr17_82500001_82750000 1.106937 0.419647 1.169464 0.513212\n## chr17.chr17_82750001_83000000 0.818990 0.591955 0.850340 0.522432\n## chr17.chr17_83000001_83250000 0.874038 0.503175 0.847926 0.528448\n## chr17.chr17_83250001_83257441 0.000000 0.000000 0.000000 0.000000\n## eigen\n## <numeric>\n## chr17.chr17_1_250000 0.000000\n## chr17.chr17_250001_500000 0.450991\n## chr17.chr17_500001_750000 0.716784\n## chr17.chr17_750001_1000000 0.904423\n## chr17.chr17_1000001_1250000 0.913023\n## ... ...\n## chr17.chr17_82250001_82500000 1.147060\n## chr17.chr17_82500001_82750000 1.106937\n## chr17.chr17_82750001_83000000 0.818990\n## chr17.chr17_83000001_83250000 0.874038\n## chr17.chr17_83250001_83257441 0.000000\n## -------\n## seqinfo: 1 sequence from an unspecified genome\n\n\n7.1.3 Exporting compartment tracks\nTo save the eigenvector (as a bigwig file) and the compartments(as a gff file), the export function can be used:\n\nlibrary(GenomicRanges)\nlibrary(rtracklayer)\ncoverage(metadata(microC_compts)$eigens, weight = 'eigen') |> export('microC_eigen.bw')\ntopologicalFeatures(microC_compts, \"compartments\") |> export('microC_compartments.gff3')\n\n\n7.1.4 Visualizing compartment tracks\nCompartment tracks should be visualized in a dedicated genome browser, with the phasing track loaded as well, to ensure they are phased accordingly.\nThat being said, it is possible to visualize a genome track in R besides the matching Hi-C contact matrix.\n\nlibrary(ggplot2)\nlibrary(patchwork)\nmicroC <- autocorrelate(microC)\n## \np1 <- plotMatrix(microC, use.scores = 'autocorrelated', scale = 'linear', limits = c(-1, 1), caption = FALSE)\neigen <- coverage(metadata(microC_compts)$eigens, weight = 'eigen')[[1]]\neigen_df <- tibble(pos = cumsum(runLength(eigen)), eigen = runValue(eigen))\np2 <- ggplot(eigen_df, aes(x = pos, y = eigen)) + \n geom_area() + \n theme_void() + \n coord_cartesian(expand = FALSE) + \n labs(x = \"Genomic position\", y = \"Eigenvector value\")\nwrap_plots(p1, p2, ncol = 1, heights = c(10, 1))\n\n\n\n\n\n\n\nHere, we clearly note the concordance between the Hi-C correlation matrix, highlighting correlated interactions between pairs of genomic segments, and the eigenvector representing chromosome segmentation into 2 compartments: A (for positive values) and B (for negative values).\n\n7.1.5 Saddle plots\nSaddle plots are typically used to measure the observed vs.Β expected interaction scores within or between genomic loci belonging to A and B compartments.\nNon-overlapping genomic windows are grouped in nbins quantiles (typically between 10 and 50 quantiles) according to their A/B compartment eigenvector value, from lowest eigenvector values (i.e.Β strongest B compartments) to highest eigenvector values (i.e.Β strongest A compartments). The average observed vs.Β expected interaction scores are then computed for pairwise eigenvector quantiles and plotted in a 2D heatmap.\n\nlibrary(BiocParallel)\nplotSaddle(microC_compts, nbins = 25, BPPARAM = SerialParam(progressbar = FALSE))\n\n\n\n\n\n\n\nHere, the top-left small corner represents average O/E scores between strong B compartments and the bottom-right larger corner represents average O/E scores between strong A compartments. Note that only chr17 interactions are contained in this dataset, explaining the grainy aspect of the saddle plot." + }, + { + "objectID": "pages/topological-features.html#topological-domains", + "href": "pages/topological-features.html#topological-domains", + "title": "\n7Β  Finding topological features in Hi-C\n", + "section": "\n7.2 Topological domains", + "text": "7.2 Topological domains\nTopological domains (a.k.a. Topologically Associating Domains, TADs, isolated neighborhoods, contact domains, …) refer to local chromosomal segments (e.b. roughly ≀ 1Mb in mammal genomes) which preferentially self-interact, in a constrained manner. They are demarcated by domain boundaries.\n\n\n\n\nThey are generally conserved across cell types and species (Schmitt et al. (2016)), typically correlate with units of DNA replication (Pope et al. (2014)), and could play a role during development (Stadhouders et al. (2019)).\n\n7.2.1 Computing diamond insulation score\nSeveral approaches exist to annotate topological domains (Sefer (2022)). Several packages in R implement some of these functionalities, e.g.Β spectralTAD or TADcompare.\nHiContacts offers a simple getDiamondInsulation function which computes the diamond insulation score (Crane et al. (2015)). This score quantifies average interaction frequency in an insulation window (of a certain window_size) sliding along contact matrices at a chosen resolution.\n\n# - Compute insulation score\nbpparam <- SerialParam(progressbar = FALSE)\nhic <- zoom(microC, 5000) |> \n refocus('chr17:60000001-83257441') |>\n getDiamondInsulation(window_size = 100000, BPPARAM = bpparam) |> \n getBorders()\n## Going through preflight checklist...\n## Scan each window and compute diamond insulation score...\n## Annotating diamond score prominence for each window...\n\nhic\n## `HiCExperiment` object with 2,156,222 contacts over 4,652 regions \n## -------\n## fileName: \"/tmp/RtmpixmP1F/Rinst529f91dd/OHCA/extdata/chr17.mcool\" \n## focus: \"chr17:60,000,001-83,257,441\" \n## resolutions(3): 5000 100000 250000\n## active resolution: 5000 \n## interactions: 2156044 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(21) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(1): insulation\n\ngetDiamondInsulation() is an endomorphism: it returns the original object, enriched with two new pieces of information:\n\nA borders topologicalFeatures:\n\n\ntopologicalFeatures(hic, \"borders\")\n## GRanges object with 21 ranges and 1 metadata column:\n## seqnames ranges strand | score\n## <Rle> <IRanges> <Rle> | <numeric>\n## strong chr17 60105001-60110000 * | 0.574760\n## weak chr17 60210001-60215000 * | 0.414425\n## weak chr17 61415001-61420000 * | 0.346668\n## strong chr17 61500001-61505000 * | 0.544336\n## weak chr17 62930001-62935000 * | 0.399794\n## ... ... ... ... . ...\n## weak chr17 78395001-78400000 * | 0.235613\n## weak chr17 79065001-79070000 * | 0.236535\n## weak chr17 80155001-80160000 * | 0.284855\n## weak chr17 81735001-81740000 * | 0.497478\n## strong chr17 81840001-81845000 * | 1.395949\n## -------\n## seqinfo: 1 sequence from an unspecified genome\n\n\nThe calculated insulation scores stored in metadata:\n\n\nmetadata(hic)$insulation\n## GRanges object with 4611 ranges and 8 metadata columns:\n## seqnames ranges strand | bin_id\n## <Rle> <IRanges> <Rle> | <numeric>\n## chr17_60100001_60105000 chr17 60100001-60105000 * | 12020\n## chr17_60105001_60110000 chr17 60105001-60110000 * | 12021\n## chr17_60110001_60115000 chr17 60110001-60115000 * | 12022\n## chr17_60115001_60120000 chr17 60115001-60120000 * | 12023\n## chr17_60120001_60125000 chr17 60120001-60125000 * | 12024\n## ... ... ... ... . ...\n## chr17_83130001_83135000 chr17 83130001-83135000 * | 16626\n## chr17_83135001_83140000 chr17 83135001-83140000 * | 16627\n## chr17_83140001_83145000 chr17 83140001-83145000 * | 16628\n## chr17_83145001_83150000 chr17 83145001-83150000 * | 16629\n## chr17_83150001_83155000 chr17 83150001-83155000 * | 16630\n## weight chr center score insulation\n## <numeric> <Rle> <integer> <numeric> <numeric>\n## chr17_60100001_60105000 0.0406489 chr17 60102500 0.188061 -0.750142\n## chr17_60105001_60110000 0.0255539 chr17 60107500 0.180860 -0.806466\n## chr17_60110001_60115000 NaN chr17 60112500 0.196579 -0.686232\n## chr17_60115001_60120000 NaN chr17 60117500 0.216039 -0.550046\n## chr17_60120001_60125000 NaN chr17 60122500 0.230035 -0.459489\n## ... ... ... ... ... ...\n## chr17_83130001_83135000 0.0314684 chr17 83132500 0.262191 -0.270723\n## chr17_83135001_83140000 0.0307197 chr17 83137500 0.240779 -0.393632\n## chr17_83140001_83145000 0.0322810 chr17 83142500 0.219113 -0.529664\n## chr17_83145001_83150000 0.0280840 chr17 83147500 0.199645 -0.663900\n## chr17_83150001_83155000 0.0272775 chr17 83152500 0.180434 -0.809873\n## min prominence\n## <logical> <numeric>\n## chr17_60100001_60105000 FALSE NA\n## chr17_60105001_60110000 TRUE 0.57476\n## chr17_60110001_60115000 FALSE NA\n## chr17_60115001_60120000 FALSE NA\n## chr17_60120001_60125000 FALSE NA\n## ... ... ...\n## chr17_83130001_83135000 FALSE NA\n## chr17_83135001_83140000 FALSE NA\n## chr17_83140001_83145000 FALSE NA\n## chr17_83145001_83150000 FALSE NA\n## chr17_83150001_83155000 FALSE NA\n## -------\n## seqinfo: 1 sequence from an unspecified genome\n\n\n\n\n\n\n\nNote\n\n\n\nThe getDiamondInsulation function can be parallelized over multiple threads by specifying the Bioconductor generic BPPARAM argument.\n\n\n\n7.2.2 Exporting insulation scores tracks\nTo save the diamond insulation scores (as a bigwig file) and the borders (as a bed file), the export function can be used:\n\ncoverage(metadata(hic)$insulation, weight = 'insulation') |> export('microC_insulation.bw')\ntopologicalFeatures(hic, \"borders\") |> export('microC_borders.bed')\n\n\n7.2.3 Visualizing chromatin domains\nInsulation tracks should be visualized in a dedicated genome browser.\nThat being said, it is possible to visualize a genome track in R besides the matching Hi-C contact matrix.\n\nhic <- zoom(hic, 100000)\np1 <- plotMatrix(\n hic, \n use.scores = 'balanced', \n limits = c(-3.5, -1),\n borders = topologicalFeatures(hic, \"borders\"),\n caption = FALSE\n)\ninsulation <- coverage(metadata(hic)$insulation, weight = 'insulation')[[1]]\ninsulation_df <- tibble(pos = cumsum(runLength(insulation)), insulation = runValue(insulation))\np2 <- ggplot(insulation_df, aes(x = pos, y = insulation)) + \n geom_area() + \n theme_void() + \n coord_cartesian(expand = FALSE) + \n labs(x = \"Genomic position\", y = \"Diamond insulation score\")\nwrap_plots(p1, p2, ncol = 1, heights = c(10, 1))\n\n\n\n\n\n\n\nLocal minima in the diamond insulation score displayed below the Hi-C contact matrix are identified using the getBorders() function, which automatically estimates a minimum threshold. These local minima correspond to borders and are visually depicted on the Hi-C map by blue diamonds." + }, + { + "objectID": "pages/topological-features.html#chromatin-loops", + "href": "pages/topological-features.html#chromatin-loops", + "title": "\n7Β  Finding topological features in Hi-C\n", + "section": "\n7.3 Chromatin loops", + "text": "7.3 Chromatin loops\n\n7.3.1 chromosight\n\nChromatin loops, dots, or contacts, refer to a strong increase of interaction frequency between a pair of two genomic loci. They correspond to focal β€œdots” on a Hi-C map. Relying on computer vision algorithms, chromosight uses this property to annotate chromatin loops in a Hi-C map (Matthey-Doret et al. (2020)). chromosight is a standalone python package and is made available in R through the HiCool-managed conda environment with the getLoops() function.\n\n7.3.1.1 Identifying loops\n\nhic <- HiCool::getLoops(microC, resolution = 5000)\n\nhic\n## `HiCExperiment` object with 917,156 contacts over 100 regions\n## -------\n## fileName: \"/home/rsg/.cache/R/fourDNData/4d434d8538a0_4DNFI9FVHJZQ.mcool\"\n## focus: \"chr17:63,000,001-63,500,000\"\n## resolutions(13): 1000 2000 ... 5000000 10000000\n## active resolution: 5000\n## interactions: 5047\n## scores(2): count balanced\n## topologicalFeatures: compartments(0) borders(0) loops(66411) viewpoints(0)\n## pairsFile: N/A\n## metadata(1): chromosight_args\n\ngetLoops() is an endomorphism: it returns the original object, enriched with two new pieces of information:\n\nA loops topologicalFeatures:\n\n\ntopologicalFeatures(hic, \"loops\")\n## GInteractions object with 66411 interactions and 5 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | bin_id1 bin_id2 score ## pvalue qvalue\n## <Rle> <IRanges> <Rle> <IRanges> | <numeric> <numeric> <numeric> ## <numeric> <numeric>\n## [1] chr1 775001-780000 --- chr1 850001-855000 | 155 170 0.334586 2.## 15995e-05 2.162e-05\n## [2] chr1 775001-780000 --- chr1 865001-870000 | 155 173 0.403336 1.## 62900e-07 1.669e-07\n## [3] chr1 865001-870000 --- chr1 890001-895000 | 173 178 0.337344 1.## 91400e-07 1.957e-07\n## [4] chr1 910001-915000 --- chr1 955001-960000 | 182 191 0.639725 0.## 00000e+00 0.000e+00\n## [5] chr1 910001-915000 --- chr1 1055001-1060000 | 182 211 0.521699 0.## 00000e+00 0.000e+00\n## ... ... ... ... ... ... . ... ... ... ## ... ...\n## [66407] chrY 19570001-19575000 --- chrY 19720001-19725000 | 610133 610163 0.315529 3.## 30e-08 3.55e-08\n## [66408] chrY 19705001-19710000 --- chrY 19730001-19735000 | 610160 610165 0.708753 0.## 00e+00 0.00e+00\n## [66409] chrY 19765001-19770000 --- chrY 19800001-19805000 | 610172 610179 0.373635 1.## 10e-09 1.40e-09\n## [66410] chrY 20555001-20560000 --- chrY 20645001-20650000 | 610330 610348 0.603308 0.## 00e+00 0.00e+00\n## [66411] chrY 21015001-21020000 --- chrY 21055001-21060000 | 610422 610430 0.394614 9.## 12e-08 9.45e-08\n## -------\n## regions: 84171 ranges and 0 metadata columns\n## seqinfo: 24 sequences from an unspecified genome; no seqlengths\n\n\nThe arguments used by chromosight, stored in metadata:\n\n\nmetadata(hic)$chromosight_args\n## $`--pattern`\n## [1] \"loops\"\n## \n## $`--dump`\n## [1] \"/data/.cache/R//RtmpSaRwiZ\"\n## \n## $`--inter`\n## [1] FALSE\n## \n## $`--iterations`\n## [1] \"auto\"\n## \n## $`--kernel-config`\n## NULL\n## \n## $`--perc-zero`\n## [1] \"auto\"\n## \n## $`--perc-undetected`\n## [1] \"auto\"\n## \n## $`--tsvd`\n## [1] FALSE\n## \n## $`--win-fmt`\n## [1] \"json\"\n## \n## $`--win-size`\n## [1] \"auto\"\n## \n## $`--no-plotting`\n## [1] TRUE\n## \n## $`--smooth-trend`\n## [1] FALSE\n## \n## $`--norm`\n## [1] \"auto\"\n## \n## $`<contact_map>`\n## [1] \"/home/rsg/.cache/R/fourDNData/4d434d8538a0_4DNFI9FVHJZQ.mcool::/resolutions/5000\"\n## \n## $`--max-dist`\n## [1] \"auto\"\n## \n## $`--min-dist`\n## [1] \"auto\"\n## \n## $`--min-separation`\n## [1] \"auto\"\n## \n## $`--n-mads`\n## [1] 5\n## \n## $`<prefix>`\n## [1] \"chromosight/chromo\"\n## \n## $`--pearson`\n## [1] \"auto\"\n## \n## $`--subsample`\n## [1] \"no\"\n## \n## $`--threads`\n## [1] 1\n\n\n7.3.1.2 Importing loops from files\nIf you are using chromosight directly from the terminal (i.e.Β outside R), you can import the annotated loops in R as follows:\n\ndf <- readr::read_tsv(\"...\") ## Here put your loops file\nloops <- InteractionSet::GInteractions(\n anchor1 = GenomicRanges::GRanges(\n df$chrom1, IRanges::IRanges(df$start1+1, df$end1)\n ),\n anchor2 = GenomicRanges::GRanges(\n df$chrom2, IRanges::IRanges(df$start2+1, df$end2)\n ),\n bin_id1 = df$bin1, \n bin_id2 = df$bin2, \n score = df$score, \n pvalue = df$pvalue, \n qvalue = df$qvalue\n)\n\n\n7.3.1.3 Exporting chromatin loops\n\nloops <- topologicalFeatures(hic, \"loops\")\nloops <- loops[loops$score >= 0.4 & loops$qvalue <= 1e-6]\nGenomicInteractions::export.bedpe(loops, 'loops.bedpe')\n\n\n7.3.1.4 Visualizing chromatin loops\n\nplotMatrix(\n refocus(hic, 'chr17:62500001-63500000') |> zoom(5000), \n loops = loops,\n limits = c(-4, -1.2),\n caption = FALSE\n)\n\n\n\n7.3.2 Other R packages\nA number of other R packages have been developed to identify focal chromatin loops, notably fitHiC (Ay et al. (2014)), GOTHiC (Mifsud et al. (2017)) or idr2d (Krismer et al. (2020)). Each fits a slightly different purpose, and we encourage the end user to read companion publications." + }, + { + "objectID": "pages/disseminating.html", + "href": "pages/disseminating.html", + "title": "\n8Β  Data gateways: accessing public Hi-C data portals\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/disseminating.html#dn-data-portal", + "href": "pages/disseminating.html#dn-data-portal", + "title": "\n8Β  Data gateways: accessing public Hi-C data portals\n", + "section": "\n8.1 4DN data portal", + "text": "8.1 4DN data portal\nThe 4D Nucleome Data Coordination and Integration Center (DCIC) has developed and actively maintains a data portal providing public access to a wealth of resources to investigate 3D chromatin architecture. Notably, 3D chromatin conformation libraries relying on different technologies (β€œin situ” or β€œdilution” Hi-C, Capture Hi-C, Micro-C, DNase Hi-C, …), generated by 50+ collaborating labs, were homogenously processed, yielding more than 350 sets of processed files.\nfourDNData (read 4DN-Data) is a package giving programmatic access to these uniformly processed Hi-C contact files.\nThe fourDNData() function provides a gateway to 4DN-hosted Hi-C files, including contact matrices (in .hic or .mcool) and other Hi-C derived files such as annotated compartments, domains, insulation scores, or .pairs files.\n\nlibrary(fourDNData)\nhead(fourDNData())\n## experimentSetAccession fileType size organism experimentType details dataset condition biosource biosourceType publication URL\n## 4DNES18BMU79 pairs 10151.53 mouse in situ Hi-C DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell primary cell Monahan K et al. (2019) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/49504f97-904e-48c1-8c20-1033680b66da/4DNFIC5AHBPV.pairs.gz\n## 4DNES18BMU79 hic 5285.82 mouse in situ Hi-C DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell primary cell Monahan K et al. (2019) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/6cd4378a-8f51-4e65-99eb-15f5c80abf8d/4DNFIT4I5C6Z.hic\n## 4DNES18BMU79 mcool 6110.75 mouse in situ Hi-C DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell primary cell Monahan K et al. (2019) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/01fb704f-2fd7-48c6-91af-c5f4584529ed/4DNFIVPAXJO8.mcool\n## 4DNES18BMU79 boundaries 0.12 mouse in situ Hi-C DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell primary cell Monahan K et al. (2019) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/5c07cdee-53e2-43e0-8853-cfe5f057b3f1/4DNFIR3XCIMA.bed.gz\n## 4DNES18BMU79 insulation 7.18 mouse in situ Hi-C DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell primary cell Monahan K et al. (2019) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/d1f4beb9-701f-4188-abe2-6271fe658770/4DNFIXKKNMS7.bw\n## 4DNES18BMU79 compartments 0.18 mouse in situ Hi-C DpnII Hi-C on Mouse Olfactory System cells Mature olfactory sensory neurons with conditional Ldb1 knockout olfactory receptor cell primary cell Monahan K et al. (2019) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/3d429647-51c8-4e3a-a18b-eec0b1480905/4DNFIN13N8C1.bw\n\n\n8.1.1 Querying individual files\nThe fourDNData() function can be used to directly fetch specific files from the 4DN data portal:\n\ncf <- fourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'mcool')\n## |===================================| 100%\n\nThis effectively downloads and caches the queried file locally.\n\ncf\n## [1] \"/home/rsg/.cache/R/fourDNData/698470d302f0_4DNFI4988896.mcool\"\n\navailableChromosomes(cf)\n## Seqinfo object with 24 sequences from an unspecified genome:\n## seqnames seqlengths isCircular genome\n## chr1 248956422 <NA> <NA>\n## chr2 242193529 <NA> <NA>\n## chr3 198295559 <NA> <NA>\n## chr4 190214555 <NA> <NA>\n## chr5 181538259 <NA> <NA>\n## ... ... ... ...\n## chr20 64444167 <NA> <NA>\n## chr21 46709983 <NA> <NA>\n## chr22 50818468 <NA> <NA>\n## chrX 156040895 <NA> <NA>\n## chrY 57227415 <NA> <NA>\n\navailableResolutions(cf)\n## resolutions(13): 1000 2000 ... 5000000 10000000\n\nimport(cf, focus = \"chr4:10000001-20000000\", resolution = 5000)\n## `HiCExperiment` object with 14,682 contacts over 2,000 regions\n## -------\n## fileName: \"/home/rsg/.cache/R/fourDNData/29051ff3104c_4DNFINSF15ZM.mcool\"\n## focus: \"chr4:10,000,001-20,000,000\"\n## resolutions(13): 1000 2000 ... 5000000 10000000\n## active resolution: 5000\n## interactions: 12016\n## scores(2): count balanced\n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0)\n## pairsFile: N/A\n## metadata(0):\n\nDifferent Hi-C related genomic files are provided by the 4DN consortium. The type of file to fetch can be specified with the type argument:\n\n\ntype = 'pairs' will fetch the pairs file which was generated by the 4DN consortium and binned into a contact matrix. Once fetched from the 4DN data portal, the local file can be imported in R using the import function, which will generate a GInteractions object.\n\n\nfourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'pairs') |> \n import()\n## GInteractions object with 13821669 interactions and 3 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2 | frag1 frag2 distance\n## <Rle> <IRanges> <Rle> <IRanges> | <character> <numeric> <integer>\n## [1] chr1 3000003 --- chr1 88307603 | UU 22 85307600\n## [2] chr1 3000022 --- chr1 28227919 | UU 50 25227897\n## [3] chr1 3000023 --- chr1 50187758 | RU 35 47187735\n## [4] chr1 3000024 --- chr1 4090828 | RU 9 1090804\n## [5] chr1 3000024 --- chr1 35080614 | UU 3 32080590\n## ... ... ... ... ... ... . ... ... ...\n## [13821665] chr1 24472292 --- chr1 24472986 | UU 60 694\n## [13821666] chr1 24472292 --- chr1 24805552 | RU 60 333260\n## [13821667] chr1 24472292 --- chr1 24874144 | UU 60 401852\n## [13821668] chr1 24472294 --- chr1 115668400 | UU 60 91196106\n## [13821669] chr1 24472295 --- chr1 43307467 | UU 60 18835172\n\n\n\n\n\n\n\nWatch out\n\n\n\n.pairs files can be particularly large and therefore will take both and long time to download and a large storage footprint.\n\n\n\n\ntype = 'insulation' will fetch a .bigwig track file precomputed by the 4DN consortium. This track corresponds to the genome-wide insulation score computed by cooltools as described in Crane et al. (2015). To know more about this, read the excerpt from 4DN data portal. Once fetched from the 4DN data portal, the local file can be imported in R using the import function, which will generate a RleList object.\n\n\nfourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'insulation') |> \n import(as = 'Rle')\n## |===================================| 100%\n## RleList of length 21\n## $chr1\n## numeric-Rle of length 195471971 with 38145 runs\n## Lengths: 3065000 5000 ... 5000 171971\n## Values : 0.00000e+00 1.01441e-01 ... 0.807009 0.000000\n## \n## $chr10\n## numeric-Rle of length 130694993 with 25100 runs\n## Lengths: 3175000 5000 5000 ... 5000 169993\n## Values : 0.00000000 0.37584546 0.33597839 ... 0.628601 0.000000\n## \n## $chr11\n## numeric-Rle of length 122082543 with 23536 runs\n## Lengths: 3165000 5000 5000 ... 5000 162543\n## Values : 0.0000000 -0.7906257 -0.7930040 ... 0.515919 0.000000\n##\n## ...\n\n\n\ntype = 'boundaries' will fetch a .bed file precomputed by the 4DN consortium, listing the annotated borders between topological domains. These borders correspond to local minima identified from the genome-wide insulation track. It can also be imported in R using the import function, which will generate a GRanges object.\n\n\nfourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'boundaries') |> \n import()\n## |===================================| 100%\n## GRanges object with 6103 ranges and 2 metadata columns:\n## seqnames ranges strand | name score\n## <Rle> <IRanges> <Rle> | <character> <numeric>\n## [1] chr1 4380001-4385000 * | Strong 0.695274\n## [2] chr1 4760001-4765000 * | Weak 0.444476\n## [3] chr1 4910001-4915000 * | Weak 0.353184\n## [4] chr1 5180001-5185000 * | Strong 0.565763\n## [5] chr1 6170001-6175000 * | Strong 1.644911\n## ... ... ... ... . ... ...\n## [6099] chrY 89725001-89730000 * | Weak 0.258094\n## [6100] chrY 89790001-89795000 * | Weak 0.442186\n## [6101] chrY 89895001-89900000 * | Weak 0.279879\n## [6102] chrY 90025001-90030000 * | Strong 0.660699\n## [6103] chrY 90410001-90415000 * | Strong 1.160018\n\n\n\ntype = 'compartments' will fetch a .bigwig track file precomputed by the 4DN consortium. This track corresponds to the selected genome-wide eigenvector computed by cooltools and representing A/B compartments. To know more about this, read the excerpt from 4DN data portal. Once fetched from the 4DN data portal, the local file can be imported in R using the import function, which will generate a RleList object. The score represents the eigenvector values, and by convention a genomic bin with a positive score is associated with the A compartment whereas a genomic bin with a negative score is associated with the B compartment.\n\n\nfourDNData(experimentSetAccession = '4DNES25ABNZ1', type = 'compartments') |> \n import()\n## |===================================| 100%\n## RleList of length 21\n## $chr1\n## numeric-Rle of length 195471971 with 771 runs\n## Lengths: 3000000 250000 250000 ... 250000 221971\n## Values : NaN -0.83457172 -0.98202854 ... 0.45792237 NaN\n## \n## $chr10\n## numeric-Rle of length 130694993 with 512 runs\n## Lengths: 3000000 250000 250000 ... 250000 194993\n## Values : NaN -0.99524581 -0.76405841 ... 0.0583894 NaN\n## \n## $chr11\n## numeric-Rle of length 122082543 with 478 runs\n## Lengths: 3000000 250000 250000 ... 250000 82543\n## Values : NaN -0.00653325 0.26659977 ... 0.25900587 NaN\n\n\n8.1.2 Querying a complete experiment dataset\nRather than importing multiple files corresponding to a single experimentSet accession ID one by one, one can import all the available files associated with a experimentSet accession ID into a HiCExperiment object by using the fourDNHiCExperiment() function.\n\nhic <- fourDNHiCExperiment('4DNESSS7VU57')\n## Fetching Hi-C contact map from 4DN portal\n## |===================================================================| 100%\n## \n## Compartments not found for the provided experimentSet accession.\n## Fetching insulation bigwig file from 4DN portal\n## |===================================================================| 100%\n## \n## Fetching borders bed file from 4DN portal\n## |===================================================================| 100%\n\nThis is a more efficient way to import datasets, as it aggregates the different bits together into a single HiCExperiment object with populated topologicalFeatures and metadata slots.\n\nhic\n## `HiCExperiment` object with 544,370,135 contacts over 286 regions\n## -------\n## fileName: \"/home/rsg/.cache/R/fourDNData/392eba3a587_4DNFIZ59STGB.mcool\"\n## focus: \"whole genome\"\n## resolutions(13): 1000 2000 ... 5000000 10000000\n## active resolution: 10000000\n## interactions: 40088\n## scores(2): count balanced\n## topologicalFeatures: compartments(0) borders(7887)\n## pairsFile: N/A\n## metadata(2): 4DN_info diamond_insulation\n\n\nmetadata(hic)\n## $`4DN_info`\n## experimentSetAccession fileType size organism experimentType details dataset condition biosource biosourceType publication URL\n## 4DNESSS7VU57 pairs 9731.58 mouse in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells female granulosa cells granulosa cell primary cell Lindeman RE et al. (2021) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/b7da6d89-9e24-48a7-b3a6-f30a49c843e3/4DNFI2PHVZ5S.pairs.gz\n## 4DNESSS7VU57 hic 4160.17 mouse in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells female granulosa cells granulosa cell primary cell Lindeman RE et al. (2021) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/327f091d-6a63-47c4-9752-2dff303a13d9/4DNFI6GFHB6G.hic\n## 4DNESSS7VU57 mcool 2863.90 mouse in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells female granulosa cells granulosa cell primary cell Lindeman RE et al. (2021) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/2fed1cf8-b334-4165-a32f-df3f9ae4d6d7/4DNFIZ59STGB.mcool\n## 4DNESSS7VU57 insulation 7.25 mouse in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells female granulosa cells granulosa cell primary cell Lindeman RE et al. (2021) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/88e1d2ad-4d59-4c6f-9793-4fd8afc74762/4DNFI65DQZJ7.bw\n## 4DNESSS7VU57 boundaries 0.12 mouse in situ Hi-C Arima - A1, A2 Hi-C on mouse somatic gonadal cells female granulosa cells granulosa cell primary cell Lindeman RE et al. (2021) https://4dn-open-data-public.s3.amazonaws.com/fourfront-webprod/wfoutput/2a29eec0-f551-4d50-8c0a-f4d4c2acd0db/4DNFIV519AWN.bed.gz\n## \n## $diamond_insulation\n## RleList of length 20\n## $chr1\n## numeric-Rle of length 195471971 with 37959 runs\n## Lengths: 3085000 5000 5000 ... 5000 186971\n## Values : 0.0000000 0.3967191 0.3961740 ... 0.8223819 0.0000000\n## \n## $chr10\n## numeric-Rle of length 130694993 with 24994 runs\n## Lengths: 3180000 5000 ... 5000 179993\n## Values : 0.00000e+00 5.35871e-01 ... 0.60626638 0.00000000\n## \n## ..." + }, + { + "objectID": "pages/disseminating.html#dna-zoo", + "href": "pages/disseminating.html#dna-zoo", + "title": "\n8Β  Data gateways: accessing public Hi-C data portals\n", + "section": "\n8.2 DNA Zoo", + "text": "8.2 DNA Zoo\nThe DNA Zoo Consortium is a collaborative group whose aim is to correct and refine genome assemblies across the tree of life using Hi-C approaches. As of 2023, they have performed Hi-C across more than 300 animal, plant and fungi species.\nDNAZooData is a package giving programmatic access to these uniformly processed Hi-C contact files, as well as the refined genome assemblies.\nThe DNAZooData() function provides a gateway to DNA Zoo-hosted Hi-C files, fetching and caching relevant contact matrices in .hic format It returns a HicFile object, which can then be imported in memory using import().\n\nlibrary(DNAZooData)\nhead(DNAZooData())\n## species readme readme_link original_assembly new_assembly new_assembly_link new_assembly_link_status hic_link\n## Acinonyx_jubatus Acinonyx_jubatus/README.json https://dnazoo.s3.wasabisys.com/Acinonyx_jubatus/README.json aciJub1 aciJub1_HiC https://dnazoo.s3.wasabisys.com/Acinonyx_jubatus/aciJub1_HiC.fasta.gz 200 https://dnazoo.s3.wasabisys.com/Acinonyx_jubatus/aciJub1.rawchrom.hic\n## Acropora_millepora Acropora_millepora/README.json https://dnazoo.s3.wasabisys.com/Acropora_millepora/README.json amil_sf_1.1 amil_sf_1.1_HiC https://dnazoo.s3.wasabisys.com/Acropora_millepora/amil_sf_1.1_HiC.fasta.gz 200 https://dnazoo.s3.wasabisys.com/Acropora_millepora/amil_sf_1.1_HiC.hic\n## Addax_nasomaculatus Addax_nasomaculatus/README.json https://dnazoo.s3.wasabisys.com/Addax_nasomaculatus/README.json ASM1959352v1 ASM1959352v1_HiC https://dnazoo.s3.wasabisys.com/Addax_nasomaculatus/ASM1959352v1_HiC.fasta.gz 200 https://dnazoo.s3.wasabisys.com/Addax_nasomaculatus/ASM1959352v1_HiC.hic\n## Aedes_aegypti Aedes_aegypti/README.json https://dnazoo.s3.wasabisys.com/Aedes_aegypti/README.json AGWG.draft AaegL5.0 https://dnazoo.s3.wasabisys.com/Aedes_aegypti/AaegL5.0.fasta.gz 404 <NA>\n## Aedes_aegypti__AaegL4 Aedes_aegypti__AaegL4/README.json https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL4/README.json AaegL3 AaegL4 https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL4/AaegL4.fasta.gz 200 https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL4/AaegL4.hic\n## Aedes_aegypti__AaegL5.0 Aedes_aegypti__AaegL5.0/README.json https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL5.0/README.json AGWG.draft AaegL5.0 https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL5.0/AaegL5.0.fasta.gz 200 https://dnazoo.s3.wasabisys.com/Aedes_aegypti__AaegL5.0/AaegL5.0.hic\n\nFor example, we can directly fetch a Hi-C dataset generated from a tardigrade sample by specifying the right species argument.\n\nhicfile <- DNAZooData(species = 'Hypsibius_dujardini')\n## Fetching Hi-C data from DNAZoo\n## |===================================| 100%\nhicfile\n## HicFile object\n## .hic file: /home/rsg/.cache/R/DNAZooData/400d7e2b0145_nHd_3.1_HiC.hic\n## resolution: 5000\n## pairs file:\n## metadata(6): organism draftAssembly ... credits assemblyURL\n\nHere again, the resulting HicFile is populated with metadata parsed from the DNA Zoo data portal.\n\nmetadata(hicfile)$organism\n## $vernacular\n## [1] \"Tardigrade\"\n## \n## $binomial\n## [1] \"Hypsibius dujardini\"\n## \n## $funFact\n## [1] \"<i>Hypsibius dujardini</i> is a species of tardigrade, a tiny microscopic organism. They are also commonly called water bears. This species is found world-wide!\"\n## \n## $extraInfo\n## [1] \"on BioKIDS website\"\n## \n## $extraInfoLink\n## [1] \"http://www.biokids.umich.edu/critters/Hypsibius_dujardini/\"\n## \n## $image\n## [1] \"https://static.wixstatic.com/media/2b9330_82db39c219f24b20a75cb38943aad1fb~mv2.jpg\"\n## \n## $imageCredit\n## [1] \"By Willow Gabriel, Goldstein Lab - https://www.flickr.com/photos/waterbears/1614095719/ Template:Uploader Transferred from en.wikipedia to Commons., CC BY-SA 2.5, https://commons.wikimedia.org/w/index.php?curi\n## d=2261992\"\n## \n## $isChromognomes\n## [1] \"FALSE\"\n## \n## $taxonomy\n## [1] \"Species:202423-914154-914155-914158-155166-155362-710171-710179-710192-155390-155420\"\n\nHiCFile metadata also points to a URL to directly fetch the genome assembly corrected by the DNA Zoo consortium.\n\nmetadata(hicfile)$assemblyURL\n## [1] \"https://dnazoo.s3.wasabisys.com/Hypsibius_dujardini/nHd_3.1_HiC.fasta.gz\"" + }, + { + "objectID": "pages/interoperability.html", + "href": "pages/interoperability.html", + "title": "\n9Β  Interoperability: using HiCExperiment with other R packages\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/interoperability.html#diffhic", + "href": "pages/interoperability.html#diffhic", + "title": "\n9Β  Interoperability: using HiCExperiment with other R packages\n", + "section": "\n9.1 diffHic", + "text": "9.1 diffHic\ndiffHic is the first R package dedicated to Hi-C processing and analysis (Lun & Smyth (2015)). It is packed with useful functions to generate a contact matrix from read pairs and to perform downstream investigation, including normalization, 2D β€œpeak” (i.e.Β loops) finding and aggregation, differential interaction between samples, etc. It works seamlessly with the InteractionSet class of object, which can be easily obtained from a HiCExperiment object.\nTo do so, we first need to extract GInteractions from one or several HiCExperiment objects and create a single InteractionSet object.\n\nlibrary(InteractionSet)\nlibrary(GenomicRanges)\nlibrary(HiCExperiment)\nlibrary(HiContactsData)\n\n# ---- This downloads an example `.mcool` file and caches it locally \ncoolf <- HiContactsData('yeast_wt', 'mcool')\n## see ?HiContactsData and browseVignettes('HiContactsData') for documentation\n## loading from cache\ncool <- import(coolf, format = 'cool')\ngi <- cool |> \n interactions() |> \n as(\"ReverseStrictGInteractions\")\niset <- InteractionSet(\n assays = list(\n counts = matrix(gi$count, ncol = 1), \n balanced = matrix(gi$balanced, ncol = 1)\n ), \n interactions = gi, \n colData = data.frame(lib = c(\"WT\"), totals = sum(gi$count))\n)\n\nFrom there, we can filter interactions to only retain those with significant enrichment over background.\n\nlibrary(diffHic)\nset.seed(1234)\n\n# --- Filter to find aggregated interactions\nenrichments <- enrichedPairs(iset)\nfilter <- filterPeaks(enrichments, min.enrich = log2(1.2), min.diag = 5)\nfiltered_iset <- iset[filter]\nfiltered_iset\n## class: InteractionSet \n## dim: 41872 1 \n## metadata(0):\n## assays(2): counts balanced\n## rownames: NULL\n## rowData names(4): bin_id1 bin_id2 count balanced\n## colnames: NULL\n## colData names(2): lib totals\n## type: ReverseStrictGInteractions\n## regions: 12079\n\n# --- Visualize filtered interactions \nlibrary(plyinteractions)\nlibrary(HiContacts)\n## Registered S3 methods overwritten by 'readr':\n## method from \n## as.data.frame.spec_tbl_df vroom\n## as_tibble.spec_tbl_df vroom\n## format.col_spec vroom\n## print.col_spec vroom\n## print.collector vroom\n## print.date_names vroom\n## print.locale vroom\n## str.col_spec vroom\ninteractions(filtered_iset) |> \n filter(seqnames2 == 'II', seqnames1 == seqnames2) |> \n plotMatrix(use.scores = 'count')\n\n\n\n\n\n\n\nNext, we can cluster filtered interactions that are next to each other.\n\n# --- Cluster interactions to find loops\nclustered_iset <- clusterPairs(filtered_iset, tol = 5000)\nclustered_iset$interactions \n## ReverseStrictGInteractions object with 1644 interactions and 0 metadata columns:\n## seqnames1 ranges1 strand1 seqnames2 ranges2 strand2\n## <Rle> <IRanges> <Rle> <Rle> <IRanges> <Rle>\n## [1] I 15001-149000 * --- I 1-122000 *\n## [2] I 133001-148000 * --- I 127001-139000 *\n## [3] I 154001-160000 * --- I 128001-149000 *\n## [4] I 168001-173000 * --- I 138001-148000 *\n## [5] I 184001-196000 * --- I 15001-23000 *\n## ... ... ... ... ... ... ... ...\n## [1640] XVI 897001-898000 * --- XVI 831001-832000 *\n## [1641] XVI 907001-910000 * --- XVI 840001-843000 *\n## [1642] XVI 926001-934000 * --- XVI 872001-878000 *\n## [1643] XVI 933001-934000 * --- XVI 858001-859000 *\n## [1644] XVI 933001-942000 * --- XVI 928001-934000 *\n## -------\n## regions: 2822 ranges and 0 metadata columns\n## seqinfo: 16 sequences from an unspecified genome\n\n# --- Visualize clustered interactions \ninteractions(filtered_iset) |> \n mutate(cluster = clustered_iset$indices[[1]]) |> \n filter(seqnames2 == 'II', seqnames1 == seqnames2) |> \n plotMatrix(use.scores = 'cluster')\n\n\n\n\n\n\n\nFinally, we can visualize identified individual interaction clusters identified with diffHic using HiContacts.\n\n# --- Plot matrix at a clustered loops\ncgi <- clustered_iset$interactions[554]\nseqn <- seqnames(anchors(cgi, type=\"second\"))\nstart <- start(anchors(cgi, type=\"second\")) - 50000\nend <- end(anchors(cgi, type=\"first\")) + 50000\ninteractions_peak <- GRanges(seqn, IRanges(start, end))\np <- plotMatrix(cool[interactions_peak])\n\nlibrary(ggplot2)\nan <- anchors(cgi)\np + geom_rect(\n data = data.frame(xmin = start(an[[2]]), xmax = end(an[[2]]), ymin = start(an[[1]]), ymax = end(an[[1]])), \n aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), \n inherit.aes = FALSE, \n fill = NA, \n colour = 'cyan'\n)" + }, + { + "objectID": "pages/interoperability.html#hicrep", + "href": "pages/interoperability.html#hicrep", + "title": "\n9Β  Interoperability: using HiCExperiment with other R packages\n", + "section": "\n9.2 HiCrep", + "text": "9.2 HiCrep\nhicrep is a popular package to compute stratum-adjusted correlations between Hi-C datasets (Yang et al. (2017)). β€œStratum” refers to the distance from the main diagonal: with increase distance from the main diagonal, interactions of the DNA polymer are bound to decrease. hicrep computes a β€œper-stratum” correlation score and computes a weighted average correlation for entire chromosomes.\n\n\n\n\n\n\nInstalling hicrep\n\n\n\nhicrep package has been available from Bioconductor for many years but has been withdrawn from their repositories at some point. You can always install hicrep directly from its GitHub repository as follows:\n\nremotes::install_github('TaoYang-dev/hicrep')\n\n\n\nIn order to use hicrep, we first need to create two HiCExperiment objects.\n\n# ---- This downloads example `.mcool` files and caches them locally \ncoolf_eco1 <- HiContactsData('yeast_eco1', 'mcool')\n\n\nhic_wt <- import(coolf_wt, format = 'cool')\nhic_eco1 <- import(coolf_eco1, format = 'cool')\n\nWe can now run the main get.scc function from hicrep. The documentation for this function is available from the console by typing ?hicrep::get.scc. More information is also available from the GitHub page. It informs the end user that the input for this function should be two intra-chromosomal Hi-C raw count matrices in square (optionally sparse) format.\n\nhic_wt\n## `HiCExperiment` object with 8,757,906 contacts over 12,079 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"whole genome\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 1000 \n## interactions: 2945692 \n## scores(2): count balanced \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) \n## pairsFile: N/A \n## metadata(0):\n\nas.matrix(hic_wt[\"IV\"], use.scores = 'count')[1:10, 1:10]\n## 10 x 10 sparse Matrix of class \"dgTMatrix\"\n## \n## [1,] . 1 . . 1 . . . . .\n## [2,] 1 . . . . . . . . .\n## [3,] . . . . . . . . . .\n## [4,] . . . . . . . . . .\n## [5,] 1 . . . . . . . 1 .\n## [6,] . . . . . . . . . .\n## [7,] . . . . . . . . . .\n## [8,] . . . . . . . . 1 .\n## [9,] . . . . 1 . . 1 . .\n## [10,] . . . . . . . . . .\n\nlibrary(hicrep)\nscc <- get.scc(\n as.matrix(hic_wt[\"IV\"], use.scores = 'count'), \n as.matrix(hic_eco1[\"IV\"], use.scores = 'count'), \n resol = 1000, h = 25, lbr = 5000, ubr = 50000\n)\nscc\n## $corr\n## [1] 0.9412784 0.9410680 0.9408082 0.9404796 0.9404544 0.9402584 0.9400710\n## [8] 0.9398965 0.9397935 0.9397027 0.9396112 0.9393001 0.9393180 0.9390608\n## [15] 0.9391645 0.9394670 0.9395147 0.9396798 0.9397547 0.9398291 0.9401371\n## [22] 0.9402369 0.9402251 0.9404188 0.9404327 0.9403101 0.9402634 0.9401683\n## [29] 0.9401746 0.9394978 0.9391277 0.9381969 0.9371561 0.9357012 0.9342620\n## [36] 0.9324366 0.9302835 0.9277556 0.9247008 0.9208466 0.9166648 0.9120206\n## [43] 0.9060828 0.9002430 0.8931754 0.8847777\n## \n## $wei\n## [1] 123.2500 123.1667 123.0833 123.0000 122.9167 122.8333 122.7500 122.6667\n## [9] 122.5833 122.5000 122.4167 122.3333 122.2500 122.1667 122.0833 122.0000\n## [17] 121.9167 121.8333 121.7500 121.6667 121.5833 121.5000 121.4167 121.3333\n## [25] 121.2500 121.1667 121.0833 121.0000 120.9167 120.8333 120.7500 120.6667\n## [33] 120.5833 120.5000 120.4167 120.3333 120.2500 120.1667 120.0833 120.0000\n## [41] 119.9167 119.8333 119.7500 119.6667 119.5833 119.5000\n## \n## $scc\n## [,1]\n## [1,] 0.9334303\n## \n## $std\n## [1] 0.001994845\n\nscc$scc\n## [,1]\n## [1,] 0.9334303" + }, + { + "objectID": "pages/interoperability.html#multihiccompare", + "href": "pages/interoperability.html#multihiccompare", + "title": "\n9Β  Interoperability: using HiCExperiment with other R packages\n", + "section": "\n9.3 multiHiCcompare", + "text": "9.3 multiHiCcompare\nThe multiHiCcompare package provides functions for joint normalization and difference detection in multiple Hi-C datasets (Stansfield et al. (2019)). According to its excerpt, to perform differential interaction analysis, it requires a list of raw counts for different samples/replicates, stored in data frames with four columns (chr, start1, start2, count).\nManipulate a HiCExperiment object to coerce it into such structure is straightforward.\n\nlibrary(dplyr)\nlibrary(tidyr)\nlibrary(purrr)\nhics <- list(\n \"wt\" = import(coolf_wt, format = 'cool'),\n \"eco1\" = import(coolf_eco1, format = 'cool')\n)\nhics_list <- map(hics, ~ .x['XI'] |> \n as.data.frame() |>\n mutate(chr = 1) |> \n relocate(chr) |>\n select(chr, start1, start2, count)\n)\nhead(hics_list[[1]])\n## chr start1 start2 count\n## 1 1 1 1 2\n## 2 1 1 1001 3\n## 3 1 1 2001 3\n## 4 1 1 3001 13\n## 5 1 1 4001 9\n## 6 1 1 5001 13\n\nOnce this list is generated, the classical multiHiCcompare workflow can be applied: first run make_hicexp(), followed by cyclic_loess(), then hic_exactTest() and finally results():\n\nDI <- hics_list |> \n make_hicexp(\n data_list = hics_list, \n groups = factor(c(1, 2))\n ) |> \n cyclic_loess() |> \n hic_exactTest() |> \n results()\nDI\n## chr region1 region2 D logFC logCPM p.value p.adj\n## 1: 1 1 1001 1 0.4279414 6.382927 0.78960192 1.0000000\n## 2: 1 1 3001 3 1.0325237 8.339327 0.06035705 0.9501367\n## 3: 1 1 4001 4 0.6862141 7.597689 0.34723639 1.0000000\n## 4: 1 1 5001 5 0.5124878 7.960339 0.43133791 1.0000000\n## 5: 1 1 6001 6 -0.3568672 8.563374 0.52289982 1.0000000\n## --- \n## 22637: 1 663001 666001 3 -1.1680738 7.158551 0.17500113 1.0000000\n## 22638: 1 664001 664001 0 1.4530501 8.536212 0.16535151 1.0000000\n## 22639: 1 664001 665001 1 -0.1014769 8.166275 1.00000000 1.0000000\n## 22640: 1 665001 665001 0 -0.3110054 10.013750 0.60075706 1.0000000\n## 22641: 1 665001 666001 1 -0.4989794 7.750157 0.41481212 1.0000000" + }, + { + "objectID": "pages/interoperability.html#topdom", + "href": "pages/interoperability.html#topdom", + "title": "\n9Β  Interoperability: using HiCExperiment with other R packages\n", + "section": "\n9.4 TopDom", + "text": "9.4 TopDom\nThe TopDom method is widely used to annotate topological domains in genomes from Hi-C data (Shin et al. (2015)). The TopDom package was created to implement this method in R (Bengtsson et al. (2020)).\nUnfortunately, the format of the input to TopDom is rather tricky (see ?TopDom::readHiC). The following chunk of code shows how to coerce a HiCExperiment object into a TopDom-compatible object.\n\nlibrary(TopDom)\nhic <- import(coolf_wt, format = 'cool')\nHiCExperiment2TopDom <- function(hic, chr) {\n data <- list()\n cm <- as(hic[chr], 'ContactMatrix')\n data$counts <- as.matrix(cm) |> base::as.matrix()\n data$counts[is.na(data$counts)] <- 0\n data$bins <- regions(cm) |> \n as.data.frame() |> \n select(seqnames, start, end) |>\n mutate(seqnames = as.character(seqnames)) |>\n mutate(id = 1:n(), start = start - 1) |> \n relocate(id) |> \n dplyr::rename(chr = seqnames, from.coord = start, to.coord = end)\n class(data) <- 'TopDomData'\n return(data)\n}\nhic_topdom <- HiCExperiment2TopDom(hic, \"II\")\nhic_topdom\n## TopDomData:\n## bins:\n## 'data.frame': 813 obs. of 4 variables:\n## $ id : int 1 2 3 4 5 6 7 8 9 10 ...\n## $ chr : chr \"II\" \"II\" \"II\" \"II\" ...\n## $ from.coord: num 0 1000 2000 3000 4000 5000 6000 7000 8000 9000 ...\n## $ to.coord : int 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 ...\n## counts:\n## num [1:813, 1:813] 0 0 0 0 0 0 0 0 0 0 ...\n\nNow that we have coerced a HiCExperiment object into a TopDom-compatible object, we can use the main TopDom function to annotate topological domains.\n\ndomains <- TopDom::TopDom(hic_topdom, window.size = 5)\ndomains\n## TopDom:\n## Parameters:\n## - window.size: 5\n## - statFilter: TRUE\n## binSignal:\n## 'data.frame': 813 obs. of 7 variables:\n## $ id : int 1 2 3 4 5 6 7 8 9 10 ...\n## $ chr : chr \"II\" \"II\" \"II\" \"II\" ...\n## $ from.coord: num 0 1000 2000 3000 4000 5000 6000 7000 8000 9000 ...\n## $ to.coord : int 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 ...\n## $ local.ext : num -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 0 0 ...\n## $ mean.cf : num 0 0 0 0 0 ...\n## $ pvalue : num 1 1 1 1 1 ...\n## domain:\n## 'data.frame': 61 obs. of 7 variables:\n## $ chr : chr \"II\" \"II\" \"II\" \"II\" ...\n## $ from.id : int 1 9 31 36 47 61 76 82 91 102 ...\n## $ from.coord: num 0 8000 30000 35000 46000 60000 75000 81000 90000 101000 ...\n## $ to.id : int 8 30 35 46 60 75 81 90 101 136 ...\n## $ to.coord : num 8000 30000 35000 46000 60000 75000 81000 90000 101000 136000 ...\n## $ tag : chr \"gap\" \"domain\" \"gap\" \"domain\" ...\n## $ size : num 8000 22000 5000 11000 14000 15000 6000 9000 11000 35000 ...\n## bed:\n## 'data.frame': 61 obs. of 4 variables:\n## $ chrom : chr \"II\" \"II\" \"II\" \"II\" ...\n## $ chromStart: num 0 8000 30000 35000 46000 60000 75000 81000 90000 101000 ...\n## $ chromEnd : num 8000 30000 35000 46000 60000 75000 81000 90000 101000 136000 ...\n## $ name : chr \"gap\" \"domain\" \"gap\" \"domain\" ...\n\nThe resulting domains object can be used to extract annotated domains, store them in topologicalFeatures of the original HiCExperiment, and optionally write a bed file to export them in text.\n\ntopologicalFeatures(hic, 'domain') <- domains$bed |> \n mutate(chromStart = chromStart + 1) |> \n filter(name == 'domain') |> \n makeGRangesFromDataFrame()\ntopologicalFeatures(hic, 'domain')\n## GRanges object with 52 ranges and 0 metadata columns:\n## seqnames ranges strand\n## <Rle> <IRanges> <Rle>\n## [1] II 8001-30000 *\n## [2] II 35001-46000 *\n## [3] II 46001-60000 *\n## [4] II 60001-75000 *\n## [5] II 75001-81000 *\n## ... ... ... ...\n## [48] II 664001-681000 *\n## [49] II 681001-707000 *\n## [50] II 707001-714000 *\n## [51] II 714001-761000 *\n## [52] II 761001-806000 *\n## -------\n## seqinfo: 1 sequence from an unspecified genome; no seqlengths\n\nrtracklayer::export(topologicalFeatures(hic, 'domain'), 'hic_domains.bed')" + }, + { + "objectID": "pages/interoperability.html#gothic", + "href": "pages/interoperability.html#gothic", + "title": "\n9Β  Interoperability: using HiCExperiment with other R packages\n", + "section": "\n9.5 GOTHiC", + "text": "9.5 GOTHiC\nGOTHiC relies on a cumulative binomial test to detect interactions between distal genomic loci that have significantly more reads than expected by chance in Hi-C experiments (Mifsud et al. (2017)).\n\n\n\n\n\n\nUsing the GOTHiC function\n\n\n\nUnfortunately, the main GOTHiC function require two .bam files as input. These files are often deleted due to their larger size, while the filtered pairs file itself is retained.\nMoreover, the internal nuts and bolts of the main GOTHiC function perform several operations that are not required in modern workflows:\n\n\nFiltering pairs from same restriction fragment; this step is now usually taken care of automatically, e.g.Β with HiCool Hi-C processing package.\n\nFiltering short-range pairs; the GOTHiC package hard-codes a 10kb lower threshold for minimum pair distance. More advanced optimized filtering approaches have been implemented since then, to circumvent the need for such hard-coded threshold.\n\nBinning pairs; this step is also already taken care of, when working with Hi-C matrices in modern formats, e.g.Β with .(m)cool files.\n\n\n\nBased on these facts, we can simplify the binomial test function provided by GOTHiC so that it can directly used binned interactions imported as a HiCExperiment object in R.\n\nShow the code for GOTHiC_binomial functionGOTHiC_binomial <- function(x) {\n\n if (length(trans(x)) != 0) stop(\"Only `cis` interactions can be used here.\")\n ints <- interactions(x) |>\n as.data.frame() |> \n select(seqnames1, start1, seqnames2, start2, count) |>\n dplyr::rename(chr1 = seqnames1, locus1 = start1, chr2 = seqnames2, locus2 = start2, frequencies = count) |>\n mutate(locus1 = locus1 - 1, locus2 = locus2 - 1) |>\n mutate(int1 = paste0(chr1, '_', locus1), int2 = paste0(chr2, '_', locus2))\n \n numberOfReadPairs <- sum(ints$frequencies)\n all_bins <- unique(c(unique(ints$int1), unique(ints$int2)))\n all_bins <- sort(all_bins)\n upperhalfBinNumber <- (length(all_bins)^2 - length(all_bins))/2\n\n cov <- ints |> \n group_by(int1) |> \n tally(frequencies) |> \n full_join(ints |> \n group_by(int2) |> \n tally(frequencies), \n by = c('int1' = 'int2')\n ) |> \n rowwise() |> \n mutate(coverage = sum(n.x, n.y, na.rm = TRUE)) |> \n ungroup() |>\n mutate(relative_coverage = coverage/sum(coverage))\n \n results <- mutate(ints,\n cov1 = left_join(ints, select(cov, int1, relative_coverage), by = c('int1' = 'int1'))$relative_coverage, \n cov2 = left_join(ints, select(cov, int1, relative_coverage), by = c('int2' = 'int1'))$relative_coverage,\n probability = cov1 * cov2 * 2 * 1/(1 - sum(cov$relative_coverage^2)),\n predicted = probability * numberOfReadPairs\n ) |> \n rowwise() |>\n mutate(\n pvalue = binom.test(\n frequencies, \n numberOfReadPairs, \n probability,\n alternative = \"greater\"\n )$p.value\n ) |> \n ungroup() |> \n mutate(\n logFoldChange = log2(frequencies / predicted), \n qvalue = stats::p.adjust(pvalue, method = \"BH\", n = upperhalfBinNumber)\n )\n\n scores(x, \"probability\") <- results$probability\n scores(x, \"predicted\") <- results$predicted\n scores(x, \"pvalue\") <- results$pvalue\n scores(x, \"qvalue\") <- results$qvalue\n scores(x, \"logFoldChange\") <- results$logFoldChange\n\n return(x)\n\n} \n\n\n\nres <- GOTHiC_binomial(hic[\"II\"])\nres\n## `HiCExperiment` object with 471,364 contacts over 802 regions \n## -------\n## fileName: \"/root/.cache/R/ExperimentHub/1701a09a86_7752\" \n## focus: \"II\" \n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 1000 \n## interactions: 74360 \n## scores(7): count balanced probability predicted pvalue qvalue logFoldChange \n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0) domain(52) \n## pairsFile: N/A \n## metadata(0):\n\ninteractions(res)\n## GInteractions object with 74360 interactions and 9 metadata columns:\n## seqnames1 ranges1 strand1 seqnames2 ranges2\n## <Rle> <IRanges> <Rle> <Rle> <IRanges>\n## [1] II 1-1000 * --- II 1001-2000\n## [2] II 1-1000 * --- II 5001-6000\n## [3] II 1-1000 * --- II 6001-7000\n## [4] II 1-1000 * --- II 8001-9000\n## [5] II 1-1000 * --- II 9001-10000\n## ... ... ... ... ... ... ...\n## [74356] II 807001-808000 * --- II 809001-810000\n## [74357] II 807001-808000 * --- II 810001-811000\n## [74358] II 808001-809000 * --- II 808001-809000\n## [74359] II 808001-809000 * --- II 809001-810000\n## [74360] II 809001-810000 * --- II 809001-810000\n## strand2 | bin_id1 bin_id2 count balanced probability\n## <Rle> | <numeric> <numeric> <numeric> <numeric> <numeric>\n## [1] * | 231 232 1 NaN 7.83580e-09\n## [2] * | 231 236 2 NaN 2.81318e-08\n## [3] * | 231 237 1 NaN 2.02960e-08\n## [4] * | 231 239 2 NaN 6.73108e-08\n## [5] * | 231 240 3 NaN 7.37336e-08\n## ... ... . ... ... ... ... ...\n## [74356] * | 1038 1040 8 0.0472023 3.85638e-07\n## [74357] * | 1038 1041 1 NaN 5.03006e-08\n## [74358] * | 1039 1039 1 NaN 8.74604e-08\n## [74359] * | 1039 1040 7 NaN 1.02111e-07\n## [74360] * | 1040 1040 2 0.0411355 1.19216e-07\n## predicted pvalue qvalue logFoldChange\n## <numeric> <numeric> <numeric> <numeric>\n## [1] 0.00369352 3.68670e-03 0.063385760 8.08079\n## [2] 0.01326033 8.71446e-05 0.001926954 7.23674\n## [3] 0.00956681 9.52120e-03 0.150288341 6.70775\n## [4] 0.03172791 4.92808e-04 0.009806734 5.97810\n## [5] 0.03475538 6.81713e-06 0.000173165 6.43158\n## ... ... ... ... ...\n## [74356] 0.1817758 2.51560e-11 1.07966e-09 5.45977\n## [74357] 0.0237099 2.34310e-02 3.38098e-01 5.39837\n## [74358] 0.0412257 4.03875e-02 5.49519e-01 4.60031\n## [74359] 0.0481315 1.13834e-13 5.77259e-12 7.18423\n## [74360] 0.0561941 1.52097e-03 2.79707e-02 5.15344\n## -------\n## regions: 802 ranges and 4 metadata columns\n## seqinfo: 16 sequences from an unspecified genome" + }, + { + "objectID": "pages/workflow-yeast.html", + "href": "pages/workflow-yeast.html", + "title": "\n10Β  Workflow 1: Distance-dependent interactions across yeast mutants\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/workflow-yeast.html#recovering-data-from-sra", + "href": "pages/workflow-yeast.html#recovering-data-from-sra", + "title": "\n10Β  Workflow 1: Distance-dependent interactions across yeast mutants\n", + "section": "\n10.1 Recovering data from SRA", + "text": "10.1 Recovering data from SRA\nThe easiest for this is to directly fetch files from SRA from their FTP server. We can do so using the base download.file function.\n\n\n\n\n\n\nNote\n\n\n\nThe next two code chunks illustrate how to do download and process Hi-C reads from SRA, but they are not actually executed when rendering this website as it would take a significant amount of time.\n\n\n\n# !! This code is not actually executed !!\ndir.create('data')\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/004/SRR8769554/SRR8769554_1.fastq.gz\", \"data/WT_G1_WT_rep1_R1.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/004/SRR8769554/SRR8769554_2.fastq.gz\", \"data/WT_G1_WT_rep1_R2.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/076/SRR10687276/SRR10687276_1.fastq.gz\", \"data/WT_G1_WT_rep2_R1.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/076/SRR10687276/SRR10687276_2.fastq.gz\", \"data/WT_G1_WT_rep2_R2.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/009/SRR8769549/SRR8769549_1.fastq.gz\", \"data/WT_G2M_WT_rep1_R1.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/009/SRR8769549/SRR8769549_2.fastq.gz\", \"data/WT_G2M_WT_rep1_R2.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/081/SRR10687281/SRR10687281_1.fastq.gz\", \"data/WT_G2M_WT_rep2_R1.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/081/SRR10687281/SRR10687281_2.fastq.gz\", \"data/WT_G2M_WT_rep2_R2.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/001/SRR8769551/SRR8769551_1.fastq.gz\", \"data/wpl1_G2M_rep1_R1.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/001/SRR8769551/SRR8769551_2.fastq.gz\", \"data/wpl1_G2M_rep1_R2.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/078/SRR10687278/SRR10687278_1.fastq.gz\", \"data/wpl1_G2M_rep2_R1.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR106/078/SRR10687278/SRR10687278_2.fastq.gz\", \"data/wpl1_G2M_rep2_R2.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/005/SRR8769555/SRR8769555_1.fastq.gz\", \"data/wpl1eco1_G2M_R1.fastq.gz\")\ndownload.file(\"ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR876/005/SRR8769555/SRR8769555_2.fastq.gz\", \"data/wpl1eco1_G2M_R2.fastq.gz\")" + }, + { + "objectID": "pages/workflow-yeast.html#processing-reads-with-hicool", + "href": "pages/workflow-yeast.html#processing-reads-with-hicool", + "title": "\n10Β  Workflow 1: Distance-dependent interactions across yeast mutants\n", + "section": "\n10.2 Processing reads with HiCool", + "text": "10.2 Processing reads with HiCool\nWe will map each pair of fastqs on the yeast genome reference (R64-1-1) using HiCool.\n\n# !! This code is not actually executed !!\nlibrary(HiCool)\nsamples <- c(\n 'WT_G1_rep1', \n 'WT_G1_rep2', \n 'WT_G2M_rep1', \n 'WT_G2M_rep2', \n 'wpl1_G2M_rep1', \n 'wpl1_G2M_rep2', \n 'wpl1eco1_G2M' \n)\npurrr::map(samples, ~ HiCool(\n r1 = paste0('data/', .x, '_R1.fastq.gz'), \n r2 = paste0('data/', .x, '_R2.fastq.gz'), \n genome = 'R64-1-1', \n restriction = 'DpnII', \n iterative = FALSE, \n threads = 15, \n output = 'data/HiCool/', \n scratch = '/data/scratch/'\n))\n\nProcessed samples are put in data/HiCool directory. CoolFile objects are pointers to individual contact matrices. We can create such objects by using the importHiCoolFolder utility function.\n\ncfs <- list(\n WT_G1_rep1 = importHiCoolFolder('data/HiCool', 'GK8ISZ'), \n WT_G1_rep2 = importHiCoolFolder('data/HiCool', 'SWZTO0'), \n WT_G2M_rep1 = importHiCoolFolder('data/HiCool', '3KHHUE'), \n WT_G2M_rep2 = importHiCoolFolder('data/HiCool', 'UVNG7M'), \n wpl1_G2M_rep1 = importHiCoolFolder('data/HiCool', 'Q4KX6Z'), \n wpl1_G2M_rep2 = importHiCoolFolder('data/HiCool', '3N0L25'), \n wpl1eco1_G2M = importHiCoolFolder('data/HiCool', 'LHMXWE')\n)\ncfs\n\nNow that these pointers have been defined, Hi-C contact matrices can be seamlessly imported in R with import.\n\nlibrary(purrr)\nlibrary(HiCExperiment)\nhics <- map(cfs, import)\nhics\n## $WT_G1_rep1\n## `HiCExperiment` object with 5,454,145 contacts over 12,079 regions\n## -------\n## fileName: \"../OHCA-data/HiCool/matrices/W303_G1_WT_rep1^mapped-S288c^GK8ISZ.mcool\"\n## focus: \"whole genome\"\n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 1000\n## interactions: 3347524\n## scores(2): count balanced\n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0)\n## pairsFile: ../OHCA-data/HiCool/pairs/W303_G1_WT_rep1^mapped-S288c^GK8ISZ.pairs\n## metadata(3): log args stats\n## \n## $WT_G1_rep2\n## `HiCExperiment` object with 12,068,214 contacts over 12,079 regions\n## -------\n## fileName: \"../OHCA-data/HiCool/matrices/W303_G1_WT_rep2^mapped-S288c^SWZTO0.mcool\"\n## focus: \"whole genome\"\n## resolutions(5): 1000 2000 4000 8000 16000\n## active resolution: 1000\n## interactions: 6756099\n## scores(2): count balanced\n## topologicalFeatures: compartments(0) borders(0) loops(0) viewpoints(0)\n## pairsFile: ../OHCA-data/HiCool/pairs/W303_G1_WT_rep2^mapped-S288c^SWZTO0.pairs\n## metadata(3): log args stats\n## \n## ..." + }, + { + "objectID": "pages/workflow-yeast.html#plotting-chromosome-wide-matrices-of-merged-replicates", + "href": "pages/workflow-yeast.html#plotting-chromosome-wide-matrices-of-merged-replicates", + "title": "\n10Β  Workflow 1: Distance-dependent interactions across yeast mutants\n", + "section": "\n10.3 Plotting chromosome-wide matrices of merged replicates", + "text": "10.3 Plotting chromosome-wide matrices of merged replicates\nWe can merge replicates with the merge function, and map the plotMatrix function over the resulting list of HiCExperiments.\n\nlibrary(HiContacts)\nchr <- 'X'\nmerged_replicates <- list(\n WT_G1 = merge(hics[[1]][chr], hics[[2]][chr]), \n WT_G2M = merge(hics[[3]][chr], hics[[4]][chr]), \n wpl1_G2M = merge(hics[[5]][chr], hics[[6]][chr]), \n wpl1eco1_G2M = hics[[7]][chr]\n)\nlibrary(dplyr)\nlibrary(ggplot2)\nmaps <- imap(merged_replicates, ~ plotMatrix(\n .x, use.scores = 'balanced', limits = c(-3.5, -1.5), caption = FALSE\n) + ggtitle(.y))\ncowplot::plot_grid(plotlist = maps, nrow = 1)\n\n\nWe can already note that long-range contacts seem to increase in frequency, in G2/M vs G1, in wpl1 vs WT and in wpl1/eco1 vs wpl1." + }, + { + "objectID": "pages/workflow-yeast.html#compute-ps-per-replicate-and-plot-it", + "href": "pages/workflow-yeast.html#compute-ps-per-replicate-and-plot-it", + "title": "\n10Β  Workflow 1: Distance-dependent interactions across yeast mutants\n", + "section": "\n10.4 Compute P(s) per replicate and plot it", + "text": "10.4 Compute P(s) per replicate and plot it\nStill using the map function, we can compute average P(s) for each replicate.\nComputation of the P(s) will take some time, as millions of pairs have to be imported in memory, but it will be accurate at the base resolution, rather than bin resolution from matrices.\n\n\n\n\n\n\nNote\n\n\n\nSince matrices were imported after HiCool processing with the importHiCoolFolder, the associated .pairs file has been automatically added to each HiCExperiment object!\n\n\nThe computed P(s) is stored for each sample as a tibble.\n\npairsFile(hics[[1]])\nps <- imap(hics, ~ distanceLaw(.x) |> mutate(sample = .y))\n## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G1_WT_rep1^mapped-S288c^GK8ISZ.pairs in memory. This may take a while...\n## |===============================================================| 100% 318 MB\n## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G1_WT_rep2^mapped-S288c^SWZTO0.pairs in memory. This may take a while...\n## |===============================================================| 100% 674 MB\n## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_WT_rep1^mapped-S288c^3KHHUE.pairs in memory. This may take a while...\n## |===============================================================| 100% 709 MB\n## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_WT_rep2^mapped-S288c^UVNG7M.pairs in memory. This may take a while...\n## |==============================================================| 100% 1683 MB\n## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_wpl1_rep1^mapped-S288c^Q4KX6Z.pairs in memory. This may take a while...\n## |==============================================================| 100% 1269 MB\n## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_wpl1_rep2^mapped-S288c^3N0L25.pairs in memory. This may take a while...\n## |==============================================================| 100% 1529 MB\n## Importing pairs file ../OHCA-data/HiCool/pairs/W303_G2M_wpl1-eco1^mapped-S288c^LHMXWE.pairs in memory. This may take a while...\n## |==============================================================| 100% 1036 MB\nps[[1]]\n## # A tibble: 133 x 6\n## binned_distance p norm_p norm_p_unity slope sample\n## <dbl> <dbl> <dbl> <dbl> <dbl> <chr>\n## 1 1 0.000154 0.000154 249. 0 WT_G1_rep1\n## 2 2 0.0000563 0.0000563 91.2 0.702 WT_G1_rep1\n## 3 3 0.0000417 0.0000417 67.5 0.699 WT_G1_rep1\n## 4 4 0.00000835 0.00000835 13.5 0.696 WT_G1_rep1\n## 5 5 0.00000501 0.00000501 8.10 0.693 WT_G1_rep1\n## 6 6 0.00000250 0.00000250 4.05 0.690 WT_G1_rep1\n## # ... with 127 more rows\n\nWe can bind all tibbles together and plot P(s) and their slope for each sample.\n\ndf <- list_rbind(ps)\nplotPs(\n df, aes(x = binned_distance, y = norm_p, \n group = sample, color = sample)\n)\nplotPsSlope(\n df, aes(x = binned_distance, y = slope, \n group = sample, color = sample)\n)" + }, + { + "objectID": "pages/workflow-yeast.html#correlation-between-replicates-with-hicrep", + "href": "pages/workflow-yeast.html#correlation-between-replicates-with-hicrep", + "title": "\n10Β  Workflow 1: Distance-dependent interactions across yeast mutants\n", + "section": "\n10.5 Correlation between replicates with hicrep\n", + "text": "10.5 Correlation between replicates with hicrep\n\nhicrep is a popular package to compute stratum-adjusted correlations between Hi-C datasets. β€œStratum” refers to the distance from the main diagonal: with increase distance from the main diagonal, interactions of the DNA polymer are bound to decrease. hicrep computes a β€œper-stratum” correlation score and computes a weighted average correlation for entire chromosomes.\nWe can check the documentation for hicrep main function, get.scc. This tells us that mat1 and mat2 n*n intrachromosomal contact maps of raw counts should be provided. Fortunately, HiCExperiment objects can easily be coerced into actual dense matrices using as.matrix() function.\n\n\n\n\n\n\nImportant\n\n\n\nMake sure to use the count scores, which are required by hicrep.\n\n\nWe can calculate the overall stratum-corrected correlation score over the chromosome IV between the two G2M WT replicates.\n\nlibrary(hicrep)\nscc <- get.scc(\n hics[['WT_G2M_rep1']][\"IV\"] |> as.matrix(use.scores = 'count'), \n hics[['WT_G2M_rep2']][\"IV\"] |> as.matrix(use.scores = 'count'), \n resol = 1000, h = 2, lbr = 5000, ubr = 50000\n)\nnames(scc)\n## [1] \"corr\" \"wei\" \"scc\" \"std\"\nscc$scc\n## [,1]\n## [1,] 0.9785691\n\nThis can be generalized to all pairwise combinations of Hi-C datasets.\n\nlibrary(purrr)\nlibrary(dplyr)\nlibrary(ggplot2)\nmats <- map(hics, ~ .x[\"IV\"] |> as.matrix(use.scores = 'count'))\ndf <- map(1:7, function(i) {\n map(1:7, function(j) {\n data.frame(\n i = names(hics)[i], \n j = names(hics)[j], \n scc = hicrep::get.scc(mats[[i]], mats[[j]], resol = 1000, h = 2, lbr = 5000, ubr = 200000)$scc\n ) |>\n mutate(i = factor(i, names(cfs))) |>\n mutate(j = factor(j, names(cfs)))\n }) |> list_rbind()\n}) |> list_rbind()\nggplot(df, aes(x = i, y = j, fill = scc)) + \n geom_tile() + \n scale_x_discrete(guide = guide_axis(angle = 90)) + \n theme_bw() + \n coord_fixed(ratio = 1) + \n scale_fill_gradientn(colours = bgrColors())\n\n\nWe can even iterate over an extra level, to compute stratum-corrected correlation for all chromosomes. Here, we will only compute correlation scores between any sample and WT_G2M_rep1 sample.\n\n\n\n\n\n\nParallelizing over chromosomes\n\n\n\nBiocParallel::bplapply() replaces purrr::map() here, as it allows parallelization of independent correlation computation runs over multiple CPUs.\n\n\n\n# Some chromosomes will be ignored as they are too small for this analysis \nchrs <- c('II', 'IV', 'V', 'VII', 'VIII', 'IX', 'X', 'XI', 'XIII', 'XIV', 'XVI')\nbpparam <- BiocParallel::MulticoreParam(workers = 6, progressbar = TRUE)\ndf <- BiocParallel::bplapply(chrs, function(CHR) {\n mats <- map(hics, ~ .x[CHR] |> interactions() |> gi2cm('count') |> cm2matrix())\n\n map(c(1, 2, 4, 5, 6, 7), function(j) {\n data.frame(\n chr = CHR,\n i = \"WT_G2M_rep1\", \n j = names(mats)[j], \n dist = seq(5000, 200000, 1000),\n scc = hicrep::get.scc(mats[[\"WT_G2M_rep1\"]], mats[[j]], resol = 1000, h = 2, lbr = 5000, ubr = 200000) \n ) |> mutate(j = factor(j, names(mats)))\n }) |> list_rbind()\n\n}, BPPARAM = bpparam) |> list_rbind()\n\nA tiny bit of data wrangling will allow us to plot the mean +/- confidence interval (90%) of stratum-adjusted correlations across the different chromosomes.\n\nresults <- group_by(df, j, dist) |> \n summarize(\n mean = Rmisc::CI(scc.corr, ci = 0.90)[2], \n CI_up = Rmisc::CI(scc.corr, ci = 0.90)[1], \n CI_down = Rmisc::CI(scc.corr, ci = 0.90)[3]\n )\nggplot(results, aes(x = dist, y = mean, ymax = CI_up, ymin = CI_down)) + \n geom_line(aes(col = j)) + \n geom_ribbon(aes(fill = j), alpha = 0.2, col = NA) + \n theme_bw() + \n labs(x = \"Stratum (genomic distance)\", y = 'Stratum-corrected correlation')" + }, + { + "objectID": "pages/workflow-yeast.html#differential-interaction-di-analysis-with-multihiccompare", + "href": "pages/workflow-yeast.html#differential-interaction-di-analysis-with-multihiccompare", + "title": "\n10Β  Workflow 1: Distance-dependent interactions across yeast mutants\n", + "section": "\n10.6 Differential interaction (DI) analysis with multiHiCcompare\n", + "text": "10.6 Differential interaction (DI) analysis with multiHiCcompare\n\nWe will now focus on the chromosome XI and identify differentially interacting (DI) loci between WT and wpl1 mutant in G2/M.\nTo do this, we can use the multiHiCcompare package. The required input for the main make_hicexp() function is a list of raw counts for different samples/replicates, stored in data frames with four columns (chr, start1, start2, count).\nAlthough this data structure does not correspond to a standard HiC format, it is easy to manipulate a HiCExperiment object to coerce it into such structure.\n\nlibrary(multiHiCcompare)\nhics_list <- map(hics, ~ .x['XI'] |> \n zoom(2000) |> \n as.data.frame() |>\n select(start1, start2, count) |> \n mutate(chr = 1) |> \n relocate(chr)\n)\nmhicc <- make_hicexp(\n data_list = hics_list[c(3, 4, 5, 6)], \n groups = factor(c(1, 1, 2, 2)\n), A.min = 1)\n\nThe mhicc object contains data over the chromosome XI binned at 2kb for two pairs of replicates (WT or wpl1 G2/M HiC, each in duplicates):\n\nGroup1 contains WT data\nGroup2 contains wpl1 data\n\nTo identify differential interactions, the actual statistical comparison is performed with the hic_exactTest() function.\n\nresults <- cyclic_loess(mhicc, span = 0.2) |> hic_exactTest()\n## |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s\n## |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=05s\nresults \n## Hi-C Experiment Object\n## 2 experimental groups\n## Group 1 has 2 samples\n## Group 2 has 2 samples\n## Data has been normalized\n\nThe results() output is not very informative as it is. It requires a little bit of reformating to be able to extract valuable insights from it.\n\ndf <- left_join(results@hic_table, results(results)) |> \n mutate(dist = region2 - region1) |> \n mutate(group = case_when(\n region1 < 430000 & region2 > 450000 ~ 'inter_arms',\n region1 >= 430000 & region2 <= 450000 ~ 'at_centro',\n TRUE ~ 'arms'\n )) |> \n filter(group %in% c('arms', 'inter_arms')) |> \n mutate(sign = p.value <= 0.05 & abs(logFC) >= 1)\ndf\n## chr region1 region2 D IF1 IF2 IF3 IF4 logFC logCPM p.value p.adj dist group sign\n## 1 1 1 0 6.16 2.09 7.96 5.43 0.5401 4.81329 5.38e-01 7.94e-01 0 arms FALSE\n## 1 1 2001 1 16.38 10.25 12.96 12.16 -0.2257 5.82484 7.00e-01 8.81e-01 2000 arms FALSE\n## 1 1 4001 2 41.41 40.72 84.41 45.14 0.5064 7.69885 5.94e-02 2.16e-01 4000 arms FALSE\n## 1 1 6001 3 22.26 30.51 73.83 48.48 1.2726 8.10243 6.48e-07 5.83e-05 6000 arms TRUE\n## 1 1 8001 4 26.63 31.20 33.39 25.92 0.0998 7.55207 8.02e-01 9.34e-01 8000 arms FALSE\n## ...\nggplot(df, aes(x = logFC, y = -log10(p.value), col = sign)) + \n geom_point(size = 0.2) + \n theme_bw() + \n facet_wrap(~group) + \n ylim(c(0, 6)) + \n theme(legend.position = 'none') + \n scale_color_manual(values = c('grey', 'black'))\n\n\nIn this volcano plot, we can visually appreciate the fold-change of interaction frequency in WT or wpl1, for interactions constrained within the chromosome XI arms (left) or spanning the chr. XI centromere (right). This clearly highlights that interactions within arms are increased in wpl1 mutant while those spanning the centromere strongly decreased.\n\nOne of the strengths of HiContacts is that it can be leveraged to visualize any quantification related to genomic interactions as a HiC heatmap, since plotMatrix can take a GInteractions object with any score saved in mcols as input.\n\ngis <- rename(df, seqnames1 = chr, start1 = region1, start2 = region2) |> \n mutate(\n seqnames2 = seqnames1, \n end1 = start1 + 1999, \n end2 = start2 + 1999\n ) |> \n filter(abs(logFC) >= 1) |>\n df2gi() \ncowplot::plot_grid(\n plotMatrix(merged_replicates[['WT_G2M']], use.scores = 'balanced', limits = c(-3.5, -1), caption = FALSE),\n plotMatrix(merged_replicates[['wpl1_G2M']], use.scores = 'balanced', limits = c(-3.5, -1), caption = FALSE),\n plotMatrix(gis, use.scores = 'logFC', scale = 'linear', limits = c(-2, 2), cmap = bgrColors()), \n align = \"hv\", axis = 'tblr', nrow = 1\n)" + }, + { + "objectID": "pages/workflow-chicken.html", + "href": "pages/workflow-chicken.html", + "title": "\n11Β  Workflow 2: Chromosome compartment cohesion upon mitosis entry\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/workflow-chicken.html#importing-data", + "href": "pages/workflow-chicken.html#importing-data", + "title": "\n11Β  Workflow 2: Chromosome compartment cohesion upon mitosis entry\n", + "section": "\n11.1 Importing data", + "text": "11.1 Importing data\nThe 4DN consortium provides access to the datasets published in Gibcus et al. (2018). in R, they can be obtained thanks to the fourDNData gateway package.\n\n\n\n\n\n\nBeware\n\n\n\nThe first time the following chunk of code is executed, it will cache a large amount of data (mostly consisting of contact matrices stored in .mcool files).\n\n\n\nlibrary(HiCExperiment)\nlibrary(fourDNData)\nlibrary(BiocParallel)\nsamples <- list(\n '4DNES9LEZXN7' = 'G2 block', \n '4DNESNWWIFZU' = 'prophase (5m)', \n '4DNESGDXKM2I' = 'prophase (10m)', \n '4DNESIR416OW' = 'prometaphase (15m)', \n '4DNESS8PTK6F' = 'prometaphase (30m)' \n)\nbpparam <- MulticoreParam(workers = 5, progressbar = TRUE)\nhics <- bplapply(names(samples), fourDNHiCExperiment, BPPARAM = bpparam)\n## Fetching local Hi-C contact map from Bioc cache\n## Fetching local compartments bigwig file from Bioc cache\n## Fetching local insulation bigwig file from Bioc cache\n## Fetching local borders bed file from Bioc cache\n## Importing contacts in memory\n## |===================================================| 100% \n##\n## ...\n\n\nnames(hics) <- samples\nhics[[\"G2 block\"]]\n## `HiCExperiment` object with 150,494,008 contacts over 4,109 regions\n## -------\n## fileName: \"/home/rsg/.cache/R/fourDNData/25c33c9d826f_4DNFIT479GDR.mcool\"\n## focus: \"whole genome\"\n## resolutions(13): 1000 2000 ... 5000000 10000000\n## active resolution: 250000\n## interactions: 7262748\n## scores(2): count balanced\n## topologicalFeatures: compartments(891) borders(3465)\n## pairsFile: N/A\n## metadata(3): 4DN_info eigens diamond_insulation" + }, + { + "objectID": "pages/workflow-chicken.html#plotting-whole-chromosome-matrices", + "href": "pages/workflow-chicken.html#plotting-whole-chromosome-matrices", + "title": "\n11Β  Workflow 2: Chromosome compartment cohesion upon mitosis entry\n", + "section": "\n11.2 Plotting whole chromosome matrices", + "text": "11.2 Plotting whole chromosome matrices\nWe can visualize the five different Hi-C maps on the entire chromosome 3 with HiContacts by iterating over each of the HiCExperiment objects.\n\nlibrary(purrr)\nlibrary(HiContacts)\npl <- imap(hics, ~ .x['chr3'] |> \n zoom(100000) |> \n plotMatrix(use.scores = 'balanced', limits = c(-4, -1), caption = FALSE) + \n ggtitle(.y)\n)\nlibrary(cowplot)\nplot_grid(plotlist = pl, nrow = 1)\n\n\n\n\nThis highlights the progressive remodeling of chromatin into condensed chromosomes, starting as soon as 5’ after release from G2 phase." + }, + { + "objectID": "pages/workflow-chicken.html#zooming-on-a-chromosome-section", + "href": "pages/workflow-chicken.html#zooming-on-a-chromosome-section", + "title": "\n11Β  Workflow 2: Chromosome compartment cohesion upon mitosis entry\n", + "section": "\n11.3 Zooming on a chromosome section", + "text": "11.3 Zooming on a chromosome section\nZooming on a chromosome section, we can plot the Hi-C autocorrelation matrix for each timepoint. These matrices are generally used to highlight the overall correlation of interaction profiles between different segments of a chromosome section (see Chapter 5 for more details).\n\n## --- Format compartment positions of chr. 4 segment\n.chr <- 'chr4'\n.start <- 59000000L\n.stop <- 75000000L\nlibrary(GenomicRanges)\ncoords <- GRanges(paste0(.chr, ':', .start, '-', .stop))\ncompts_df <- topologicalFeatures(hics[[\"G2 block\"]], \"compartments\") |> \n subsetByOverlaps(coords, type = 'within') |> \n as.data.frame()\ncompts_gg <- geom_rect(\n data = compts_df, \n mapping = aes(xmin = start, xmax = end, ymin = -500000, ymax = 0, alpha = compartment), \n col = 'black', inherit.aes = FALSE\n)\n\n## --- Subset contact matrices to chr. 4 segment and computing autocorrelation scores\ng2 <- hics[[\"G2 block\"]] |> \n subsetByOverlaps(coords) |>\n zoom(100000) |> \n autocorrelate()\npro5 <- hics[[\"prophase (5m)\"]] |> \n subsetByOverlaps(coords) |>\n zoom(100000) |> \n autocorrelate()\npro30 <- hics[[\"prometaphase (30m)\"]] |> \n subsetByOverlaps(coords) |>\n zoom(100000) |> \n autocorrelate()\n\n## --- Plot autocorrelation matrices\nplot_grid(\n plotMatrix(\n g2,\n use.scores = 'autocorrelated', \n scale = 'linear', \n limits = c(-1, 1), \n cmap = bwrColors(), \n maxDistance = 10000000, \n caption = FALSE\n ) + ggtitle('G2') + compts_gg,\n plotMatrix(\n pro5,\n use.scores = 'autocorrelated', \n scale = 'linear', \n limits = c(-1, 1), \n cmap = bwrColors(), \n maxDistance = 10000000, \n caption = FALSE\n ) + ggtitle('Prophase 5min') + compts_gg,\n plotMatrix(\n pro30,\n use.scores = 'autocorrelated', \n scale = 'linear', \n limits = c(-1, 1), \n cmap = bwrColors(), \n maxDistance = 10000000, \n caption = FALSE\n ) + ggtitle('Prometaphase 30min') + compts_gg,\n nrow = 1\n)\n\n\n\n\nThese correlation matrices suggest that there are two different regimes of chromatin compartment remodeling in this chromosome section:\n\nCorrelation scores between genomic bins within the compartment A remain positive 5’ after G2 release (albeit reduced compared to G2 block) and eventually become null 30’ after G2 release.\nCorrelation scores between genomic bins within the compartment B are overall null as soon as 5’ after G2 release." + }, + { + "objectID": "pages/workflow-chicken.html#generating-saddle-plots", + "href": "pages/workflow-chicken.html#generating-saddle-plots", + "title": "\n11Β  Workflow 2: Chromosome compartment cohesion upon mitosis entry\n", + "section": "\n11.4 Generating saddle plots", + "text": "11.4 Generating saddle plots\nSaddle plots are typically used to measure the observed vs.Β expected interaction scores within or between genomic loci belonging to A and B compartments. Here, they can be used to check whether the two regimes of chromatin compartment remodeling are observed genome-wide.\nNon-overlapping genomic windows are grouped by nbins quantiles (typically between 10 and 50 bins) according to their A/B compartment eigenvector value, from lowest eigenvector values (i.e.Β strongest B compartments) to highest eigenvector values (i.e.Β strongest A compartments). The average observed vs.Β expected interaction scores are computed for pairwise eigenvector quantiles and plotted in a 2D heatmap.\n\npl <- imap(hics, ~ plotSaddle(.x, nbins = 38, BPPARAM = bpparam) + ggtitle(.y)) \nplot_grid(plotlist = pl, nrow = 1)\n\n\n\n\nThese plots confirm the previous observation made on chr. 4 and reveal that intra-B compartment interactions are generally lost 5’ after G2 release, while intra-A interactions take up to 15’ after G2 release to disappear.\n\n\n\n\n\n\nBeware\n\n\n\nThe plotSaddle() function requires an eigenvector corresponding to A/B compartments. In this example, this eigenvector is recovered from the 4DN data portal. If not already available, this eigenvector can be computed from the contact matrix using the getCompartments() function." + }, + { + "objectID": "pages/workflow-chicken.html#quantifying-interactions-within-and-between-compartments", + "href": "pages/workflow-chicken.html#quantifying-interactions-within-and-between-compartments", + "title": "\n11Β  Workflow 2: Chromosome compartment cohesion upon mitosis entry\n", + "section": "\n11.5 Quantifying interactions within and between compartments", + "text": "11.5 Quantifying interactions within and between compartments\nWe can leverage the replicate-merged contact matrices to quantify the interaction frequencies within A or B compartments or between A and B comaprtments, at different timepoints.\nWe can use the A/B compartment annotations obtained at the G2 block timepoint and extract O/E (observed vs expected) scores for interactions within A or B compartments or between A and B compartments, at different timepoints.\n\n## --- Extract the A/B compartments identified in G2 block\ncompts <- topologicalFeatures(hics[[\"G2 block\"]], \"compartments\")\ncompts$ID <- paste0(compts$compartment, seq_along(compts))\n\n## --- Iterate over timepoints to extract `detrended` (O/E) scores and \n## compartment annotations\nlibrary(plyranges)\ndf <- imap(hics[c(1, 2, 5)], ~ {\n ints <- cis(.x) |> ## Filter out trans interactions\n detrend() |> ## Compute O/E scores\n interactions() ## Recover interactions \n ints$comp_first <- join_overlap_left(anchors(ints, \"first\"), compts)$ID\n ints$comp_second <- join_overlap_left(anchors(ints, \"second\"), compts)$ID\n tibble(\n sample = .y, \n bin1 = ints$comp_first, \n bin2 = ints$comp_second, \n dist = pairdist(ints), \n OE = ints$detrended \n ) |> \n filter(dist > 5e6) |>\n mutate(type = case_when(\n grepl('A', bin1) & grepl('A', bin2) ~ 'AA',\n grepl('B', bin1) & grepl('B', bin2) ~ 'BB',\n grepl('A', bin1) & grepl('B', bin2) ~ 'AB',\n grepl('B', bin1) & grepl('A', bin2) ~ 'BA'\n )) |> \n filter(bin1 != bin2)\n}) |> list_rbind() |> mutate(\n sample = factor(sample, names(hics)[c(1, 2, 5)])\n)\n\nWe can now plot the changes in O/E scores for intra-A, intra-B, A-B or B-A interactions, splitting boxplots by timepoint.\n\nggplot(df, aes(x = type, y = OE, group = type, fill = type)) + \n geom_boxplot(outlier.shape = NA) + \n facet_grid(~sample) + \n theme_bw() + \n ylim(c(-2, 2))\n\n\nThis visualization suggests that interactions between genomic loci belonging to the B compartment are lost more rapidly than those between genomic loci belonging to the A compartment, when cells are released from G2 to enter mitosis." + }, + { + "objectID": "pages/workflow-centros.html", + "href": "pages/workflow-centros.html", + "title": "\n12Β  Workflow 3: Inter-centromere interactions in yeast\n", + "section": "", + "text": "References" + }, + { + "objectID": "pages/workflow-centros.html#importing-hi-c-data-and-plotting-contact-matrices", + "href": "pages/workflow-centros.html#importing-hi-c-data-and-plotting-contact-matrices", + "title": "\n12Β  Workflow 3: Inter-centromere interactions in yeast\n", + "section": "\n12.1 Importing Hi-C data and plotting contact matrices", + "text": "12.1 Importing Hi-C data and plotting contact matrices\n\nlibrary(HiContacts)\nlibrary(purrr)\nlibrary(ggplot2)\nhics <- list(\n 'G1' = import('/home/rsg/repos/OHCA-data/S288c_G1.mcool', resolution = 4000),\n 'G2M' = import('/home/rsg/repos/OHCA-data/S288c_G2M.mcool', resolution = 4000)\n)\nimap(hics, ~ plotMatrix(\n .x, use.scores = 'balanced', limits = c(-4, -1), caption = FALSE\n) + ggtitle(.y))\n\n\nWe can visually appreciate that inter-chromosomal interactions, notably between centromeres, are less prominent in G2/M." + }, + { + "objectID": "pages/workflow-centros.html#checking-ps-and-cistrans-interactions-ratio", + "href": "pages/workflow-centros.html#checking-ps-and-cistrans-interactions-ratio", + "title": "\n12Β  Workflow 3: Inter-centromere interactions in yeast\n", + "section": "\n12.2 Checking P(s) and cis/trans interactions ratio", + "text": "12.2 Checking P(s) and cis/trans interactions ratio\n\nlibrary(dplyr)\npairs <- list(\n 'G1' = PairsFile('/home/rsg/repos/OHCA-data/S288c_G1.pairs'),\n 'G2M' = PairsFile('/home/rsg/repos/OHCA-data/S288c_G2M.pairs') \n)\nps <- imap_dfr(pairs, ~ distanceLaw(.x, by_chr = TRUE) |> \n mutate(sample = .y) \n)\nplotPs(ps, aes(x = binned_distance, y = norm_p, group = interaction(sample, chr), color = sample)) + \n scale_color_manual(values = c('black', 'red'))\nplotPsSlope(ps, ggplot2::aes(x = binned_distance, y = slope, group = interaction(sample, chr), color = sample)) + \n scale_color_manual(values = c('black', 'red'))\n\n\nThis confirms that interactions in cells synchronized in G2/M are enriched for 10-30kb-long interactions.\n\nratios <- imap_dfr(hics, ~ cisTransRatio(.x) |> mutate(sample = .y))\nggplot(ratios, aes(x = chr, y = trans_pct, fill = sample)) + \n geom_col() + \n labs(x = 'Chromosomes', y = \"% of trans interactions\") + \n scale_y_continuous(labels = scales::percent) + \n facet_grid(~sample)\n\n\nWe can also highlight that trans (inter-chromosomal) interactions are proportionally decreasing in G2/M-synchronized cells." + }, + { + "objectID": "pages/workflow-centros.html#centromere-virtual-4c-profiles", + "href": "pages/workflow-centros.html#centromere-virtual-4c-profiles", + "title": "\n12Β  Workflow 3: Inter-centromere interactions in yeast\n", + "section": "\n12.3 Centromere virtual 4C profiles", + "text": "12.3 Centromere virtual 4C profiles\n\ndata(centros_yeast)\nv4c_centro <- imap_dfr(hics, ~ virtual4C(.x, resize(centros_yeast[2], 8000)) |> \n as_tibble() |> \n mutate(sample = .y) |> \n filter(seqnames == 'IV')\n) \nggplot(v4c_centro, aes(x = start, y = score, colour = sample)) +\n geom_line() +\n theme_bw() +\n labs(\n x = \"chrIV position\", \n y = \"Contacts with chrII centromere\", \n title = \"Interaction profile of chrII centromere\"\n )" + }, + { + "objectID": "pages/workflow-centros.html#aggregated-2d-signal-over-all-pairs-of-centromeres", + "href": "pages/workflow-centros.html#aggregated-2d-signal-over-all-pairs-of-centromeres", + "title": "\n12Β  Workflow 3: Inter-centromere interactions in yeast\n", + "section": "\n12.4 Aggregated 2D signal over all pairs of centromeres", + "text": "12.4 Aggregated 2D signal over all pairs of centromeres\nWe can start by computing all possible pairs of centromeres.\n\ncentros_pairs <- lapply(1:length(centros_yeast), function(i) {\n lapply(1:length(centros_yeast), function(j) {\n S4Vectors::Pairs(centros_yeast[i], centros_yeast[j])\n })\n}) |> \n do.call(c, args = _) |>\n do.call(c, args = _) |> \n InteractionSet::makeGInteractionsFromGRangesPairs()\ncentros_pairs <- centros_pairs[anchors(centros_pairs, 'first') != anchors(centros_pairs, 'second')]\n\ncentros_pairs\n## GInteractions object with 240 interactions and 0 metadata columns:\n## seqnames1 ranges1 seqnames2 ranges2\n## <Rle> <IRanges> <Rle> <IRanges>\n## [1] I 151583-151641 --- II 238361-238419\n## [2] I 151583-151641 --- III 114322-114380\n## [3] I 151583-151641 --- IV 449879-449937\n## [4] I 151583-151641 --- V 152522-152580\n## [5] I 151583-151641 --- VI 147981-148039\n## ... ... ... ... ... ...\n## [236] XVI 556255-556313 --- XI 440229-440287\n## [237] XVI 556255-556313 --- XII 151366-151424\n## [238] XVI 556255-556313 --- XIII 268222-268280\n## [239] XVI 556255-556313 --- XIV 628588-628646\n## [240] XVI 556255-556313 --- XV 326897-326955\n## -------\n## regions: 16 ranges and 0 metadata columns\n## seqinfo: 17 sequences (1 circular) from R64-1-1 genome\n\nThen we can aggregate the Hi-C signal over each pair of centromeres.\n\naggr_maps <- purrr::imap(hics, ~ {\n aggr <- aggregate(.x, centros_pairs, maxDistance = 1e999)\n plotMatrix(\n aggr, use.scores = 'balanced', limits = c(-5, -1), \n cmap = HiContacts::rainbowColors(), \n caption = FALSE\n ) + ggtitle(.y)\n})\n## Going through preflight checklist...\n## Parsing the entire contact matrice as a sparse matrix...\n## Modeling distance decay...\n## Filtering for contacts within provided targets...\n## Going through preflight checklist...\n## Parsing the entire contact matrice as a sparse matrix...\n## Modeling distance decay...\n## Filtering for contacts within provided targets...\n\ncowplot::plot_grid(plotlist = aggr_maps, nrow = 1)" + }, + { + "objectID": "pages/workflow-centros.html#aggregated-1d-interaction-profile-of-centromeres", + "href": "pages/workflow-centros.html#aggregated-1d-interaction-profile-of-centromeres", + "title": "\n12Β  Workflow 3: Inter-centromere interactions in yeast\n", + "section": "\n12.5 Aggregated 1D interaction profile of centromeres", + "text": "12.5 Aggregated 1D interaction profile of centromeres\nOne can generalize the previous virtual 4C plot, by extracting the interaction profile between all possible pairs of centromeres in each dataset.\n\ndf <- map_dfr(1:{length(centros_yeast)-1}, function(i) {\n centro1 <- resize(centros_yeast[i], fix = 'center', 8000)\n map_dfr({i+1}:length(centros_yeast), function(j) {\n centro2 <- resize(centros_yeast[j], fix = 'center', 80000)\n gi <- GInteractions(centro1, centro2)\n imap_dfr(hics, ~ .x[gi] |> \n interactions() |> \n as_tibble() |>\n mutate(\n sample = .y, \n center = center2 - start(resize(centro2, fix = 'center', 1))\n ) |> \n select(sample, seqnames1, seqnames2, center, balanced)\n )\n })\n}) \np <- ggplot(df, aes(x = center/1e3, y = balanced)) + \n geom_line(aes(group = interaction(seqnames1, seqnames2)), alpha = 0.03, col = \"black\") + \n geom_smooth(col = \"red\", fill = \"red\") + \n theme_bw() + \n theme(legend.position = 'none') + \n labs(\n x = \"Distance from centromere (kb)\", y = \"Normalized interaction frequency\", \n title = \"Centromere pairwise interaction profiles\"\n ) +\n facet_grid(~sample)" + } +] \ No newline at end of file diff --git a/docs/devel/site_libs/bootstrap/bootstrap-icons.css b/docs/devel/site_libs/bootstrap/bootstrap-icons.css new file mode 100644 index 0000000..94f1940 --- /dev/null +++ b/docs/devel/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/docs/devel/site_libs/bootstrap/bootstrap-icons.woff b/docs/devel/site_libs/bootstrap/bootstrap-icons.woff new file mode 100644 index 0000000..18d21d4 Binary files /dev/null and b/docs/devel/site_libs/bootstrap/bootstrap-icons.woff differ diff --git a/docs/devel/site_libs/bootstrap/bootstrap.min.css b/docs/devel/site_libs/bootstrap/bootstrap.min.css new file mode 100644 index 0000000..0c35ee0 --- /dev/null +++ b/docs/devel/site_libs/bootstrap/bootstrap.min.css @@ -0,0 +1,10 @@ +ο»Ώ/*! + * 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) + */@import"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap";:root{--bs-blue: #2780e3;--bs-indigo: #6610f2;--bs-purple: #613d7c;--bs-pink: #e83e8c;--bs-red: #ff0039;--bs-orange: #f0ad4e;--bs-yellow: #ff7518;--bs-green: #3fb618;--bs-teal: #20c997;--bs-cyan: #9954bb;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #373a3c;--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: #373a3c;--bs-gray-900: #212529;--bs-default: #373a3c;--bs-primary: #070707;--bs-secondary: #373a3c;--bs-success: #3fb618;--bs-info: #9954bb;--bs-warning: #ff7518;--bs-danger: #ff0039;--bs-light: #f8f9fa;--bs-dark: #373a3c;--bs-default-rgb: 55, 58, 60;--bs-primary-rgb: 7, 7, 7;--bs-secondary-rgb: 55, 58, 60;--bs-success-rgb: 63, 182, 24;--bs-info-rgb: 153, 84, 187;--bs-warning-rgb: 255, 117, 24;--bs-danger-rgb: 255, 0, 57;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 55, 58, 60;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-body-color-rgb: 7, 7, 7;--bs-body-bg-rgb: 255, 255, 255;--bs-font-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: Atkinson Hyperlegible, sans-serif;--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #070707;--bs-body-bg: #fff}*,*::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:400;line-height:1.2}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title],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:#070707;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{color:#060606}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.875em;color:#000;background-color:#f5f5f5;padding:.5rem;border:1px solid #dee2e6}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:#9753b8;background-color:#f5f5f5;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529}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;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: #070707;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #070707;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #070707;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#070707;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 #878787}.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: #cdcdcd;--bs-table-striped-bg: #c3c3c3;--bs-table-striped-color: #000;--bs-table-active-bg: #b9b9b9;--bs-table-active-color: #000;--bs-table-hover-bg: #bebebe;--bs-table-hover-color: #000;color:#000;border-color:#b9b9b9}.table-secondary{--bs-table-bg: #d7d8d8;--bs-table-striped-bg: #cccdcd;--bs-table-striped-color: #000;--bs-table-active-bg: #c2c2c2;--bs-table-active-color: #000;--bs-table-hover-bg: #c7c8c8;--bs-table-hover-color: #000;color:#000;border-color:#c2c2c2}.table-success{--bs-table-bg: #d9f0d1;--bs-table-striped-bg: #cee4c7;--bs-table-striped-color: #000;--bs-table-active-bg: #c3d8bc;--bs-table-active-color: #000;--bs-table-hover-bg: #c9dec1;--bs-table-hover-color: #000;color:#000;border-color:#c3d8bc}.table-info{--bs-table-bg: #ebddf1;--bs-table-striped-bg: #dfd2e5;--bs-table-striped-color: #000;--bs-table-active-bg: #d4c7d9;--bs-table-active-color: #000;--bs-table-hover-bg: #d9ccdf;--bs-table-hover-color: #000;color:#000;border-color:#d4c7d9}.table-warning{--bs-table-bg: #ffe3d1;--bs-table-striped-bg: #f2d8c7;--bs-table-striped-color: #000;--bs-table-active-bg: #e6ccbc;--bs-table-active-color: #000;--bs-table-hover-bg: #ecd2c1;--bs-table-hover-color: #000;color:#000;border-color:#e6ccbc}.table-danger{--bs-table-bg: #ffccd7;--bs-table-striped-bg: #f2c2cc;--bs-table-striped-color: #000;--bs-table-active-bg: #e6b8c2;--bs-table-active-color: #000;--bs-table-hover-bg: #ecbdc7;--bs-table-hover-color: #000;color:#000;border-color:#e6b8c2}.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: #373a3c;--bs-table-striped-bg: #414446;--bs-table-striped-color: #fff;--bs-table-active-bg: #4b4e50;--bs-table-active-color: #fff;--bs-table-hover-bg: #46494b;--bs-table-hover-color: #fff;color:#fff;border-color:#4b4e50}.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:#070707;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:0;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:#070707;background-color:#fff;border-color:#838383;outline:0;box-shadow:0 0 0 .25rem rgba(7,7,7,.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:#070707;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:#070707;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:#070707;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}.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}.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}.form-control-color::-webkit-color-swatch{height:1.5em}.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:#070707;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='%23373a3c' 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:0;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:#838383;outline:0;box-shadow:0 0 0 .25rem rgba(7,7,7,.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 #070707}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.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=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:#838383;outline:0;box-shadow:0 0 0 .25rem rgba(7,7,7,.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:#070707;border-color:#070707}.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='%23fff' 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='%23fff'/%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:#070707;border-color:#070707;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='%23fff' 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;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='%23838383'/%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='%23fff'/%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(7,7,7,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(7,7,7,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;background-color:#070707;border:0;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:#b5b5b5}.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)}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#070707;border:0;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:#b5b5b5}.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)}.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:#070707;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da}.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}.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}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#3fb618}.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(63,182,24,.9)}.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:#3fb618;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='%233fb618' 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:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.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:#3fb618}.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='%23373a3c' 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='%233fb618' 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:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#3fb618}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#3fb618}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#3fb618}.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:#ff0039}.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(255,0,57,.9)}.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:#ff0039;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='%23ff0039'%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='%23ff0039' 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:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.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:#ff0039}.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='%23373a3c' 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='%23ff0039'%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='%23ff0039' 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:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#ff0039}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#ff0039}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#ff0039}.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:#070707;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: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){.btn{transition:none}}.btn:hover{color:#070707}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(7,7,7,.25)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-default{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-default:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-default,.btn-default:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-default,.btn-check:active+.btn-default,.btn-default:active,.btn-default.active,.show>.btn-default.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.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(85,88,89,.5)}.btn-default:disabled,.btn-default.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-primary{color:#fff;background-color:#070707;border-color:#070707}.btn-primary:hover{color:#fff;background-color:#060606;border-color:#060606}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#060606;border-color:#060606;box-shadow:0 0 0 .25rem rgba(44,44,44,.5)}.btn-check:checked+.btn-primary,.btn-check:active+.btn-primary,.btn-primary:active,.btn-primary.active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#060606;border-color:#050505}.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(44,44,44,.5)}.btn-primary:disabled,.btn-primary.disabled{color:#fff;background-color:#070707;border-color:#070707}.btn-secondary{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-secondary:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-secondary,.btn-check:active+.btn-secondary,.btn-secondary:active,.btn-secondary.active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.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(85,88,89,.5)}.btn-secondary:disabled,.btn-secondary.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-success{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-success:hover{color:#fff;background-color:#369b14;border-color:#329213}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#369b14;border-color:#329213;box-shadow:0 0 0 .25rem rgba(92,193,59,.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:#329213;border-color:#2f8912}.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(92,193,59,.5)}.btn-success:disabled,.btn-success.disabled{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-info{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-info:hover{color:#fff;background-color:#82479f;border-color:#7a4396}.btn-check:focus+.btn-info,.btn-info:focus{color:#fff;background-color:#82479f;border-color:#7a4396;box-shadow:0 0 0 .25rem rgba(168,110,197,.5)}.btn-check:checked+.btn-info,.btn-check:active+.btn-info,.btn-info:active,.btn-info.active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#7a4396;border-color:#733f8c}.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(168,110,197,.5)}.btn-info:disabled,.btn-info.disabled{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-warning{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-warning:hover{color:#fff;background-color:#d96314;border-color:#cc5e13}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#fff;background-color:#d96314;border-color:#cc5e13;box-shadow:0 0 0 .25rem rgba(255,138,59,.5)}.btn-check:checked+.btn-warning,.btn-check:active+.btn-warning,.btn-warning:active,.btn-warning.active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#cc5e13;border-color:#bf5812}.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(255,138,59,.5)}.btn-warning:disabled,.btn-warning.disabled{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-danger{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-danger:hover{color:#fff;background-color:#d90030;border-color:#cc002e}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#d90030;border-color:#cc002e;box-shadow:0 0 0 .25rem rgba(255,38,87,.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:#cc002e;border-color:#bf002b}.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(255,38,87,.5)}.btn-danger:disabled,.btn-danger.disabled{color:#fff;background-color:#ff0039;border-color:#ff0039}.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:#373a3c;border-color:#373a3c}.btn-dark:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.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:#2c2e30;border-color:#292c2d}.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(85,88,89,.5)}.btn-dark:disabled,.btn-dark.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-outline-default{color:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-default:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-default,.btn-outline-default:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.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:#fff;background-color:#373a3c;border-color:#373a3c}.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(55,58,60,.5)}.btn-outline-default:disabled,.btn-outline-default.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-primary{color:#070707;border-color:#070707;background-color:rgba(0,0,0,0)}.btn-outline-primary:hover{color:#fff;background-color:#070707;border-color:#070707}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(7,7,7,.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:#fff;background-color:#070707;border-color:#070707}.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(7,7,7,.5)}.btn-outline-primary:disabled,.btn-outline-primary.disabled{color:#070707;background-color:rgba(0,0,0,0)}.btn-outline-secondary{color:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-secondary:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.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:#fff;background-color:#373a3c;border-color:#373a3c}.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(55,58,60,.5)}.btn-outline-secondary:disabled,.btn-outline-secondary.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-success{color:#3fb618;border-color:#3fb618;background-color:rgba(0,0,0,0)}.btn-outline-success:hover{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.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:#3fb618;border-color:#3fb618}.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(63,182,24,.5)}.btn-outline-success:disabled,.btn-outline-success.disabled{color:#3fb618;background-color:rgba(0,0,0,0)}.btn-outline-info{color:#9954bb;border-color:#9954bb;background-color:rgba(0,0,0,0)}.btn-outline-info:hover{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(153,84,187,.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:#fff;background-color:#9954bb;border-color:#9954bb}.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(153,84,187,.5)}.btn-outline-info:disabled,.btn-outline-info.disabled{color:#9954bb;background-color:rgba(0,0,0,0)}.btn-outline-warning{color:#ff7518;border-color:#ff7518;background-color:rgba(0,0,0,0)}.btn-outline-warning:hover{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,117,24,.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:#fff;background-color:#ff7518;border-color:#ff7518}.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,117,24,.5)}.btn-outline-warning:disabled,.btn-outline-warning.disabled{color:#ff7518;background-color:rgba(0,0,0,0)}.btn-outline-danger{color:#ff0039;border-color:#ff0039;background-color:rgba(0,0,0,0)}.btn-outline-danger:hover{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.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:#ff0039;border-color:#ff0039}.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(255,0,57,.5)}.btn-outline-danger:disabled,.btn-outline-danger.disabled{color:#ff0039;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:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-dark:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.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:#373a3c;border-color:#373a3c}.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(55,58,60,.5)}.btn-outline-dark:disabled,.btn-outline-dark.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-link{font-weight:400;color:#070707;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:hover{color:#060606}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:0}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:0}.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:#070707;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15)}.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:#fff;text-decoration:none;background-color:#070707}.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:#373a3c;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:#fff;background-color:#070707}.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}.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}.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:#070707;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:#060606}.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)}.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}.nav-pills .nav-link{background:none;border:0}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#070707}.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);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:#f8f9fa}.navbar-light .navbar-brand{color:#545555}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:#070707}.navbar-light .navbar-nav .nav-link{color:#545555}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(7,7,7,.8)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(84,85,85,.75)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .nav-link.active{color:#070707}.navbar-light .navbar-toggler{color:#545555;border-color:rgba(84,85,85,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='%23545555' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:#545555}.navbar-light .navbar-text a,.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:#070707}.navbar-dark{background-color:#f8f9fa}.navbar-dark .navbar-brand{color:#545555}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#070707}.navbar-dark .navbar-nav .nav-link{color:#545555}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(7,7,7,.8)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(84,85,85,.75)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active{color:#070707}.navbar-dark .navbar-toggler{color:#545555;border-color:rgba(84,85,85,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='%23545555' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:#545555}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#070707}.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)}.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}.card>.list-group:last-child{border-bottom-width:0}.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-footer{padding:.5rem 1rem;background-color:#adb5bd;border-top:1px solid rgba(0,0,0,.125)}.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}.card-img,.card-img-top,.card-img-bottom{width:100%}.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}}.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:#070707;text-align:left;background-color:#fff;border: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:#060606;background-color:#e6e6e6;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='%23060606'%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='%23070707'%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:#838383;outline:0;box-shadow:0 0 0 .25rem rgba(7,7,7,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom: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:#070707;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:#060606;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#060606;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(7,7,7,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#070707;border-color:#070707}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:0.875rem}.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}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:0 solid rgba(0,0,0,0)}.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:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-default .alert-link{color:#1a1c1d}.alert-primary{color:#040404;background-color:#cdcdcd;border-color:#b5b5b5}.alert-primary .alert-link{color:#030303}.alert-secondary{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-secondary .alert-link{color:#1a1c1d}.alert-success{color:#266d0e;background-color:#d9f0d1;border-color:#c5e9ba}.alert-success .alert-link{color:#1e570b}.alert-info{color:#5c3270;background-color:#ebddf1;border-color:#e0cceb}.alert-info .alert-link{color:#4a285a}.alert-warning{color:#99460e;background-color:#ffe3d1;border-color:#ffd6ba}.alert-warning .alert-link{color:#7a380b}.alert-danger{color:#902;background-color:#ffccd7;border-color:#ffb3c4}.alert-danger .alert-link{color:#7a001b}.alert-light{color:#959596;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#777778}.alert-dark{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-dark .alert-link{color:#1a1c1d}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress{display:flex;display:-webkit-flex;height:.5rem;overflow:hidden;font-size:0.75rem;background-color:#e9ecef}.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:#070707;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:.5rem .5rem}.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}.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:#070707;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.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#070707;border-color:#070707}.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.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.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.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.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.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.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>.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:#212324;background-color:#d7d8d8}.list-group-item-default.list-group-item-action:hover,.list-group-item-default.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-default.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.list-group-item-primary{color:#040404;background-color:#cdcdcd}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#040404;background-color:#b9b9b9}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#040404;border-color:#040404}.list-group-item-secondary{color:#212324;background-color:#d7d8d8}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.list-group-item-success{color:#266d0e;background-color:#d9f0d1}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#266d0e;background-color:#c3d8bc}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#266d0e;border-color:#266d0e}.list-group-item-info{color:#5c3270;background-color:#ebddf1}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#5c3270;background-color:#d4c7d9}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#5c3270;border-color:#5c3270}.list-group-item-warning{color:#99460e;background-color:#ffe3d1}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#99460e;background-color:#e6ccbc}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#99460e;border-color:#99460e}.list-group-item-danger{color:#902;background-color:#ffccd7}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#902;background-color:#e6b8c2}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#902;border-color:#902}.list-group-item-light{color:#959596;background-color:#fefefe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#959596;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#959596;border-color:#959596}.list-group-item-dark{color:#212324;background-color:#d7d8d8}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.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;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(7,7,7,.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)}.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)}.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);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}.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}.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}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:"Atkinson Hyperlegible",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}.popover{position:absolute;top:0;left:0 /* rtl:ignore */;z-index:1070;display:block;max-width:276px;font-family:"Atkinson Hyperlegible",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)}.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)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#070707}.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='%23fff'%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='%23fff'%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:#373a3c}.link-default:hover,.link-default:focus{color:#2c2e30}.link-primary{color:#070707}.link-primary:hover,.link-primary:focus{color:#060606}.link-secondary{color:#373a3c}.link-secondary:hover,.link-secondary:focus{color:#2c2e30}.link-success{color:#3fb618}.link-success:hover,.link-success:focus{color:#329213}.link-info{color:#9954bb}.link-info:hover,.link-info:focus{color:#7a4396}.link-warning{color:#ff7518}.link-warning:hover,.link-warning:focus{color:#cc5e13}.link-danger{color:#ff0039}.link-danger:hover,.link-danger:focus{color:#cc002e}.link-light{color:#f8f9fa}.link-light:hover,.link-light:focus{color:#f9fafb}.link-dark{color:#373a3c}.link-dark:hover,.link-dark:focus{color:#2c2e30}.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:#373a3c !important}.border-primary{border-color:#070707 !important}.border-secondary{border-color:#373a3c !important}.border-success{border-color:#3fb618 !important}.border-info{border-color:#9954bb !important}.border-warning{border-color:#ff7518 !important}.border-danger{border-color:#ff0039 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#373a3c !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.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-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:#fff}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#fff}.bg-warning{color:#fff}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-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}}.sidebar-item .chapter-number{color:#070707}.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:#545555}.navbar .quarto-navbar-tools .quarto-navigation-tool:hover{color:#070707}@media(max-width: 991.98px){.navbar .quarto-navbar-tools{margin-top:.25em;padding-top:.75em;display:block;color:solid #d4d4d4 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:#545555}.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:#545555;padding-top:4px}.quarto-secondary-nav nav.quarto-page-breadcrumbs{color:#545555}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{color:#545555}.quarto-secondary-nav nav.quarto-page-breadcrumbs a:hover{color:rgba(7,7,7,.8)}.quarto-secondary-nav nav.quarto-page-breadcrumbs .breadcrumb-item::before{color:#878888}div.sidebar-item-container{color:#545555}div.sidebar-item-container:hover,div.sidebar-item-container:focus{color:rgba(7,7,7,.8)}div.sidebar-item-container.disabled{color:rgba(84,85,85,.75)}div.sidebar-item-container .active,div.sidebar-item-container .show>.nav-link,div.sidebar-item-container .sidebar-link>code{color:#070707}div.sidebar.sidebar-navigation.rollup.quarto-sidebar-toggle-contents,nav.sidebar.sidebar-navigation:not(.rollup){background-color:#f8f9fa}.sidebar.sidebar-navigation:not(.rollup){border-right:1px solid #dee2e6 !important}@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:#f8f9fa;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:#060606}.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:#060606}.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:#f8f9fa}body.nav-fixed{padding-top:64px}body .nav-footer{border-top:1px solid #dee2e6}.nav-footer-contents{color:#6c757d;margin-top:.25rem}.nav-footer{min-height:3.5em;color:#727373}.nav-footer a{color:#727373}.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:#545555;border-radius:3px}.quarto-reader-toggle.reader.quarto-navigation-tool .quarto-reader-toggle-btn{background-color:#545555;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:#545555;opacity:1}.navbar #quarto-search.type-overlay .aa-Autocomplete svg.aa-SubmitIcon{width:26px;height:26px;color:#545555;opacity:1}.aa-Autocomplete .aa-Form,.aa-DetachedFormContainer .aa-Form{align-items:center;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;color:#070707;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(7,7,7,.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:#070707;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:#070707;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:#070707;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:#070707;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:#070707;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:#070707;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:#070707;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:#070707}.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:#fff;background-color:#070707}.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:#fff;background-color:#1b1b1b}.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:#070707}.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:#727272}.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:#070707}.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:#070707}.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:#545555}.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:#545555}.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:#070707;cursor:pointer;margin:0 0 0 .5em;padding:0 .5em}.aa-DetachedCancelButton:hover,.aa-DetachedCancelButton:focus{box-shadow:rgba(7,7,7,.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(7,7,7,.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:#070707;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:#070707;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:"Atkinson Hyperlegible",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:#3a3a3a;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:#070707}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:#3a3a3a;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:#070707}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:#3a3a3a;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:#070707}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:#3a3a3a;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:#070707}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:#3a3a3a;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:#070707}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:#070707;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:#070707}.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}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: #fff;--quarto-body-color: #070707;--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: #fff;--mermaid-edge-color: #373a3c;--mermaid-node-fg-color: #070707;--mermaid-fg-color: #070707;--mermaid-fg-color--lighter: #212121;--mermaid-fg-color--lightest: #3a3a3a;--mermaid-font-family: Source Sans Pro, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;--mermaid-label-bg-color: #fff;--mermaid-label-fg-color: #070707;--mermaid-node-bg-color: rgba(7, 7, 7, 0.1);--mermaid-node-fg-color: #070707}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 70px [body-start-outset] 70px [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] 70px [body-start-outset] 70px [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] 70px [body-start-outset] 70px [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] 70px [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(100px, 200px) [page-start-inset] 100px [body-start-outset] 100px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 3em [body-end] 100px [body-end-outset] minmax(0px, 250px) [page-end-inset] minmax(100px, 200px) [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] 70px [page-start-inset] minmax(0px, 350px) [body-start-outset] 70px [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] 70px [page-start-inset] minmax(0px, 350px) [body-start-outset] 70px [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(50px, 100px) [page-start-inset] minmax(100px, 300px) [body-start-outset] minmax(50px, 100px) [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(100px, 200px) [page-start-inset] 100px [body-start-outset] 100px [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(100px, 200px) [page-start-inset] 100px [body-start-outset] 100px [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] 100px [page-start-inset] minmax(100px, 300px) [body-start-outset] 100px [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(100px, 200px) [page-start-inset] 100px [body-start-outset] 100px [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(100px, 200px) [page-start-inset] 100px [body-start-outset] 100px [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] 100px [page-start-inset] minmax(100px, 300px) [body-start-outset] 100px [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(50px, 100px) [page-start-inset] minmax(100px, 300px) [body-start-outset] minmax(50px, 100px) [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] 70px [page-start-inset] minmax(0px, 290px) [body-start-outset] 70px [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] 70px [page-start-inset] minmax(0px, 290px) [body-start-outset] 70px [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:#474747}.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:#474747}.table-caption,caption{color:#070707}.quarto-layout-cell[data-ref-parent] caption{color:#474747}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#474747;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:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.25rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#474747}.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:#070707}.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:#070707}.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 #070707;color:#070707 !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#070707 !important}kbd,.kbd{color:#070707;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 #878787}.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:#2780e3}div.callout-note.callout-style-default>.callout-header{background-color:#e9f2fc}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:#3fb618}div.callout-tip.callout-style-default>.callout-header{background-color:#ecf8e8}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:#ff7518}div.callout-warning.callout-style-default>.callout-header{background-color:#fff1e8}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:#f0ad4e}div.callout-caution.callout-style-default>.callout-header{background-color:#fef7ed}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:#ff0039}div.callout-important.callout-style-default>.callout-header{background-color:#ffe6eb}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:#070707}.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:#cbcccc;background-color:#373a3c;border-color:#373a3c}.btn.btn-quarto:hover,div.cell-output-display .btn-quarto:hover{color:#cbcccc;background-color:#555859;border-color:#4b4e50}.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:#cbcccc;background-color:#555859;border-color:#4b4e50;box-shadow:0 0 0 .25rem rgba(77,80,82,.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:#fff;background-color:#5f6163;border-color:#4b4e50}.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(77,80,82,.5)}.btn.btn-quarto:disabled,.btn.btn-quarto.disabled,div.cell-output-display .btn-quarto:disabled,div.cell-output-display .btn-quarto.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}nav.quarto-secondary-nav.color-navbar{background-color:#f8f9fa;color:#545555}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#545555}@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:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:var(--bs-font-monospace);color:#212121;border:solid #212121 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family: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:#bababa;border-bottom-style:solid;border-bottom-width:1px}.table>:not(:first-child){border-top:1px solid #878787;border-bottom:1px solid inherit}.table tbody{border-bottom-color:#878787}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:#545555;background:#f8f9fa}.quarto-title-banner .code-tools-button{color:#878888}.quarto-title-banner .code-tools-button:hover{color:#545555}.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:#070707}#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}body{-webkit-font-smoothing:antialiased}.badge.bg-light{color:#373a3c}.progress .progress-bar{font-size:8px;line-height:8px}code{color:#070707}div.sourceCode{background-color:rgba(255,255,255,0);border:2px;border-radius:8px;box-shadow:0 0 0 0 rgba(0,0,0,.06),0 2px 5px 0 rgba(0,0,0,.06),0 10px 10px 0 rgba(0,0,0,.05),0 22px 13px 0 rgba(0,0,0,.03),0 39px 16px 0 rgba(0,0,0,.01),0 61px 17px 0 rgba(0,0,0,0)}pre.sourceCode.r,code.sourceCode.r{color:#070707;background:#fff;background-clip:padding-box;border:solid 2px rgba(0,0,0,0);border-radius:8px}pre.sourceCode.r:before,code.sourceCode.r:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:-1;margin:-2px;border-radius:inherit;background:linear-gradient(to right, #18a603, #0484a9, #0087af)}.chapter-number::before{content:"Chapter "}.chapter-number::after{content:" –"}.quarto-cover-image{max-width:250px;float:right;margin-left:30px;margin-top:-30px;margin-right:10%}div.sidebar-item-container .active,div.sidebar-item-container .show>.nav-link,div.sidebar-item-container .sidebar-link>code{font-weight:800}.sidebar-title{font-weight:800;background:linear-gradient(to right, #18a603, #0484a9, #0087af);-webkit-background-clip:text;-webkit-text-fill-color:rgba(0,0,0,0)}.sidebar-tools-main{font-weight:normal;background:#fff;color:#000;-webkit-background-clip:text;-webkit-text-fill-color:#000}.sidebar-navigation li a{text-decoration:underline}.text-start{text-align:left !important;font-weight:800}#quarto-sidebar{transition:width .15s ease-in;padding:14px 10%;background-color:#fff}.sidebar.sidebar-navigation:not(.rollup){border-right:0px !important}.sidebar-navigation .sidebar-item{font-size:1rem;line-height:2em}.sidebar-menu-container{border:solid #add2dd 1px;border-radius:8px;padding:8px;margin-top:25px}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:4px solid #3792ad;font-weight:800}#toc-title+ul>li>.nav-link{font-weight:800}h1,.h1{font-size:36px;color:#070707;font-weight:700;border-image:linear-gradient(to right, #18a603, #0484a9, #0087af) 1;border-bottom-style:solid;border-bottom-width:4px}h2,.h2{margin-top:3rem;margin-bottom:1rem;font-size:32px;border-bottom:0px}h3,.h3{margin-top:1.5em;font-size:1.2rem}h4,.h4{margin-top:1.5em;font-size:1.1rem}h5,.h5{margin-top:1.5em;font-size:1rem}h1,.h1,h2,.h2,h3,.h3,h4,.h4,h5,.h5{line-height:120%;margin:0 0 1rem;width:fit-content;padding-top:.5rem;color:#070707}p{margin:0 0 1rem;font-size:1rem;color:#070707;line-height:130%;display:block;margin-block-start:1em;margin-block-end:1em;margin-inline-start:0px;margin-inline-end:0px}.quarto-section-identifier{color:#070707;font-weight:normal}ul li::marker{color:#3792ad}.citation a,.footnote-ref{text-decoration:underline}@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}}/*# sourceMappingURL=5752e79b73c3fc43a4dc99ba1d45f305.css.map */ diff --git a/docs/devel/site_libs/bootstrap/bootstrap.min.js b/docs/devel/site_libs/bootstrap/bootstrap.min.js new file mode 100644 index 0000000..cc0a255 --- /dev/null +++ b/docs/devel/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/docs/devel/site_libs/clipboard/clipboard.min.js b/docs/devel/site_libs/clipboard/clipboard.min.js new file mode 100644 index 0000000..1103f81 --- /dev/null +++ b/docs/devel/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=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",u.sheet.cssRules.length),u.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",u.sheet.cssRules.length),u.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',u.sheet.cssRules.length)),u=document.querySelectorAll("[id]"),t=[].map.call(u,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); +// @license-end \ No newline at end of file diff --git a/docs/devel/site_libs/quarto-html/popper.min.js b/docs/devel/site_libs/quarto-html/popper.min.js new file mode 100644 index 0000000..2269d66 --- /dev/null +++ b/docs/devel/site_libs/quarto-html/popper.min.js @@ -0,0 +1,6 @@ +/** + * @popperjs/core v2.11.4 - MIT License + */ + +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(e,t){void 0===t&&(t=!1);var n=e.getBoundingClientRect(),o=1,i=1;if(r(e)&&t){var a=e.offsetHeight,f=e.offsetWidth;f>0&&(o=s(n.width)/f||1),a>0&&(i=s(n.height)/a||1)}return{width:n.width/o,height:n.height/i,top:n.top/i,right:n.right/o,bottom:n.bottom/i,left:n.left/o,x:n.left/o,y:n.top/i}}function c(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function p(e){return e?(e.nodeName||"").toLowerCase():null}function u(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function l(e){return f(u(e)).left+c(e).scrollLeft}function d(e){return t(e).getComputedStyle(e)}function h(e){var t=d(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function m(e,n,o){void 0===o&&(o=!1);var i,a,d=r(n),m=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),v=u(n),g=f(e,m),y={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(d||!d&&!o)&&(("body"!==p(n)||h(v))&&(y=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:c(i)),r(n)?((b=f(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):v&&(b.x=l(v))),{x:g.left+y.scrollLeft-b.x,y:g.top+y.scrollTop-b.y,width:g.width,height:g.height}}function v(e){var t=f(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function g(e){return"html"===p(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||u(e)}function y(e){return["html","body","#document"].indexOf(p(e))>=0?e.ownerDocument.body:r(e)&&h(e)?e:y(g(e))}function b(e,n){var r;void 0===n&&(n=[]);var o=y(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],h(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(b(g(s)))}function x(e){return["table","td","th"].indexOf(p(e))>=0}function w(e){return r(e)&&"fixed"!==d(e).position?e.offsetParent:null}function O(e){for(var n=t(e),i=w(e);i&&x(i)&&"static"===d(i).position;)i=w(i);return i&&("html"===p(i)||"body"===p(i)&&"static"===d(i).position)?n:i||function(e){var t=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&r(e)&&"fixed"===d(e).position)return null;var n=g(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(p(n))<0;){var i=d(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var j="top",E="bottom",D="right",A="left",L="auto",P=[j,E,D,A],M="start",k="end",W="viewport",B="popper",H=P.reduce((function(e,t){return e.concat([t+"-"+M,t+"-"+k])}),[]),T=[].concat(P,[L]).reduce((function(e,t){return e.concat([t,t+"-"+M,t+"-"+k])}),[]),R=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function S(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function q(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function V(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function N(e,r){return r===W?V(function(e){var n=t(e),r=u(e),o=n.visualViewport,i=r.clientWidth,a=r.clientHeight,s=0,f=0;return o&&(i=o.width,a=o.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(s=o.offsetLeft,f=o.offsetTop)),{width:i,height:a,x:s+l(e),y:f}}(e)):n(r)?function(e){var t=f(e);return t.top=t.top+e.clientTop,t.left=t.left+e.clientLeft,t.bottom=t.top+e.clientHeight,t.right=t.left+e.clientWidth,t.width=e.clientWidth,t.height=e.clientHeight,t.x=t.left,t.y=t.top,t}(r):V(function(e){var t,n=u(e),r=c(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+l(e),p=-r.scrollTop;return"rtl"===d(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:p}}(u(e)))}function I(e,t,o){var s="clippingParents"===t?function(e){var t=b(g(e)),o=["absolute","fixed"].indexOf(d(e).position)>=0&&r(e)?O(e):e;return n(o)?t.filter((function(e){return n(e)&&q(e,o)&&"body"!==p(e)})):[]}(e):[].concat(t),f=[].concat(s,[o]),c=f[0],u=f.reduce((function(t,n){var r=N(e,n);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),N(e,c));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function _(e){return e.split("-")[1]}function F(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function U(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?_(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case j:t={x:s,y:n.y-r.height};break;case E:t={x:s,y:n.y+n.height};break;case D:t={x:n.x+n.width,y:f};break;case A:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?F(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case M:t[c]=t[c]-(n[p]/2-r[p]/2);break;case k:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function z(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function X(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function Y(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.boundary,s=void 0===a?"clippingParents":a,c=r.rootBoundary,p=void 0===c?W:c,l=r.elementContext,d=void 0===l?B:l,h=r.altBoundary,m=void 0!==h&&h,v=r.padding,g=void 0===v?0:v,y=z("number"!=typeof g?g:X(g,P)),b=d===B?"reference":B,x=e.rects.popper,w=e.elements[m?b:d],O=I(n(w)?w:w.contextElement||u(e.elements.popper),s,p),A=f(e.elements.reference),L=U({reference:A,element:x,strategy:"absolute",placement:i}),M=V(Object.assign({},x,L)),k=d===B?M:A,H={top:O.top-k.top+y.top,bottom:k.bottom-O.bottom+y.bottom,left:O.left-k.left+y.left,right:k.right-O.right+y.right},T=e.modifiersData.offset;if(d===B&&T){var R=T[i];Object.keys(H).forEach((function(e){var t=[D,E].indexOf(e)>=0?1:-1,n=[j,E].indexOf(e)>=0?"y":"x";H[e]+=R[n]*t}))}return H}var G={placement:"bottom",modifiers:[],strategy:"absolute"};function J(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[A,D].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},ie={left:"right",right:"left",bottom:"top",top:"bottom"};function ae(e){return e.replace(/left|right|bottom|top/g,(function(e){return ie[e]}))}var se={start:"end",end:"start"};function fe(e){return e.replace(/start|end/g,(function(e){return se[e]}))}function ce(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?T:f,p=_(r),u=p?s?H:H.filter((function(e){return _(e)===p})):P,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=Y(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var pe={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,g=C(v),y=f||(g===v||!h?[ae(v)]:function(e){if(C(e)===L)return[];var t=ae(e);return[fe(e),t,fe(t)]}(v)),b=[v].concat(y).reduce((function(e,n){return e.concat(C(n)===L?ce(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,P=!0,k=b[0],W=0;W=0,S=R?"width":"height",q=Y(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),V=R?T?D:A:T?E:j;x[S]>w[S]&&(V=ae(V));var N=ae(V),I=[];if(i&&I.push(q[H]<=0),s&&I.push(q[V]<=0,q[N]<=0),I.every((function(e){return e}))){k=B,P=!1;break}O.set(B,I)}if(P)for(var F=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return k=t,"break"},U=h?3:1;U>0;U--){if("break"===F(U))break}t.placement!==k&&(t.modifiersData[r]._skip=!0,t.placement=k,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ue(e,t,n){return i(e,a(t,n))}var le={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,g=n.tetherOffset,y=void 0===g?0:g,b=Y(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=_(t.placement),L=!w,P=F(x),k="x"===P?"y":"x",W=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,q={x:0,y:0};if(W){if(s){var V,N="y"===P?j:A,I="y"===P?E:D,U="y"===P?"height":"width",z=W[P],X=z+b[N],G=z-b[I],J=m?-H[U]/2:0,K=w===M?B[U]:H[U],Q=w===M?-H[U]:-B[U],Z=t.elements.arrow,$=m&&Z?v(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=ue(0,B[U],$[U]),oe=L?B[U]/2-J-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=L?-B[U]/2+J+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&O(t.elements.arrow),se=ae?"y"===P?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(V=null==S?void 0:S[P])?V:0,ce=z+ie-fe,pe=ue(m?a(X,z+oe-fe-se):X,z,m?i(G,ce):G);W[P]=pe,q[P]=pe-z}if(c){var le,de="x"===P?j:A,he="x"===P?E:D,me=W[k],ve="y"===k?"height":"width",ge=me+b[de],ye=me-b[he],be=-1!==[j,A].indexOf(x),xe=null!=(le=null==S?void 0:S[k])?le:0,we=be?ge:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ye,je=m&&be?function(e,t,n){var r=ue(e,t,n);return r>n?n:r}(we,me,Oe):ue(m?we:ge,me,m?Oe:ye);W[k]=je,q[k]=je-me}t.modifiersData[r]=q}},requiresIfExists:["offset"]};var de={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=F(s),c=[A,D].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return z("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:X(e,P))}(o.padding,n),u=v(i),l="y"===f?j:A,d="y"===f?E:D,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],g=O(i),y=g?"y"===f?g.clientHeight||0:g.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],L=y/2-u[c]/2+b,M=ue(x,L,w),k=f;n.modifiersData[r]=((t={})[k]=M,t.centerOffset=M-L,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&q(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function he(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function me(e){return[j,D,E,A].some((function(t){return e[t]>=0}))}var ve={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=Y(t,{elementContext:"reference"}),s=Y(t,{altBoundary:!0}),f=he(a,r),c=he(s,o,i),p=me(f),u=me(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},ge=K({defaultModifiers:[Z,$,ne,re]}),ye=[Z,$,ne,re,oe,pe,le,de,ve],be=K({defaultModifiers:ye});e.applyStyles=re,e.arrow=de,e.computeStyles=ne,e.createPopper=be,e.createPopperLite=ge,e.defaultModifiers=ye,e.detectOverflow=Y,e.eventListeners=Z,e.flip=pe,e.hide=ve,e.offset=oe,e.popperGenerator=K,e.popperOffsets=$,e.preventOverflow=le,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/docs/devel/site_libs/quarto-html/quarto-syntax-highlighting.css b/docs/devel/site_libs/quarto-html/quarto-syntax-highlighting.css new file mode 100644 index 0000000..775adc4 --- /dev/null +++ b/docs/devel/site_libs/quarto-html/quarto-syntax-highlighting.css @@ -0,0 +1,183 @@ +/* quarto syntax highlight colors */ +:root { + --quarto-hl-al-color: #95da4c; + --quarto-hl-an-color: #50a14f; + --quarto-hl-at-color: #a626a4; + --quarto-hl-bn-color: #986801; + --quarto-hl-bu-color: #a626a4; + --quarto-hl-ch-color: #50a14f; + --quarto-hl-co-color: #a0a1a7; + --quarto-hl-cv-color: #e45649; + --quarto-hl-cn-color: #986801; + --quarto-hl-cf-color: #a626a4; + --quarto-hl-dt-color: #a626a4; + --quarto-hl-dv-color: #986801; + --quarto-hl-do-color: #e45649; + --quarto-hl-er-color: #f44747; + --quarto-hl-ex-color: #4078f2; + --quarto-hl-fl-color: #986801; + --quarto-hl-fu-color: #4078f2; + --quarto-hl-im-color: #50a14f; + --quarto-hl-in-color: #c45b00; + --quarto-hl-kw-color: #a626a4; + --quarto-hl-op-color: #a626a4; + --quarto-hl-pp-color: #a626a4; + --quarto-hl-re-color: #2980b9; + --quarto-hl-sc-color: #0184bc; + --quarto-hl-ss-color: #da4453; + --quarto-hl-st-color: #50a14f; + --quarto-hl-va-color: #e45649; + --quarto-hl-vs-color: #da4453; + --quarto-hl-wa-color: #da4453; +} + +/* other quarto variables */ +:root { + --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +code span.al { + background-color: #4d1f24; + font-weight: bold; + color: #95da4c; +} + +code span.an { + color: #50a14f; +} + +code span.at { + color: #a626a4; +} + +code span.bn { + color: #986801; +} + +code span.bu { + color: #a626a4; +} + +code span.ch { + color: #50a14f; +} + +code span.co { + font-style: italic; + color: #a0a1a7; +} + +code span.cv { + font-style: italic; + color: #e45649; +} + +code span.cn { + color: #986801; +} + +code span.cf { + color: #a626a4; +} + +code span.dt { + color: #a626a4; +} + +code span.dv { + color: #986801; +} + +code span.do { + color: #e45649; +} + +code span.er { + color: #f44747; + text-decoration: underline; +} + +code span.ex { + font-weight: bold; + color: #4078f2; +} + +code span.fl { + color: #986801; +} + +code span.fu { + color: #4078f2; +} + +code span.im { + color: #50a14f; +} + +code span.in { + color: #c45b00; +} + +code span.kw { + color: #a626a4; +} + +pre > code.sourceCode > span { + color: #383a42; +} + +code span { + color: #383a42; +} + +code.sourceCode > span { + color: #383a42; +} + +div.sourceCode, +div.sourceCode pre.sourceCode { + color: #383a42; +} + +code span.op { + color: #a626a4; +} + +code span.pp { + color: #a626a4; +} + +code span.re { + background-color: #153042; + color: #2980b9; +} + +code span.sc { + color: #0184bc; +} + +code span.ss { + color: #da4453; +} + +code span.st { + color: #50a14f; +} + +code span.va { + color: #e45649; +} + +code span.vs { + color: #da4453; +} + +code span.wa { + color: #da4453; +} + +.prevent-inlining { + content: " { + // Find any conflicting margin elements and add margins to the + // top to prevent overlap + const marginChildren = window.document.querySelectorAll( + ".column-margin.column-container > * " + ); + + let lastBottom = 0; + for (const marginChild of marginChildren) { + if (marginChild.offsetParent !== null) { + // clear the top margin so we recompute it + marginChild.style.marginTop = null; + const top = marginChild.getBoundingClientRect().top + window.scrollY; + console.log({ + childtop: marginChild.getBoundingClientRect().top, + scroll: window.scrollY, + top, + lastBottom, + }); + if (top < lastBottom) { + const margin = lastBottom - top; + marginChild.style.marginTop = `${margin}px`; + } + const styles = window.getComputedStyle(marginChild); + const marginTop = parseFloat(styles["marginTop"]); + + console.log({ + top, + height: marginChild.getBoundingClientRect().height, + marginTop, + total: top + marginChild.getBoundingClientRect().height + marginTop, + }); + lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; + } + } +}; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Recompute the position of margin elements anytime the body size changes + if (window.ResizeObserver) { + const resizeObserver = new window.ResizeObserver( + throttle(layoutMarginEls, 50) + ); + resizeObserver.observe(window.document.body); + } + + const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); + const sidebarEl = window.document.getElementById("quarto-sidebar"); + const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); + const marginSidebarEl = window.document.getElementById( + "quarto-margin-sidebar" + ); + // function to determine whether the element has a previous sibling that is active + const prevSiblingIsActiveLink = (el) => { + const sibling = el.previousElementSibling; + if (sibling && sibling.tagName === "A") { + return sibling.classList.contains("active"); + } else { + return false; + } + }; + + // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) + function fireSlideEnter(e) { + const event = window.document.createEvent("Event"); + event.initEvent("slideenter", true, true); + window.document.dispatchEvent(event); + } + const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); + tabs.forEach((tab) => { + tab.addEventListener("shown.bs.tab", fireSlideEnter); + }); + + // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) + document.addEventListener("tabby", fireSlideEnter, false); + + // Track scrolling and mark TOC links as active + // get table of contents and sidebar (bail if we don't have at least one) + const tocLinks = tocEl + ? [...tocEl.querySelectorAll("a[data-scroll-target]")] + : []; + const makeActive = (link) => tocLinks[link].classList.add("active"); + const removeActive = (link) => tocLinks[link].classList.remove("active"); + const removeAllActive = () => + [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); + + // activate the anchor for a section associated with this TOC entry + tocLinks.forEach((link) => { + link.addEventListener("click", () => { + if (link.href.indexOf("#") !== -1) { + const anchor = link.href.split("#")[1]; + const heading = window.document.querySelector( + `[data-anchor-id=${anchor}]` + ); + if (heading) { + // Add the class + heading.classList.add("reveal-anchorjs-link"); + + // function to show the anchor + const handleMouseout = () => { + heading.classList.remove("reveal-anchorjs-link"); + heading.removeEventListener("mouseout", handleMouseout); + }; + + // add a function to clear the anchor when the user mouses out of it + heading.addEventListener("mouseout", handleMouseout); + } + } + }); + }); + + const sections = tocLinks.map((link) => { + const target = link.getAttribute("data-scroll-target"); + if (target.startsWith("#")) { + return window.document.getElementById(decodeURI(`${target.slice(1)}`)); + } else { + return window.document.querySelector(decodeURI(`${target}`)); + } + }); + + const sectionMargin = 200; + let currentActive = 0; + // track whether we've initialized state the first time + let init = false; + + const updateActiveLink = () => { + // The index from bottom to top (e.g. reversed list) + let sectionIndex = -1; + if ( + window.innerHeight + window.pageYOffset >= + window.document.body.offsetHeight + ) { + sectionIndex = 0; + } else { + sectionIndex = [...sections].reverse().findIndex((section) => { + if (section) { + return window.pageYOffset >= section.offsetTop - sectionMargin; + } else { + return false; + } + }); + } + if (sectionIndex > -1) { + const current = sections.length - sectionIndex - 1; + if (current !== currentActive) { + removeAllActive(); + currentActive = current; + makeActive(current); + if (init) { + window.dispatchEvent(sectionChanged); + } + init = true; + } + } + }; + + const inHiddenRegion = (top, bottom, hiddenRegions) => { + for (const region of hiddenRegions) { + if (top <= region.bottom && bottom >= region.top) { + return true; + } + } + return false; + }; + + const categorySelector = "header.quarto-title-block .quarto-category"; + const activateCategories = (href) => { + // Find any categories + // Surround them with a link pointing back to: + // #category=Authoring + try { + const categoryEls = window.document.querySelectorAll(categorySelector); + for (const categoryEl of categoryEls) { + const categoryText = categoryEl.textContent; + if (categoryText) { + const link = `${href}#category=${encodeURIComponent(categoryText)}`; + const linkEl = window.document.createElement("a"); + linkEl.setAttribute("href", link); + for (const child of categoryEl.childNodes) { + linkEl.append(child); + } + categoryEl.appendChild(linkEl); + } + } + } catch { + // Ignore errors + } + }; + function hasTitleCategories() { + return window.document.querySelector(categorySelector) !== null; + } + + function offsetRelativeUrl(url) { + const offset = getMeta("quarto:offset"); + return offset ? offset + url : url; + } + + function offsetAbsoluteUrl(url) { + const offset = getMeta("quarto:offset"); + const baseUrl = new URL(offset, window.location); + + const projRelativeUrl = url.replace(baseUrl, ""); + if (projRelativeUrl.startsWith("/")) { + return projRelativeUrl; + } else { + return "/" + projRelativeUrl; + } + } + + // read a meta tag value + function getMeta(metaName) { + const metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; + } + + async function findAndActivateCategories() { + const currentPagePath = offsetAbsoluteUrl(window.location.href); + const response = await fetch(offsetRelativeUrl("listings.json")); + if (response.status == 200) { + return response.json().then(function (listingPaths) { + const listingHrefs = []; + for (const listingPath of listingPaths) { + const pathWithoutLeadingSlash = listingPath.listing.substring(1); + for (const item of listingPath.items) { + if ( + item === currentPagePath || + item === currentPagePath + "index.html" + ) { + // Resolve this path against the offset to be sure + // we already are using the correct path to the listing + // (this adjusts the listing urls to be rooted against + // whatever root the page is actually running against) + const relative = offsetRelativeUrl(pathWithoutLeadingSlash); + const baseUrl = window.location; + const resolvedPath = new URL(relative, baseUrl); + listingHrefs.push(resolvedPath.pathname); + break; + } + } + } + + // Look up the tree for a nearby linting and use that if we find one + const nearestListing = findNearestParentListing( + offsetAbsoluteUrl(window.location.pathname), + listingHrefs + ); + if (nearestListing) { + activateCategories(nearestListing); + } else { + // See if the referrer is a listing page for this item + const referredRelativePath = offsetAbsoluteUrl(document.referrer); + const referrerListing = listingHrefs.find((listingHref) => { + const isListingReferrer = + listingHref === referredRelativePath || + listingHref === referredRelativePath + "index.html"; + return isListingReferrer; + }); + + if (referrerListing) { + // Try to use the referrer if possible + activateCategories(referrerListing); + } else if (listingHrefs.length > 0) { + // Otherwise, just fall back to the first listing + activateCategories(listingHrefs[0]); + } + } + }); + } + } + if (hasTitleCategories()) { + findAndActivateCategories(); + } + + const findNearestParentListing = (href, listingHrefs) => { + if (!href || !listingHrefs) { + return undefined; + } + // Look up the tree for a nearby linting and use that if we find one + const relativeParts = href.substring(1).split("/"); + while (relativeParts.length > 0) { + const path = relativeParts.join("/"); + for (const listingHref of listingHrefs) { + if (listingHref.startsWith(path)) { + return listingHref; + } + } + relativeParts.pop(); + } + + return undefined; + }; + + const manageSidebarVisiblity = (el, placeholderDescriptor) => { + let isVisible = true; + let elRect; + + return (hiddenRegions) => { + if (el === null) { + return; + } + + // Find the last element of the TOC + const lastChildEl = el.lastElementChild; + + if (lastChildEl) { + // Converts the sidebar to a menu + const convertToMenu = () => { + for (const child of el.children) { + child.style.opacity = 0; + child.style.overflow = "hidden"; + } + + nexttick(() => { + const toggleContainer = window.document.createElement("div"); + toggleContainer.style.width = "100%"; + toggleContainer.classList.add("zindex-over-content"); + toggleContainer.classList.add("quarto-sidebar-toggle"); + toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom + toggleContainer.id = placeholderDescriptor.id; + toggleContainer.style.position = "fixed"; + + const toggleIcon = window.document.createElement("i"); + toggleIcon.classList.add("quarto-sidebar-toggle-icon"); + toggleIcon.classList.add("bi"); + toggleIcon.classList.add("bi-caret-down-fill"); + + const toggleTitle = window.document.createElement("div"); + const titleEl = window.document.body.querySelector( + placeholderDescriptor.titleSelector + ); + if (titleEl) { + toggleTitle.append( + titleEl.textContent || titleEl.innerText, + toggleIcon + ); + } + toggleTitle.classList.add("zindex-over-content"); + toggleTitle.classList.add("quarto-sidebar-toggle-title"); + toggleContainer.append(toggleTitle); + + const toggleContents = window.document.createElement("div"); + toggleContents.classList = el.classList; + toggleContents.classList.add("zindex-over-content"); + toggleContents.classList.add("quarto-sidebar-toggle-contents"); + for (const child of el.children) { + if (child.id === "toc-title") { + continue; + } + + const clone = child.cloneNode(true); + clone.style.opacity = 1; + clone.style.display = null; + toggleContents.append(clone); + } + toggleContents.style.height = "0px"; + const positionToggle = () => { + // position the element (top left of parent, same width as parent) + if (!elRect) { + elRect = el.getBoundingClientRect(); + } + toggleContainer.style.left = `${elRect.left}px`; + toggleContainer.style.top = `${elRect.top}px`; + toggleContainer.style.width = `${elRect.width}px`; + }; + positionToggle(); + + toggleContainer.append(toggleContents); + el.parentElement.prepend(toggleContainer); + + // Process clicks + let tocShowing = false; + // Allow the caller to control whether this is dismissed + // when it is clicked (e.g. sidebar navigation supports + // opening and closing the nav tree, so don't dismiss on click) + const clickEl = placeholderDescriptor.dismissOnClick + ? toggleContainer + : toggleTitle; + + const closeToggle = () => { + if (tocShowing) { + toggleContainer.classList.remove("expanded"); + toggleContents.style.height = "0px"; + tocShowing = false; + } + }; + + // Get rid of any expanded toggle if the user scrolls + window.document.addEventListener( + "scroll", + throttle(() => { + closeToggle(); + }, 50) + ); + + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + positionToggle(); + }, 50) + ); + + window.addEventListener("quarto-hrChanged", () => { + elRect = undefined; + }); + + // Process the click + clickEl.onclick = () => { + if (!tocShowing) { + toggleContainer.classList.add("expanded"); + toggleContents.style.height = null; + tocShowing = true; + } else { + closeToggle(); + } + }; + }); + }; + + // Converts a sidebar from a menu back to a sidebar + const convertToSidebar = () => { + for (const child of el.children) { + child.style.opacity = 1; + child.style.overflow = null; + } + + const placeholderEl = window.document.getElementById( + placeholderDescriptor.id + ); + if (placeholderEl) { + placeholderEl.remove(); + } + + el.classList.remove("rollup"); + }; + + if (isReaderMode()) { + convertToMenu(); + isVisible = false; + } else { + // Find the top and bottom o the element that is being managed + const elTop = el.offsetTop; + const elBottom = + elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; + + if (!isVisible) { + // If the element is current not visible reveal if there are + // no conflicts with overlay regions + if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToSidebar(); + isVisible = true; + } + } else { + // If the element is visible, hide it if it conflicts with overlay regions + // and insert a placeholder toggle (or if we're in reader mode) + if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToMenu(); + isVisible = false; + } + } + } + } + }; + }; + + const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); + for (const tabEl of tabEls) { + const id = tabEl.getAttribute("data-bs-target"); + if (id) { + const columnEl = document.querySelector( + `${id} .column-margin, .tabset-margin-content` + ); + if (columnEl) + tabEl.addEventListener("shown.bs.tab", function (event) { + const el = event.srcElement; + if (el) { + const visibleCls = `${el.id}-margin-content`; + // walk up until we find a parent tabset + let panelTabsetEl = el.parentElement; + while (panelTabsetEl) { + if (panelTabsetEl.classList.contains("panel-tabset")) { + break; + } + panelTabsetEl = panelTabsetEl.parentElement; + } + + if (panelTabsetEl) { + const prevSib = panelTabsetEl.previousElementSibling; + if ( + prevSib && + prevSib.classList.contains("tabset-margin-container") + ) { + const childNodes = prevSib.querySelectorAll( + ".tabset-margin-content" + ); + for (const childEl of childNodes) { + if (childEl.classList.contains(visibleCls)) { + childEl.classList.remove("collapse"); + } else { + childEl.classList.add("collapse"); + } + } + } + } + } + + layoutMarginEls(); + }); + } + } + + // Manage the visibility of the toc and the sidebar + const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { + id: "quarto-toc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { + id: "quarto-sidebarnav-toggle", + titleSelector: ".title", + dismissOnClick: false, + }); + let tocLeftScrollVisibility; + if (leftTocEl) { + tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { + id: "quarto-lefttoc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + } + + // Find the first element that uses formatting in special columns + const conflictingEls = window.document.body.querySelectorAll( + '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' + ); + + // Filter all the possibly conflicting elements into ones + // the do conflict on the left or ride side + const arrConflictingEls = Array.from(conflictingEls); + const leftSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return false; + } + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + className.startsWith("column-") && + !className.endsWith("right") && + !className.endsWith("container") && + className !== "column-margin" + ); + }); + }); + const rightSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return true; + } + + const hasMarginCaption = Array.from(el.classList).find((className) => { + return className == "margin-caption"; + }); + if (hasMarginCaption) { + return true; + } + + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + !className.endsWith("container") && + className.startsWith("column-") && + !className.endsWith("left") + ); + }); + }); + + const kOverlapPaddingSize = 10; + function toRegions(els) { + return els.map((el) => { + const boundRect = el.getBoundingClientRect(); + const top = + boundRect.top + + document.documentElement.scrollTop - + kOverlapPaddingSize; + return { + top, + bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, + }; + }); + } + + let hasObserved = false; + const visibleItemObserver = (els) => { + let visibleElements = [...els]; + const intersectionObserver = new IntersectionObserver( + (entries, _observer) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + if (visibleElements.indexOf(entry.target) === -1) { + visibleElements.push(entry.target); + } + } else { + visibleElements = visibleElements.filter((visibleEntry) => { + return visibleEntry !== entry; + }); + } + }); + + if (!hasObserved) { + hideOverlappedSidebars(); + } + hasObserved = true; + }, + {} + ); + els.forEach((el) => { + intersectionObserver.observe(el); + }); + + return { + getVisibleEntries: () => { + return visibleElements; + }, + }; + }; + + const rightElementObserver = visibleItemObserver(rightSideConflictEls); + const leftElementObserver = visibleItemObserver(leftSideConflictEls); + + const hideOverlappedSidebars = () => { + marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); + sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); + if (tocLeftScrollVisibility) { + tocLeftScrollVisibility( + toRegions(leftElementObserver.getVisibleEntries()) + ); + } + }; + + window.quartoToggleReader = () => { + // Applies a slow class (or removes it) + // to update the transition speed + const slowTransition = (slow) => { + const manageTransition = (id, slow) => { + const el = document.getElementById(id); + if (el) { + if (slow) { + el.classList.add("slow"); + } else { + el.classList.remove("slow"); + } + } + }; + + manageTransition("TOC", slow); + manageTransition("quarto-sidebar", slow); + }; + const readerMode = !isReaderMode(); + setReaderModeValue(readerMode); + + // If we're entering reader mode, slow the transition + if (readerMode) { + slowTransition(readerMode); + } + highlightReaderToggle(readerMode); + hideOverlappedSidebars(); + + // If we're exiting reader mode, restore the non-slow transition + if (!readerMode) { + slowTransition(!readerMode); + } + }; + + const highlightReaderToggle = (readerMode) => { + const els = document.querySelectorAll(".quarto-reader-toggle"); + if (els) { + els.forEach((el) => { + if (readerMode) { + el.classList.add("reader"); + } else { + el.classList.remove("reader"); + } + }); + } + }; + + const setReaderModeValue = (val) => { + if (window.location.protocol !== "file:") { + window.localStorage.setItem("quarto-reader-mode", val); + } else { + localReaderMode = val; + } + }; + + const isReaderMode = () => { + if (window.location.protocol !== "file:") { + return window.localStorage.getItem("quarto-reader-mode") === "true"; + } else { + return localReaderMode; + } + }; + let localReaderMode = null; + + const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); + const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; + + // Walk the TOC and collapse/expand nodes + // Nodes are expanded if: + // - they are top level + // - they have children that are 'active' links + // - they are directly below an link that is 'active' + const walk = (el, depth) => { + // Tick depth when we enter a UL + if (el.tagName === "UL") { + depth = depth + 1; + } + + // It this is active link + let isActiveNode = false; + if (el.tagName === "A" && el.classList.contains("active")) { + isActiveNode = true; + } + + // See if there is an active child to this element + let hasActiveChild = false; + for (child of el.children) { + hasActiveChild = walk(child, depth) || hasActiveChild; + } + + // Process the collapse state if this is an UL + if (el.tagName === "UL") { + if (tocOpenDepth === -1 && depth > 1) { + el.classList.add("collapse"); + } else if ( + depth <= tocOpenDepth || + hasActiveChild || + prevSiblingIsActiveLink(el) + ) { + el.classList.remove("collapse"); + } else { + el.classList.add("collapse"); + } + + // untick depth when we leave a UL + depth = depth - 1; + } + return hasActiveChild || isActiveNode; + }; + + // walk the TOC and expand / collapse any items that should be shown + + if (tocEl) { + walk(tocEl, 0); + updateActiveLink(); + } + + // Throttle the scroll event and walk peridiocally + window.document.addEventListener( + "scroll", + throttle(() => { + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 5) + ); + window.addEventListener( + "resize", + throttle(() => { + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 10) + ); + hideOverlappedSidebars(); + highlightReaderToggle(isReaderMode()); +}); + +// grouped tabsets +window.addEventListener("pageshow", (_event) => { + function getTabSettings() { + const data = localStorage.getItem("quarto-persistent-tabsets-data"); + if (!data) { + localStorage.setItem("quarto-persistent-tabsets-data", "{}"); + return {}; + } + if (data) { + return JSON.parse(data); + } + } + + function setTabSettings(data) { + localStorage.setItem( + "quarto-persistent-tabsets-data", + JSON.stringify(data) + ); + } + + function setTabState(groupName, groupValue) { + const data = getTabSettings(); + data[groupName] = groupValue; + setTabSettings(data); + } + + function toggleTab(tab, active) { + const tabPanelId = tab.getAttribute("aria-controls"); + const tabPanel = document.getElementById(tabPanelId); + if (active) { + tab.classList.add("active"); + tabPanel.classList.add("active"); + } else { + tab.classList.remove("active"); + tabPanel.classList.remove("active"); + } + } + + function toggleAll(selectedGroup, selectorsToSync) { + for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { + const active = selectedGroup === thisGroup; + for (const tab of tabs) { + toggleTab(tab, active); + } + } + } + + function findSelectorsToSyncByLanguage() { + const result = {}; + const tabs = Array.from( + document.querySelectorAll(`div[data-group] a[id^='tabset-']`) + ); + for (const item of tabs) { + const div = item.parentElement.parentElement.parentElement; + const group = div.getAttribute("data-group"); + if (!result[group]) { + result[group] = {}; + } + const selectorsToSync = result[group]; + const value = item.innerHTML; + if (!selectorsToSync[value]) { + selectorsToSync[value] = []; + } + selectorsToSync[value].push(item); + } + return result; + } + + function setupSelectorSync() { + const selectorsToSync = findSelectorsToSyncByLanguage(); + Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { + Object.entries(tabSetsByValue).forEach(([value, items]) => { + items.forEach((item) => { + item.addEventListener("click", (_event) => { + setTabState(group, value); + toggleAll(value, selectorsToSync[group]); + }); + }); + }); + }); + return selectorsToSync; + } + + const selectorsToSync = setupSelectorSync(); + for (const [group, selectedName] of Object.entries(getTabSettings())) { + const selectors = selectorsToSync[group]; + // it's possible that stale state gives us empty selections, so we explicitly check here. + if (selectors) { + toggleAll(selectedName, selectors); + } + } +}); + +function throttle(func, wait) { + let waiting = false; + return function () { + if (!waiting) { + func.apply(this, arguments); + waiting = true; + setTimeout(function () { + waiting = false; + }, wait); + } + }; +} + +function nexttick(func) { + return setTimeout(func, 0); +} diff --git a/docs/devel/site_libs/quarto-html/tippy.css b/docs/devel/site_libs/quarto-html/tippy.css new file mode 100644 index 0000000..e6ae635 --- /dev/null +++ b/docs/devel/site_libs/quarto-html/tippy.css @@ -0,0 +1 @@ +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/docs/devel/site_libs/quarto-html/tippy.umd.min.js b/docs/devel/site_libs/quarto-html/tippy.umd.min.js new file mode 100644 index 0000000..ca292be --- /dev/null +++ b/docs/devel/site_libs/quarto-html/tippy.umd.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); + diff --git a/docs/devel/site_libs/quarto-nav/headroom.min.js b/docs/devel/site_libs/quarto-nav/headroom.min.js new file mode 100644 index 0000000..b08f1df --- /dev/null +++ b/docs/devel/site_libs/quarto-nav/headroom.min.js @@ -0,0 +1,7 @@ +/*! + * headroom.js v0.12.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t){return t===Object(t)?t:{down:t,up:t}}function s(t,n){n=n||{},Object.assign(this,s.options,n),this.classes=Object.assign({},s.options.classes,n.classes),this.elem=t,this.tolerance=o(this.tolerance),this.offset=o(this.offset),this.initialised=!1,this.frozen=!1}return s.prototype={constructor:s,init:function(){return s.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},s.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},s.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),s}); diff --git a/docs/devel/site_libs/quarto-nav/quarto-nav.js b/docs/devel/site_libs/quarto-nav/quarto-nav.js new file mode 100644 index 0000000..3b21201 --- /dev/null +++ b/docs/devel/site_libs/quarto-nav/quarto-nav.js @@ -0,0 +1,277 @@ +const headroomChanged = new CustomEvent("quarto-hrChanged", { + detail: {}, + bubbles: true, + cancelable: false, + composed: false, +}); + +window.document.addEventListener("DOMContentLoaded", function () { + let init = false; + + // Manage the back to top button, if one is present. + let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop; + const scrollDownBuffer = 5; + const scrollUpBuffer = 35; + const btn = document.getElementById("quarto-back-to-top"); + const hideBackToTop = () => { + btn.style.display = "none"; + }; + const showBackToTop = () => { + btn.style.display = "inline-block"; + }; + if (btn) { + window.document.addEventListener( + "scroll", + function () { + const currentScrollTop = + window.pageYOffset || document.documentElement.scrollTop; + + // Shows and hides the button 'intelligently' as the user scrolls + if (currentScrollTop - scrollDownBuffer > lastScrollTop) { + hideBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } else if (currentScrollTop < lastScrollTop - scrollUpBuffer) { + showBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } + + // Show the button at the bottom, hides it at the top + if (currentScrollTop <= 0) { + hideBackToTop(); + } else if ( + window.innerHeight + currentScrollTop >= + document.body.offsetHeight + ) { + showBackToTop(); + } + }, + false + ); + } + + function throttle(func, wait) { + var timeout; + return function () { + const context = this; + const args = arguments; + const later = function () { + clearTimeout(timeout); + timeout = null; + func.apply(context, args); + }; + + if (!timeout) { + timeout = setTimeout(later, wait); + } + }; + } + + function headerOffset() { + // Set an offset if there is are fixed top navbar + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl) { + return headerEl.clientHeight; + } else { + return 0; + } + } + + function footerOffset() { + const footerEl = window.document.querySelector("footer.footer"); + if (footerEl) { + return footerEl.clientHeight; + } else { + return 0; + } + } + + function updateDocumentOffsetWithoutAnimation() { + updateDocumentOffset(false); + } + + function updateDocumentOffset(animated) { + // set body offset + const topOffset = headerOffset(); + const bodyOffset = topOffset + footerOffset(); + const bodyEl = window.document.body; + bodyEl.setAttribute("data-bs-offset", topOffset); + bodyEl.style.paddingTop = topOffset + "px"; + + // deal with sidebar offsets + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + if (!animated) { + sidebar.classList.add("notransition"); + // Remove the no transition class after the animation has time to complete + setTimeout(function () { + sidebar.classList.remove("notransition"); + }, 201); + } + + if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) { + sidebar.style.top = "0"; + sidebar.style.maxHeight = "100vh"; + } else { + sidebar.style.top = topOffset + "px"; + sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)"; + } + }); + + // allow space for footer + const mainContainer = window.document.querySelector(".quarto-container"); + if (mainContainer) { + mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)"; + } + + // link offset + let linkStyle = window.document.querySelector("#quarto-target-style"); + if (!linkStyle) { + linkStyle = window.document.createElement("style"); + linkStyle.setAttribute("id", "quarto-target-style"); + window.document.head.appendChild(linkStyle); + } + while (linkStyle.firstChild) { + linkStyle.removeChild(linkStyle.firstChild); + } + if (topOffset > 0) { + linkStyle.appendChild( + window.document.createTextNode(` + section:target::before { + content: ""; + display: block; + height: ${topOffset}px; + margin: -${topOffset}px 0 0; + }`) + ); + } + if (init) { + window.dispatchEvent(headroomChanged); + } + init = true; + } + + // initialize headroom + var header = window.document.querySelector("#quarto-header"); + if (header && window.Headroom) { + const headroom = new window.Headroom(header, { + tolerance: 5, + onPin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.remove("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + onUnpin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.add("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + }); + headroom.init(); + + let frozen = false; + window.quartoToggleHeadroom = function () { + if (frozen) { + headroom.unfreeze(); + frozen = false; + } else { + headroom.freeze(); + frozen = true; + } + }; + } + + window.addEventListener( + "hashchange", + function (e) { + if ( + getComputedStyle(document.documentElement).scrollBehavior !== "smooth" + ) { + window.scrollTo(0, window.pageYOffset - headerOffset()); + } + }, + false + ); + + // Observe size changed for the header + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl && window.ResizeObserver) { + const observer = new window.ResizeObserver( + updateDocumentOffsetWithoutAnimation + ); + observer.observe(headerEl, { + attributes: true, + childList: true, + characterData: true, + }); + } else { + window.addEventListener( + "resize", + throttle(updateDocumentOffsetWithoutAnimation, 50) + ); + } + setTimeout(updateDocumentOffsetWithoutAnimation, 250); + + // fixup index.html links if we aren't on the filesystem + if (window.location.protocol !== "file:") { + const links = window.document.querySelectorAll("a"); + for (let i = 0; i < links.length; i++) { + if (links[i].href) { + links[i].href = links[i].href.replace(/\/index\.html/, "/"); + } + } + + // Fixup any sharing links that require urls + // Append url to any sharing urls + const sharingLinks = window.document.querySelectorAll( + "a.sidebar-tools-main-item" + ); + for (let i = 0; i < sharingLinks.length; i++) { + const sharingLink = sharingLinks[i]; + const href = sharingLink.getAttribute("href"); + if (href) { + sharingLink.setAttribute( + "href", + href.replace("|url|", window.location.href) + ); + } + } + + // Scroll the active navigation item into view, if necessary + const navSidebar = window.document.querySelector("nav#quarto-sidebar"); + if (navSidebar) { + // Find the active item + const activeItem = navSidebar.querySelector("li.sidebar-item a.active"); + if (activeItem) { + // Wait for the scroll height and height to resolve by observing size changes on the + // nav element that is scrollable + const resizeObserver = new ResizeObserver((_entries) => { + // The bottom of the element + const elBottom = activeItem.offsetTop; + const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight; + + // The element height and scroll height are the same, then we are still loading + if (viewBottom !== navSidebar.scrollHeight) { + // Determine if the item isn't visible and scroll to it + if (elBottom >= viewBottom) { + navSidebar.scrollTop = elBottom; + } + + // stop observing now since we've completed the scroll + resizeObserver.unobserve(navSidebar); + } + }); + resizeObserver.observe(navSidebar); + } + } + } +}); diff --git a/docs/devel/site_libs/quarto-search/autocomplete.umd.js b/docs/devel/site_libs/quarto-search/autocomplete.umd.js new file mode 100644 index 0000000..619c57c --- /dev/null +++ b/docs/devel/site_libs/quarto-search/autocomplete.umd.js @@ -0,0 +1,3 @@ +/*! @algolia/autocomplete-js 1.7.3 | MIT License | Β© Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["@algolia/autocomplete-js"]={})}(this,(function(e){"use strict";function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function n(e){for(var n=1;n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function a(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,o,i=[],u=!0,a=!1;try{for(n=n.call(e);!(u=(r=n.next()).done)&&(i.push(r.value),!t||i.length!==t);u=!0);}catch(e){a=!0,o=e}finally{try{u||null==n.return||n.return()}finally{if(a)throw o}}return i}(e,t)||l(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function c(e){return function(e){if(Array.isArray(e))return s(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||l(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(e,t){if(e){if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?s(e,t):void 0}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=n?null===r?null:0:o}function S(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function E(e,t){var n=[];return Promise.resolve(e(t)).then((function(e){return Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,n.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));n.push(e.sourceId);var t=function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var ae,ce,le,se=null,pe=(ae=-1,ce=-1,le=void 0,function(e){var t=++ae;return Promise.resolve(e).then((function(e){return le&&t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var ye=["props","refresh","store"],be=["inputElement","formElement","panelElement"],Oe=["inputElement"],_e=["inputElement","maxLength"],Pe=["item","source"];function je(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function we(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function Ee(e){var t=e.props,n=e.refresh,r=e.store,o=Ie(e,ye);return{getEnvironmentProps:function(e){var n=e.inputElement,o=e.formElement,i=e.panelElement;function u(e){!r.getState().isOpen&&r.pendingRequests.isEmpty()||e.target===n||!1===[o,i].some((function(t){return n=t,r=e.target,n===r||n.contains(r);var n,r}))&&(r.dispatch("blur",null),t.debug||r.pendingRequests.cancelAll())}return we({onTouchStart:u,onMouseDown:u,onTouchMove:function(e){!1!==r.getState().isOpen&&n===t.environment.document.activeElement&&e.target!==n&&n.blur()}},Ie(e,be))},getRootProps:function(e){return we({role:"combobox","aria-expanded":r.getState().isOpen,"aria-haspopup":"listbox","aria-owns":r.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label")},e)},getFormProps:function(e){return e.inputElement,we({action:"",noValidate:!0,role:"search",onSubmit:function(i){var u;i.preventDefault(),t.onSubmit(we({event:i,refresh:n,state:r.getState()},o)),r.dispatch("submit",null),null===(u=e.inputElement)||void 0===u||u.blur()},onReset:function(i){var u;i.preventDefault(),t.onReset(we({event:i,refresh:n,state:r.getState()},o)),r.dispatch("reset",null),null===(u=e.inputElement)||void 0===u||u.focus()}},Ie(e,Oe))},getLabelProps:function(e){return we({htmlFor:"".concat(t.id,"-input"),id:"".concat(t.id,"-label")},e)},getInputProps:function(e){var i;function u(e){(t.openOnFocus||Boolean(r.getState().query))&&fe(we({event:e,props:t,query:r.getState().completion||r.getState().query,refresh:n,store:r},o)),r.dispatch("focus",null)}var a=e||{};a.inputElement;var c=a.maxLength,l=void 0===c?512:c,s=Ie(a,_e),p=A(r.getState()),f=function(e){return Boolean(e&&e.match(C))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),d=null!=p&&p.itemUrl&&!f?"go":"search";return we({"aria-autocomplete":"both","aria-activedescendant":r.getState().isOpen&&null!==r.getState().activeItemId?"".concat(t.id,"-item-").concat(r.getState().activeItemId):void 0,"aria-controls":r.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label"),value:r.getState().completion||r.getState().query,id:"".concat(t.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:d,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:l,type:"search",onChange:function(e){fe(we({event:e,props:t,query:e.currentTarget.value.slice(0,l),refresh:n,store:r},o))},onKeyDown:function(e){!function(e){var t=e.event,n=e.props,r=e.refresh,o=e.store,i=ge(e,de);if("ArrowUp"===t.key||"ArrowDown"===t.key){var u=function(){var e=n.environment.document.getElementById("".concat(n.id,"-item-").concat(o.getState().activeItemId));e&&(e.scrollIntoViewIfNeeded?e.scrollIntoViewIfNeeded(!1):e.scrollIntoView(!1))},a=function(){var e=A(o.getState());if(null!==o.getState().activeItemId&&e){var n=e.item,u=e.itemInputValue,a=e.itemUrl,c=e.source;c.onActive(ve({event:t,item:n,itemInputValue:u,itemUrl:a,refresh:r,source:c,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(n.openOnFocus||Boolean(o.getState().query))?fe(ve({event:t,props:n,query:o.getState().query,refresh:r,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:n.defaultActiveItemId}),a(),setTimeout(u,0)})):(o.dispatch(t.key,{}),a(),u())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(n.debug||o.pendingRequests.cancelAll());t.preventDefault();var c=A(o.getState()),l=c.item,s=c.itemInputValue,p=c.itemUrl,f=c.source;if(t.metaKey||t.ctrlKey)void 0!==p&&(f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),n.navigator.navigateNewTab({itemUrl:p,item:l,state:o.getState()}));else if(t.shiftKey)void 0!==p&&(f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),n.navigator.navigateNewWindow({itemUrl:p,item:l,state:o.getState()}));else if(t.altKey);else{if(void 0!==p)return f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),void n.navigator.navigate({itemUrl:p,item:l,state:o.getState()});fe(ve({event:t,nextState:{isOpen:!1},props:n,query:s,refresh:r,store:o},i)).then((function(){f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i))}))}}}(we({event:e,props:t,refresh:n,store:r},o))},onFocus:u,onBlur:y,onClick:function(n){e.inputElement!==t.environment.document.activeElement||r.getState().isOpen||u(n)}},s)},getPanelProps:function(e){return we({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){r.dispatch("mouseleave",null)}},e)},getListProps:function(e){return we({role:"listbox","aria-labelledby":"".concat(t.id,"-label"),id:"".concat(t.id,"-list")},e)},getItemProps:function(e){var i=e.item,u=e.source,a=Ie(e,Pe);return we({id:"".concat(t.id,"-item-").concat(i.__autocomplete_id),role:"option","aria-selected":r.getState().activeItemId===i.__autocomplete_id,onMouseMove:function(e){if(i.__autocomplete_id!==r.getState().activeItemId){r.dispatch("mousemove",i.__autocomplete_id);var t=A(r.getState());if(null!==r.getState().activeItemId&&t){var u=t.item,a=t.itemInputValue,c=t.itemUrl,l=t.source;l.onActive(we({event:e,item:u,itemInputValue:a,itemUrl:c,refresh:n,source:l,state:r.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var a=u.getItemInputValue({item:i,state:r.getState()}),c=u.getItemUrl({item:i,state:r.getState()});(c?Promise.resolve():fe(we({event:e,nextState:{isOpen:!1},props:t,query:a,refresh:n,store:r},o))).then((function(){u.onSelect(we({event:e,item:i,itemInputValue:a,itemUrl:c,refresh:n,source:u,state:r.getState()},o))}))}},a)}}}function Ae(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ce(e){for(var t=1;t0},reshape:function(e){return e.sources}},e),{},{id:null!==(n=e.id)&&void 0!==n?n:v(),plugins:o,initialState:H({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var n;null===(n=e.onStateChange)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onStateChange)||void 0===n?void 0:n.call(e,t)}))},onSubmit:function(t){var n;null===(n=e.onSubmit)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onSubmit)||void 0===n?void 0:n.call(e,t)}))},onReset:function(t){var n;null===(n=e.onReset)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onReset)||void 0===n?void 0:n.call(e,t)}))},getSources:function(n){return Promise.all([].concat(F(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return E(e,n)}))).then((function(e){return d(e)})).then((function(e){return e.map((function(e){return H(H({},e),{},{onSelect:function(n){e.onSelect(n),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,n)}))},onActive:function(n){e.onActive(n),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,n)}))}})}))}))},navigator:H({navigate:function(e){var t=e.itemUrl;r.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,n=r.open(t,"_blank","noopener");null==n||n.focus()},navigateNewWindow:function(e){var t=e.itemUrl;r.open(t,"_blank","noopener")}},e.navigator)})}(e,t),r=R(Te,n,(function(e){var t=e.prevState,r=e.state;n.onStateChange(Be({prevState:t,state:r,refresh:u},o))})),o=function(e){var t=e.store;return{setActiveItemId:function(e){t.dispatch("setActiveItemId",e)},setQuery:function(e){t.dispatch("setQuery",e)},setCollections:function(e){var n=0,r=e.map((function(e){return L(L({},e),{},{items:d(e.items).map((function(e){return L(L({},e),{},{__autocomplete_id:n++})}))})}));t.dispatch("setCollections",r)},setIsOpen:function(e){t.dispatch("setIsOpen",e)},setStatus:function(e){t.dispatch("setStatus",e)},setContext:function(e){t.dispatch("setContext",e)}}}({store:r}),i=Ee(Be({props:n,refresh:u,store:r},o));function u(){return fe(Be({event:new Event("input"),nextState:{isOpen:r.getState().isOpen},props:n,query:r.getState().query,refresh:u,store:r},o))}return n.plugins.forEach((function(e){var n;return null===(n=e.subscribe)||void 0===n?void 0:n.call(e,Be(Be({},o),{},{refresh:u,onSelect:function(e){t.push({onSelect:e})},onActive:function(e){t.push({onActive:e})}}))})),function(e){var t,n,r=e.metadata,o=e.environment;if(null===(t=o.navigator)||void 0===t||null===(n=t.userAgent)||void 0===n?void 0:n.includes("Algolia Crawler")){var i=o.document.createElement("meta"),u=o.document.querySelector("head");i.name="algolia:metadata",setTimeout((function(){i.content=JSON.stringify(r),u.appendChild(i)}),0)}}({metadata:ke({plugins:n.plugins,options:e}),environment:n.environment}),Be(Be({refresh:u},i),o)}var Ue=function(e,t,n,r){var o;t[0]=0;for(var i=1;i=5&&((o||!e&&5===r)&&(u.push(r,0,o,n),r=6),e&&(u.push(r,e,0,n),r=6)),o=""},c=0;c"===t?(r=1,o=""):o=t+o[0]:i?t===i?i="":o+=t:'"'===t||"'"===t?i=t:">"===t?(a(),r=1):r&&("="===t?(r=5,n=o,o=""):"/"===t&&(r<5||">"===e[c][l+1])?(a(),3===r&&(u=u[0]),r=u,(u=u[0]).push(2,0,r),r=0):" "===t||"\t"===t||"\n"===t||"\r"===t?(a(),r=2):o+=t),3===r&&"!--"===o&&(r=4,u=u[0])}return a(),u}(e)),t),arguments,[])).length>1?t:t[0]}var We=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-ClearIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","18"),n.setAttribute("height","18"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M5.293 6.707l5.293 5.293-5.293 5.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5.293-5.293 5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-5.293-5.293 5.293-5.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"),n.appendChild(r),n};function Qe(e,t){if("string"==typeof t){var n=e.document.querySelector(t);return"The element ".concat(JSON.stringify(t)," is not in the document."),n}return t}function $e(){for(var e=arguments.length,t=new Array(e),n=0;n2&&(u.children=arguments.length>3?lt.call(arguments,2):n),"function"==typeof e&&null!=e.defaultProps)for(i in e.defaultProps)void 0===u[i]&&(u[i]=e.defaultProps[i]);return _t(e,u,r,o,null)}function _t(e,t,n,r,o){var i={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==o?++pt:o};return null==o&&null!=st.vnode&&st.vnode(i),i}function Pt(e){return e.children}function jt(e,t){this.props=e,this.context=t}function wt(e,t){if(null==t)return e.__?wt(e.__,e.__.__k.indexOf(e)+1):null;for(var n;t0?_t(d.type,d.props,d.key,null,d.__v):d)){if(d.__=n,d.__b=n.__b+1,null===(f=g[s])||f&&d.key==f.key&&d.type===f.type)g[s]=void 0;else for(p=0;p0&&void 0!==arguments[0]?arguments[0]:[];return{get:function(){return e},add:function(t){var n=e[e.length-1];(null==n?void 0:n.isHighlighted)===t.isHighlighted?e[e.length-1]={value:n.value+t.value,isHighlighted:n.isHighlighted}:e.push(t)}}}(n?[{value:n,isHighlighted:!1}]:[]);return t.forEach((function(e){var t=e.split(Ht);r.add({value:t[0],isHighlighted:!0}),""!==t[1]&&r.add({value:t[1],isHighlighted:!1})})),r.get()}function Wt(e){return function(e){if(Array.isArray(e))return Qt(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Qt(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Qt(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Qt(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n",""":'"',"'":"'"},Gt=new RegExp(/\w/i),Kt=/&(amp|quot|lt|gt|#39);/g,Jt=RegExp(Kt.source);function Yt(e,t){var n,r,o,i=e[t],u=(null===(n=e[t+1])||void 0===n?void 0:n.isHighlighted)||!0,a=(null===(r=e[t-1])||void 0===r?void 0:r.isHighlighted)||!0;return Gt.test((o=i.value)&&Jt.test(o)?o.replace(Kt,(function(e){return zt[e]})):o)||a!==u?i.isHighlighted:a}function Xt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Zt(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function mn(e){return function(e){if(Array.isArray(e))return vn(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return vn(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return vn(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function vn(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;if(!O.value.core.openOnFocus&&!t.query)return n;var r=Boolean(h.current||O.value.renderer.renderNoResults);return!n&&r||n},__autocomplete_metadata:{userAgents:Sn,options:e}}))})),j=p(n({collections:[],completion:null,context:{},isOpen:!1,query:"",activeItemId:null,status:"idle"},O.value.core.initialState)),w={getEnvironmentProps:O.value.renderer.getEnvironmentProps,getFormProps:O.value.renderer.getFormProps,getInputProps:O.value.renderer.getInputProps,getItemProps:O.value.renderer.getItemProps,getLabelProps:O.value.renderer.getLabelProps,getListProps:O.value.renderer.getListProps,getPanelProps:O.value.renderer.getPanelProps,getRootProps:O.value.renderer.getRootProps},S={setActiveItemId:P.value.setActiveItemId,setQuery:P.value.setQuery,setCollections:P.value.setCollections,setIsOpen:P.value.setIsOpen,setStatus:P.value.setStatus,setContext:P.value.setContext,refresh:P.value.refresh},I=d((function(){return Ve.bind(O.value.renderer.renderer.createElement)})),E=d((function(){return ct({autocomplete:P.value,autocompleteScopeApi:S,classNames:O.value.renderer.classNames,environment:O.value.core.environment,isDetached:_.value,placeholder:O.value.core.placeholder,propGetters:w,setIsModalOpen:k,state:j.current,translations:O.value.renderer.translations})}));function A(){tt(E.value.panel,{style:_.value?{}:wn({panelPlacement:O.value.renderer.panelPlacement,container:E.value.root,form:E.value.form,environment:O.value.core.environment})})}function C(e){j.current=e;var t={autocomplete:P.value,autocompleteScopeApi:S,classNames:O.value.renderer.classNames,components:O.value.renderer.components,container:O.value.renderer.container,html:I.value,dom:E.value,panelContainer:_.value?E.value.detachedContainer:O.value.renderer.panelContainer,propGetters:w,state:j.current,renderer:O.value.renderer.renderer},r=!g(e)&&!h.current&&O.value.renderer.renderNoResults||O.value.renderer.render;!function(e){var t=e.autocomplete,r=e.autocompleteScopeApi,o=e.dom,i=e.propGetters,u=e.state;nt(o.root,i.getRootProps(n({state:u,props:t.getRootProps({})},r))),nt(o.input,i.getInputProps(n({state:u,props:t.getInputProps({inputElement:o.input}),inputElement:o.input},r))),tt(o.label,{hidden:"stalled"===u.status}),tt(o.loadingIndicator,{hidden:"stalled"!==u.status}),tt(o.clearButton,{hidden:!u.query})}(t),function(e,t){var r=t.autocomplete,o=t.autocompleteScopeApi,u=t.classNames,a=t.html,c=t.dom,l=t.panelContainer,s=t.propGetters,p=t.state,f=t.components,d=t.renderer;if(p.isOpen){l.contains(c.panel)||"loading"===p.status||l.appendChild(c.panel),c.panel.classList.toggle("aa-Panel--stalled","stalled"===p.status);var m=p.collections.filter((function(e){var t=e.source,n=e.items;return t.templates.noResults||n.length>0})).map((function(e,t){var c=e.source,l=e.items;return d.createElement("section",{key:t,className:u.source,"data-autocomplete-source-id":c.sourceId},c.templates.header&&d.createElement("div",{className:u.sourceHeader},c.templates.header({components:f,createElement:d.createElement,Fragment:d.Fragment,items:l,source:c,state:p,html:a})),c.templates.noResults&&0===l.length?d.createElement("div",{className:u.sourceNoResults},c.templates.noResults({components:f,createElement:d.createElement,Fragment:d.Fragment,source:c,state:p,html:a})):d.createElement("ul",i({className:u.list},s.getListProps(n({state:p,props:r.getListProps({})},o))),l.map((function(e){var t=r.getItemProps({item:e,source:c});return d.createElement("li",i({key:t.id,className:u.item},s.getItemProps(n({state:p,props:t},o))),c.templates.item({components:f,createElement:d.createElement,Fragment:d.Fragment,item:e,state:p,html:a}))}))),c.templates.footer&&d.createElement("div",{className:u.sourceFooter},c.templates.footer({components:f,createElement:d.createElement,Fragment:d.Fragment,items:l,source:c,state:p,html:a})))})),v=d.createElement(d.Fragment,null,d.createElement("div",{className:u.panelLayout},m),d.createElement("div",{className:"aa-GradientBottom"})),h=m.reduce((function(e,t){return e[t.props["data-autocomplete-source-id"]]=t,e}),{});e(n(n({children:v,state:p,sections:m,elements:h},d),{},{components:f,html:a},o),c.panel)}else l.contains(c.panel)&&l.removeChild(c.panel)}(r,t)}function D(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};c();var t=O.value.renderer,n=t.components,r=u(t,In);y.current=Ge(r,O.value.core,{components:Ke(n,(function(e){return!e.value.hasOwnProperty("__autocomplete_componentName")})),initialState:j.current},e),m(),l(),P.value.refresh().then((function(){C(j.current)}))}function k(e){requestAnimationFrame((function(){var t=O.value.core.environment.document.body.contains(E.value.detachedOverlay);e!==t&&(e?(O.value.core.environment.document.body.appendChild(E.value.detachedOverlay),O.value.core.environment.document.body.classList.add("aa-Detached"),E.value.input.focus()):(O.value.core.environment.document.body.removeChild(E.value.detachedOverlay),O.value.core.environment.document.body.classList.remove("aa-Detached"),P.value.setQuery(""),P.value.refresh()))}))}return a((function(){var e=P.value.getEnvironmentProps({formElement:E.value.form,panelElement:E.value.panel,inputElement:E.value.input});return tt(O.value.core.environment,e),function(){tt(O.value.core.environment,Object.keys(e).reduce((function(e,t){return n(n({},e),{},o({},t,void 0))}),{}))}})),a((function(){var e=_.value?O.value.core.environment.document.body:O.value.renderer.panelContainer,t=_.value?E.value.detachedOverlay:E.value.panel;return _.value&&j.current.isOpen&&k(!0),C(j.current),function(){e.contains(t)&&e.removeChild(t)}})),a((function(){var e=O.value.renderer.container;return e.appendChild(E.value.root),function(){e.removeChild(E.value.root)}})),a((function(){var e=f((function(e){C(e.state)}),0);return b.current=function(t){var n=t.state,r=t.prevState;(_.value&&r.isOpen!==n.isOpen&&k(n.isOpen),_.value||!n.isOpen||r.isOpen||A(),n.query!==r.query)&&O.value.core.environment.document.querySelectorAll(".aa-Panel--scrollable").forEach((function(e){0!==e.scrollTop&&(e.scrollTop=0)}));e({state:n})},function(){b.current=void 0}})),a((function(){var e=f((function(){var e=_.value;_.value=O.value.core.environment.matchMedia(O.value.renderer.detachedMediaQuery).matches,e!==_.value?D({}):requestAnimationFrame(A)}),20);return O.value.core.environment.addEventListener("resize",e),function(){O.value.core.environment.removeEventListener("resize",e)}})),a((function(){if(!_.value)return function(){};function e(e){E.value.detachedContainer.classList.toggle("aa-DetachedContainer--modal",e)}function t(t){e(t.matches)}var n=O.value.core.environment.matchMedia(getComputedStyle(O.value.core.environment.document.documentElement).getPropertyValue("--aa-detached-modal-media-query"));e(n.matches);var r=Boolean(n.addEventListener);return r?n.addEventListener("change",t):n.addListener(t),function(){r?n.removeEventListener("change",t):n.removeListener(t)}})),a((function(){return requestAnimationFrame(A),function(){}})),n(n({},S),{},{update:D,destroy:function(){c()}})},e.getAlgoliaFacets=function(e){var t=En({transformResponse:function(e){return e.facetHits}}),r=e.queries.map((function(e){return n(n({},e),{},{type:"facet"})}));return t(n(n({},e),{},{queries:r}))},e.getAlgoliaResults=An,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/docs/devel/site_libs/quarto-search/fuse.min.js b/docs/devel/site_libs/quarto-search/fuse.min.js new file mode 100644 index 0000000..adc2835 --- /dev/null +++ b/docs/devel/site_libs/quarto-search/fuse.min.js @@ -0,0 +1,9 @@ +/** + * Fuse.js v6.6.2 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2022 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(C).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),c=parseFloat(Math.round(o*r)/r);return n.set(i,c),c},clear:function(){n.clear()}}}var $=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?I.getFn:n,o=t.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o;r(this,e),this.norm=E(c,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,g(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();g(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?I.getFn:r,o=n.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o,a=new $({getFn:i,fieldNormWeight:c});return a.setKeys(e.map(_)),a.setSources(t),a.create(),a}function R(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,c=t.expectedLocation,a=void 0===c?0:c,s=t.distance,u=void 0===s?I.distance:s,h=t.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=r/e.length;if(l)return f;var d=Math.abs(a-o);return u?f+d/u:d?1:f}function N(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:I.minMatchCharLength,n=[],r=-1,i=-1,o=0,c=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}var P=32;function W(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,c=void 0===o?I.location:o,a=i.threshold,s=void 0===a?I.threshold:a,u=i.distance,h=void 0===u?I.distance:u,l=i.includeMatches,f=void 0===l?I.includeMatches:l,d=i.findAllMatches,v=void 0===d?I.findAllMatches:d,g=i.minMatchCharLength,y=void 0===g?I.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?I.isCaseSensitive:p,k=i.ignoreLocation,M=void 0===k?I.ignoreLocation:k;if(r(this,e),this.options={location:c,threshold:s,distance:h,includeMatches:f,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:M},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var b=function(e,t){n.chunks.push({pattern:e,alphabet:W(e),startIndex:t})},x=this.pattern.length;if(x>P){for(var w=0,L=x%P,S=x-L;w3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?I.location:i,c=r.distance,a=void 0===c?I.distance:c,s=r.threshold,u=void 0===s?I.threshold:s,h=r.findAllMatches,l=void 0===h?I.findAllMatches:h,f=r.minMatchCharLength,d=void 0===f?I.minMatchCharLength:f,v=r.includeMatches,g=void 0===v?I.includeMatches:v,y=r.ignoreLocation,p=void 0===y?I.ignoreLocation:y;if(t.length>P)throw new Error(w(P));for(var m,k=t.length,M=e.length,b=Math.max(0,Math.min(o,M)),x=u,L=b,S=d>1||g,_=S?Array(M):[];(m=e.indexOf(t,L))>-1;){var O=R(t,{currentLocation:m,expectedLocation:b,distance:a,ignoreLocation:p});if(x=Math.min(O,x),L=m+k,S)for(var j=0;j=z;q-=1){var B=q-1,J=n[e.charAt(B)];if(S&&(_[B]=+!!J),K[q]=(K[q+1]<<1|1)&J,F&&(K[q]|=(A[q+1]|A[q])<<1|1|A[q+1]),K[q]&$&&(C=R(t,{errors:F,currentLocation:B,expectedLocation:b,distance:a,ignoreLocation:p}))<=x){if(x=C,(L=B)<=b)break;z=Math.max(1,2*b-L)}}if(R(t,{errors:F+1,currentLocation:b,expectedLocation:b,distance:a,ignoreLocation:p})>x)break;A=K}var U={isMatch:L>=0,score:Math.max(.001,C)};if(S){var V=N(_,d);V.length?g&&(U.indices=V):U.isMatch=!1}return U}(e,n,i,{location:c+o,distance:a,threshold:s,findAllMatches:u,minMatchCharLength:h,includeMatches:r,ignoreLocation:l}),p=y.isMatch,m=y.score,k=y.indices;p&&(g=!0),v+=m,p&&k&&(d=[].concat(f(d),f(k)))}));var y={isMatch:g,score:g?v/this.chunks.length:1};return g&&r&&(y.indices=d),y}}]),e}(),z=function(){function e(t){r(this,e),this.pattern=t}return o(e,[{key:"search",value:function(){}}],[{key:"isMultiMatch",value:function(e){return D(e,this.multiRegex)}},{key:"isSingleMatch",value:function(e){return D(e,this.singleRegex)}}]),e}();function D(e,t){var n=e.match(t);return n?n[1]:null}var K=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"exact"}},{key:"multiRegex",get:function(){return/^="(.*)"$/}},{key:"singleRegex",get:function(){return/^=(.*)$/}}]),n}(z),q=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=-1===e.indexOf(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"$/}},{key:"singleRegex",get:function(){return/^!(.*)$/}}]),n}(z),B=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"prefix-exact"}},{key:"multiRegex",get:function(){return/^\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^\^(.*)$/}}]),n}(z),J=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-prefix-exact"}},{key:"multiRegex",get:function(){return/^!\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^!\^(.*)$/}}]),n}(z),U=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[e.length-this.pattern.length,e.length-1]}}}],[{key:"type",get:function(){return"suffix-exact"}},{key:"multiRegex",get:function(){return/^"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^(.*)\$$/}}]),n}(z),V=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-suffix-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^!(.*)\$$/}}]),n}(z),G=function(e){a(n,e);var t=l(n);function n(e){var i,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},c=o.location,a=void 0===c?I.location:c,s=o.threshold,u=void 0===s?I.threshold:s,h=o.distance,l=void 0===h?I.distance:h,f=o.includeMatches,d=void 0===f?I.includeMatches:f,v=o.findAllMatches,g=void 0===v?I.findAllMatches:v,y=o.minMatchCharLength,p=void 0===y?I.minMatchCharLength:y,m=o.isCaseSensitive,k=void 0===m?I.isCaseSensitive:m,M=o.ignoreLocation,b=void 0===M?I.ignoreLocation:M;return r(this,n),(i=t.call(this,e))._bitapSearch=new T(e,{location:a,threshold:u,distance:l,includeMatches:d,findAllMatches:g,minMatchCharLength:p,isCaseSensitive:k,ignoreLocation:b}),i}return o(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(z),H=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){for(var t,n=0,r=[],i=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+i,r.push([t,n-1]);var o=!!r.length;return{isMatch:o,score:o?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(z),Q=[K,H,B,J,V,U,q,G],X=Q.length,Y=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;function Z(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(Y).filter((function(e){return e&&!!e.trim()})),r=[],i=0,o=n.length;i1&&void 0!==arguments[1]?arguments[1]:{},i=n.isCaseSensitive,o=void 0===i?I.isCaseSensitive:i,c=n.includeMatches,a=void 0===c?I.includeMatches:c,s=n.minMatchCharLength,u=void 0===s?I.minMatchCharLength:s,h=n.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=n.findAllMatches,d=void 0===f?I.findAllMatches:f,v=n.location,g=void 0===v?I.location:v,y=n.threshold,p=void 0===y?I.threshold:y,m=n.distance,k=void 0===m?I.distance:m;r(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:u,findAllMatches:d,ignoreLocation:l,location:g,threshold:p,distance:k},this.pattern=o?t:t.toLowerCase(),this.query=Z(this.pattern,this.options)}return o(e,[{key:"searchIn",value:function(e){var t=this.query;if(!t)return{isMatch:!1,score:1};var n=this.options,r=n.includeMatches;e=n.isCaseSensitive?e:e.toLowerCase();for(var i=0,o=[],c=0,a=0,s=t.length;a-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function ve(e,t){t.score=e.score}function ge(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?I.includeMatches:r,o=n.includeScore,c=void 0===o?I.includeScore:o,a=[];return i&&a.push(de),c&&a.push(ve),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return a.length&&a.forEach((function(t){t(e,r)})),r}))}var ye=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;r(this,e),this.options=t(t({},I),i),this.options.useExtendedSearch,this._keyStore=new S(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof $))throw new Error("Incorrect 'index' type");this._myIndex=t||F(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){k(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.limit,r=void 0===n?-1:n,i=this.options,o=i.includeMatches,c=i.includeScore,a=i.shouldSort,s=i.sortFn,u=i.ignoreFieldNorm,h=g(e)?g(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return fe(h,{ignoreFieldNorm:u}),a&&h.sort(s),y(r)&&r>-1&&(h=h.slice(0,r)),ge(h,this._docs,{includeMatches:o,includeScore:c})}},{key:"_searchStringList",value:function(e){var t=re(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(k(n)){var c=t.searchIn(n),a=c.isMatch,s=c.score,u=c.indices;a&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:u}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=function(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).auto,r=void 0===n||n,i=function e(n){var i=Object.keys(n),o=ue(n);if(!o&&i.length>1&&!se(n))return e(le(n));if(he(n)){var c=o?n[ce]:i[0],a=o?n[ae]:n[c];if(!g(a))throw new Error(x(c));var s={keyId:j(c),pattern:a};return r&&(s.searcher=re(a,t)),s}var u={children:[],operator:i[0]};return i.forEach((function(t){var r=n[t];v(r)&&r.forEach((function(t){u.children.push(e(t))}))})),u};return se(e)||(e=le(e)),i(e)}(e,this.options),r=function e(n,r,i){if(!n.children){var o=n.keyId,c=n.searcher,a=t._findMatches({key:t._keyStore.get(o),value:t._myIndex.getValueForItemAtKeyId(r,o),searcher:c});return a&&a.length?[{idx:i,item:r,matches:a}]:[]}for(var s=[],u=0,h=n.children.length;u1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?I.getFn:n,i=t.fieldNormWeight,o=void 0===i?I.fieldNormWeight:i,c=e.keys,a=e.records,s=new $({getFn:r,fieldNormWeight:o});return s.setKeys(c),s.setIndexRecords(a),s},ye.config=I,function(){ne.push.apply(ne,arguments)}(te),ye},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/docs/devel/site_libs/quarto-search/quarto-search.js b/docs/devel/site_libs/quarto-search/quarto-search.js new file mode 100644 index 0000000..f5d852d --- /dev/null +++ b/docs/devel/site_libs/quarto-search/quarto-search.js @@ -0,0 +1,1140 @@ +const kQueryArg = "q"; +const kResultsArg = "show-results"; + +// If items don't provide a URL, then both the navigator and the onSelect +// function aren't called (and therefore, the default implementation is used) +// +// We're using this sentinel URL to signal to those handlers that this +// item is a more item (along with the type) and can be handled appropriately +const kItemTypeMoreHref = "0767FDFD-0422-4E5A-BC8A-3BE11E5BBA05"; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Ensure that search is available on this page. If it isn't, + // should return early and not do anything + var searchEl = window.document.getElementById("quarto-search"); + if (!searchEl) return; + + const { autocomplete } = window["@algolia/autocomplete-js"]; + + let quartoSearchOptions = {}; + let language = {}; + const searchOptionEl = window.document.getElementById( + "quarto-search-options" + ); + if (searchOptionEl) { + const jsonStr = searchOptionEl.textContent; + quartoSearchOptions = JSON.parse(jsonStr); + language = quartoSearchOptions.language; + } + + // note the search mode + if (quartoSearchOptions.type === "overlay") { + searchEl.classList.add("type-overlay"); + } else { + searchEl.classList.add("type-textbox"); + } + + // Used to determine highlighting behavior for this page + // A `q` query param is expected when the user follows a search + // to this page + const currentUrl = new URL(window.location); + const query = currentUrl.searchParams.get(kQueryArg); + const showSearchResults = currentUrl.searchParams.get(kResultsArg); + const mainEl = window.document.querySelector("main"); + + // highlight matches on the page + if (query !== null && mainEl) { + // perform any highlighting + highlight(escapeRegExp(query), mainEl); + + // fix up the URL to remove the q query param + const replacementUrl = new URL(window.location); + replacementUrl.searchParams.delete(kQueryArg); + window.history.replaceState({}, "", replacementUrl); + } + + // function to clear highlighting on the page when the search query changes + // (e.g. if the user edits the query or clears it) + let highlighting = true; + const resetHighlighting = (searchTerm) => { + if (mainEl && highlighting && query !== null && searchTerm !== query) { + clearHighlight(query, mainEl); + highlighting = false; + } + }; + + // Clear search highlighting when the user scrolls sufficiently + const resetFn = () => { + resetHighlighting(""); + window.removeEventListener("quarto-hrChanged", resetFn); + window.removeEventListener("quarto-sectionChanged", resetFn); + }; + + // Register this event after the initial scrolling and settling of events + // on the page + window.addEventListener("quarto-hrChanged", resetFn); + window.addEventListener("quarto-sectionChanged", resetFn); + + // Responsively switch to overlay mode if the search is present on the navbar + // Note that switching the sidebar to overlay mode requires more coordinate (not just + // the media query since we generate different HTML for sidebar overlays than we do + // for sidebar input UI) + const detachedMediaQuery = + quartoSearchOptions.type === "overlay" ? "all" : "(max-width: 991px)"; + + // If configured, include the analytics client to send insights + const plugins = configurePlugins(quartoSearchOptions); + + let lastState = null; + const { setIsOpen, setQuery, setCollections } = autocomplete({ + container: searchEl, + detachedMediaQuery: detachedMediaQuery, + defaultActiveItemId: 0, + panelContainer: "#quarto-search-results", + panelPlacement: quartoSearchOptions["panel-placement"], + debug: false, + openOnFocus: true, + plugins, + classNames: { + form: "d-flex", + }, + translations: { + clearButtonTitle: language["search-clear-button-title"], + detachedCancelButtonText: language["search-detached-cancel-button-title"], + submitButtonTitle: language["search-submit-button-title"], + }, + initialState: { + query, + }, + getItemUrl({ item }) { + return item.href; + }, + onStateChange({ state }) { + // Perhaps reset highlighting + resetHighlighting(state.query); + + // If the panel just opened, ensure the panel is positioned properly + if (state.isOpen) { + if (lastState && !lastState.isOpen) { + setTimeout(() => { + positionPanel(quartoSearchOptions["panel-placement"]); + }, 150); + } + } + + // Perhaps show the copy link + showCopyLink(state.query, quartoSearchOptions); + + lastState = state; + }, + reshape({ sources, state }) { + return sources.map((source) => { + try { + const items = source.getItems(); + + // Validate the items + validateItems(items); + + // group the items by document + const groupedItems = new Map(); + items.forEach((item) => { + const hrefParts = item.href.split("#"); + const baseHref = hrefParts[0]; + const isDocumentItem = hrefParts.length === 1; + + const items = groupedItems.get(baseHref); + if (!items) { + groupedItems.set(baseHref, [item]); + } else { + // If the href for this item matches the document + // exactly, place this item first as it is the item that represents + // the document itself + if (isDocumentItem) { + items.unshift(item); + } else { + items.push(item); + } + groupedItems.set(baseHref, items); + } + }); + + const reshapedItems = []; + let count = 1; + for (const [_key, value] of groupedItems) { + const firstItem = value[0]; + reshapedItems.push({ + ...firstItem, + type: kItemTypeDoc, + }); + + const collapseMatches = quartoSearchOptions["collapse-after"]; + const collapseCount = + typeof collapseMatches === "number" ? collapseMatches : 1; + + if (value.length > 1) { + const target = `search-more-${count}`; + const isExpanded = + state.context.expanded && + state.context.expanded.includes(target); + + const remainingCount = value.length - collapseCount; + + for (let i = 1; i < value.length; i++) { + if (collapseMatches && i === collapseCount) { + reshapedItems.push({ + target, + title: isExpanded + ? language["search-hide-matches-text"] + : remainingCount === 1 + ? `${remainingCount} ${language["search-more-match-text"]}` + : `${remainingCount} ${language["search-more-matches-text"]}`, + type: kItemTypeMore, + href: kItemTypeMoreHref, + }); + } + + if (isExpanded || !collapseMatches || i < collapseCount) { + reshapedItems.push({ + ...value[i], + type: kItemTypeItem, + target, + }); + } + } + } + count += 1; + } + + return { + ...source, + getItems() { + return reshapedItems; + }, + }; + } catch (error) { + // Some form of error occurred + return { + ...source, + getItems() { + return [ + { + title: error.name || "An Error Occurred While Searching", + text: + error.message || + "An unknown error occurred while attempting to perform the requested search.", + type: kItemTypeError, + }, + ]; + }, + }; + } + }); + }, + navigator: { + navigate({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.location.assign(itemUrl); + } + }, + navigateNewTab({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + const windowReference = window.open(itemUrl, "_blank", "noopener"); + if (windowReference) { + windowReference.focus(); + } + } + }, + navigateNewWindow({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.open(itemUrl, "_blank", "noopener"); + } + }, + }, + getSources({ state, setContext, setActiveItemId, refresh }) { + return [ + { + sourceId: "documents", + getItemUrl({ item }) { + if (item.href) { + return offsetURL(item.href); + } else { + return undefined; + } + }, + onSelect({ + item, + state, + setContext, + setIsOpen, + setActiveItemId, + refresh, + }) { + if (item.type === kItemTypeMore) { + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + + // Toggle more + setIsOpen(true); + } + }, + getItems({ query }) { + if (query === null || query === "") { + return []; + } + + const limit = quartoSearchOptions.limit; + if (quartoSearchOptions.algolia) { + return algoliaSearch(query, limit, quartoSearchOptions.algolia); + } else { + // Fuse search options + const fuseSearchOptions = { + isCaseSensitive: false, + shouldSort: true, + minMatchCharLength: 2, + limit: limit, + }; + + return readSearchData().then(function (fuse) { + return fuseSearch(query, fuse, fuseSearchOptions); + }); + } + }, + templates: { + noResults({ createElement }) { + const hasQuery = lastState.query; + + return createElement( + "div", + { + class: `quarto-search-no-results${ + hasQuery ? "" : " no-query" + }`, + }, + language["search-no-results-text"] + ); + }, + header({ items, createElement }) { + // count the documents + const count = items.filter((item) => { + return item.type === kItemTypeDoc; + }).length; + + if (count > 0) { + return createElement( + "div", + { class: "search-result-header" }, + `${count} ${language["search-matching-documents-text"]}` + ); + } else { + return createElement( + "div", + { class: "search-result-header-no-results" }, + `` + ); + } + }, + footer({ _items, createElement }) { + if ( + quartoSearchOptions.algolia && + quartoSearchOptions.algolia["show-logo"] + ) { + const libDir = quartoSearchOptions.algolia["libDir"]; + const logo = createElement("img", { + src: offsetURL( + `${libDir}/quarto-search/search-by-algolia.svg` + ), + class: "algolia-search-logo", + }); + return createElement( + "a", + { href: "http://www.algolia.com/" }, + logo + ); + } + }, + + item({ item, createElement }) { + return renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh + ); + }, + }, + }, + ]; + }, + }); + + window.quartoOpenSearch = () => { + setIsOpen(false); + setIsOpen(true); + focusSearchInput(); + }; + + // Remove the labeleledby attribute since it is pointing + // to a non-existent label + if (quartoSearchOptions.type === "overlay") { + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + if (inputEl) { + inputEl.removeAttribute("aria-labelledby"); + } + } + + // If the main document scrolls dismiss the search results + // (otherwise, since they're floating in the document they can scroll with the document) + window.document.body.onscroll = () => { + setIsOpen(false); + }; + + if (showSearchResults) { + setIsOpen(true); + focusSearchInput(); + } +}); + +function configurePlugins(quartoSearchOptions) { + const autocompletePlugins = []; + const algoliaOptions = quartoSearchOptions.algolia; + if ( + algoliaOptions && + algoliaOptions["analytics-events"] && + algoliaOptions["search-only-api-key"] && + algoliaOptions["application-id"] + ) { + const apiKey = algoliaOptions["search-only-api-key"]; + const appId = algoliaOptions["application-id"]; + + // Aloglia insights may not be loaded because they require cookie consent + // Use deferred loading so events will start being recorded when/if consent + // is granted. + const algoliaInsightsDeferredPlugin = deferredLoadPlugin(() => { + if ( + window.aa && + window["@algolia/autocomplete-plugin-algolia-insights"] + ) { + window.aa("init", { + appId, + apiKey, + useCookie: true, + }); + + const { createAlgoliaInsightsPlugin } = + window["@algolia/autocomplete-plugin-algolia-insights"]; + // Register the insights client + const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({ + insightsClient: window.aa, + onItemsChange({ insights, insightsEvents }) { + const events = insightsEvents.map((event) => { + const maxEvents = event.objectIDs.slice(0, 20); + return { + ...event, + objectIDs: maxEvents, + }; + }); + + insights.viewedObjectIDs(...events); + }, + }); + return algoliaInsightsPlugin; + } + }); + + // Add the plugin + autocompletePlugins.push(algoliaInsightsDeferredPlugin); + return autocompletePlugins; + } +} + +// For plugins that may not load immediately, create a wrapper +// plugin and forward events and plugin data once the plugin +// is initialized. This is useful for cases like cookie consent +// which may prevent the analytics insights event plugin from initializing +// immediately. +function deferredLoadPlugin(createPlugin) { + let plugin = undefined; + let subscribeObj = undefined; + const wrappedPlugin = () => { + if (!plugin && subscribeObj) { + plugin = createPlugin(); + if (plugin && plugin.subscribe) { + plugin.subscribe(subscribeObj); + } + } + return plugin; + }; + + return { + subscribe: (obj) => { + subscribeObj = obj; + }, + onStateChange: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onStateChange) { + plugin.onStateChange(obj); + } + }, + onSubmit: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onSubmit) { + plugin.onSubmit(obj); + } + }, + onReset: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onReset) { + plugin.onReset(obj); + } + }, + getSources: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.getSources) { + return plugin.getSources(obj); + } else { + return Promise.resolve([]); + } + }, + data: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.data) { + plugin.data(obj); + } + }, + }; +} + +function validateItems(items) { + // Validate the first item + if (items.length > 0) { + const item = items[0]; + const missingFields = []; + if (item.href == undefined) { + missingFields.push("href"); + } + if (!item.title == undefined) { + missingFields.push("title"); + } + if (!item.text == undefined) { + missingFields.push("text"); + } + + if (missingFields.length === 1) { + throw { + name: `Error: Search index is missing the ${missingFields[0]} field.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items include the ${missingFields[0]} field or use index-fields in your _quarto.yml file to specify the field names.`, + }; + } else if (missingFields.length > 1) { + const missingFieldList = missingFields + .map((field) => { + return `${field}`; + }) + .join(", "); + + throw { + name: `Error: Search index is missing the following fields: ${missingFieldList}.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items includes the following fields: ${missingFieldList}, or use index-fields in your _quarto.yml file to specify the field names.`, + }; + } + } +} + +let lastQuery = null; +function showCopyLink(query, options) { + const language = options.language; + lastQuery = query; + // Insert share icon + const inputSuffixEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix" + ); + + if (inputSuffixEl) { + let copyButtonEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix .aa-CopyButton" + ); + + if (copyButtonEl === null) { + copyButtonEl = window.document.createElement("button"); + copyButtonEl.setAttribute("class", "aa-CopyButton"); + copyButtonEl.setAttribute("type", "button"); + copyButtonEl.setAttribute("title", language["search-copy-link-title"]); + copyButtonEl.onmousedown = (e) => { + e.preventDefault(); + e.stopPropagation(); + }; + + const linkIcon = "bi-clipboard"; + const checkIcon = "bi-check2"; + + const shareIconEl = window.document.createElement("i"); + shareIconEl.setAttribute("class", `bi ${linkIcon}`); + copyButtonEl.appendChild(shareIconEl); + inputSuffixEl.prepend(copyButtonEl); + + const clipboard = new window.ClipboardJS(".aa-CopyButton", { + text: function (_trigger) { + const copyUrl = new URL(window.location); + copyUrl.searchParams.set(kQueryArg, lastQuery); + copyUrl.searchParams.set(kResultsArg, "1"); + return copyUrl.toString(); + }, + }); + clipboard.on("success", function (e) { + // Focus the input + + // button target + const button = e.trigger; + const icon = button.querySelector("i.bi"); + + // flash "checked" + icon.classList.add(checkIcon); + icon.classList.remove(linkIcon); + setTimeout(function () { + icon.classList.remove(checkIcon); + icon.classList.add(linkIcon); + }, 1000); + }); + } + + // If there is a query, show the link icon + if (copyButtonEl) { + if (lastQuery && options["copy-button"]) { + copyButtonEl.style.display = "flex"; + } else { + copyButtonEl.style.display = "none"; + } + } + } +} + +/* Search Index Handling */ +// create the index +var fuseIndex = undefined; +async function readSearchData() { + // Initialize the search index on demand + if (fuseIndex === undefined) { + // create fuse index + const options = { + keys: [ + { name: "title", weight: 20 }, + { name: "section", weight: 20 }, + { name: "text", weight: 10 }, + ], + ignoreLocation: true, + threshold: 0.1, + }; + const fuse = new window.Fuse([], options); + + // fetch the main search.json + const response = await fetch(offsetURL("search.json")); + if (response.status == 200) { + return response.json().then(function (searchDocs) { + searchDocs.forEach(function (searchDoc) { + fuse.add(searchDoc); + }); + fuseIndex = fuse; + return fuseIndex; + }); + } else { + return Promise.reject( + new Error( + "Unexpected status from search index request: " + response.status + ) + ); + } + } + return fuseIndex; +} + +function inputElement() { + return window.document.body.querySelector(".aa-Form .aa-Input"); +} + +function focusSearchInput() { + setTimeout(() => { + const inputEl = inputElement(); + if (inputEl) { + inputEl.focus(); + } + }, 50); +} + +/* Panels */ +const kItemTypeDoc = "document"; +const kItemTypeMore = "document-more"; +const kItemTypeItem = "document-item"; +const kItemTypeError = "error"; + +function renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh +) { + switch (item.type) { + case kItemTypeDoc: + return createDocumentCard( + createElement, + "file-richtext", + item.title, + item.section, + item.text, + item.href + ); + case kItemTypeMore: + return createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh + ); + case kItemTypeItem: + return createSectionCard( + createElement, + item.section, + item.text, + item.href + ); + case kItemTypeError: + return createErrorCard(createElement, item.title, item.text); + default: + return undefined; + } +} + +function createDocumentCard(createElement, icon, title, section, text, href) { + const iconEl = createElement("i", { + class: `bi bi-${icon} search-result-icon`, + }); + const titleEl = createElement("p", { class: "search-result-title" }, title); + const titleContainerEl = createElement( + "div", + { class: "search-result-title-container" }, + [iconEl, titleEl] + ); + + const textEls = []; + if (section) { + const sectionEl = createElement( + "p", + { class: "search-result-section" }, + section + ); + textEls.push(sectionEl); + } + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + textEls.push(descEl); + + const textContainerEl = createElement( + "div", + { class: "search-result-text-container" }, + textEls + ); + + const containerEl = createElement( + "div", + { + class: "search-result-container", + }, + [titleContainerEl, textContainerEl] + ); + + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + containerEl + ); + + const classes = ["search-result-doc", "search-item"]; + if (!section) { + classes.push("document-selectable"); + } + + return createElement( + "div", + { + class: classes.join(" "), + }, + linkEl + ); +} + +function createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh +) { + const moreCardEl = createElement( + "div", + { + class: "search-result-more search-item", + onClick: (e) => { + // Handle expanding the sections by adding the expanded + // section to the list of expanded sections + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + e.stopPropagation(); + }, + }, + item.title + ); + + return moreCardEl; +} + +function toggleExpanded(item, state, setContext, setActiveItemId, refresh) { + const expanded = state.context.expanded || []; + if (expanded.includes(item.target)) { + setContext({ + expanded: expanded.filter((target) => target !== item.target), + }); + } else { + setContext({ expanded: [...expanded, item.target] }); + } + + refresh(); + setActiveItemId(item.__autocomplete_id); +} + +function createSectionCard(createElement, section, text, href) { + const sectionEl = createSection(createElement, section, text, href); + return createElement( + "div", + { + class: "search-result-doc-section search-item", + }, + sectionEl + ); +} + +function createSection(createElement, title, text, href) { + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { class: "search-result-section" }, title); + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + [titleEl, descEl] + ); + return linkEl; +} + +function createErrorCard(createElement, title, text) { + const descEl = createElement("p", { + class: "search-error-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { + class: "search-error-title", + dangerouslySetInnerHTML: { + __html: ` ${title}`, + }, + }); + const errorEl = createElement("div", { class: "search-error" }, [ + titleEl, + descEl, + ]); + return errorEl; +} + +function positionPanel(pos) { + const panelEl = window.document.querySelector( + "#quarto-search-results .aa-Panel" + ); + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + + if (panelEl && inputEl) { + panelEl.style.top = `${Math.round(panelEl.offsetTop)}px`; + if (pos === "start") { + panelEl.style.left = `${Math.round(inputEl.left)}px`; + } else { + panelEl.style.right = `${Math.round(inputEl.offsetRight)}px`; + } + } +} + +/* Highlighting */ +// highlighting functions +function highlightMatch(query, text) { + if (text) { + const start = text.toLowerCase().indexOf(query.toLowerCase()); + if (start !== -1) { + const startMark = ""; + const endMark = ""; + + const end = start + query.length; + text = + text.slice(0, start) + + startMark + + text.slice(start, end) + + endMark + + text.slice(end); + const startInfo = clipStart(text, start); + const endInfo = clipEnd( + text, + startInfo.position + startMark.length + endMark.length + ); + text = + startInfo.prefix + + text.slice(startInfo.position, endInfo.position) + + endInfo.suffix; + + return text; + } else { + return text; + } + } else { + return text; + } +} + +function clipStart(text, pos) { + const clipStart = pos - 50; + if (clipStart < 0) { + // This will just return the start of the string + return { + position: 0, + prefix: "", + }; + } else { + // We're clipping before the start of the string, walk backwards to the first space. + const spacePos = findSpace(text, pos, -1); + return { + position: spacePos.position, + prefix: "", + }; + } +} + +function clipEnd(text, pos) { + const clipEnd = pos + 200; + if (clipEnd > text.length) { + return { + position: text.length, + suffix: "", + }; + } else { + const spacePos = findSpace(text, clipEnd, 1); + return { + position: spacePos.position, + suffix: spacePos.clipped ? "…" : "", + }; + } +} + +function findSpace(text, start, step) { + let stepPos = start; + while (stepPos > -1 && stepPos < text.length) { + const char = text[stepPos]; + if (char === " " || char === "," || char === ":") { + return { + position: step === 1 ? stepPos : stepPos - step, + clipped: stepPos > 1 && stepPos < text.length, + }; + } + stepPos = stepPos + step; + } + + return { + position: stepPos - step, + clipped: false, + }; +} + +// removes highlighting as implemented by the mark tag +function clearHighlight(searchterm, el) { + const childNodes = el.childNodes; + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + if (node.nodeType === Node.ELEMENT_NODE) { + if ( + node.tagName === "MARK" && + node.innerText.toLowerCase() === searchterm.toLowerCase() + ) { + el.replaceChild(document.createTextNode(node.innerText), node); + } else { + clearHighlight(searchterm, node); + } + } + } +} + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} + +// highlight matches +function highlight(term, el) { + const termRegex = new RegExp(term, "ig"); + const childNodes = el.childNodes; + + // walk back to front avoid mutating elements in front of us + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + + if (node.nodeType === Node.TEXT_NODE) { + // Search text nodes for text to highlight + const text = node.nodeValue; + + let startIndex = 0; + let matchIndex = text.search(termRegex); + if (matchIndex > -1) { + const markFragment = document.createDocumentFragment(); + while (matchIndex > -1) { + const prefix = text.slice(startIndex, matchIndex); + markFragment.appendChild(document.createTextNode(prefix)); + + const mark = document.createElement("mark"); + mark.appendChild( + document.createTextNode( + text.slice(matchIndex, matchIndex + term.length) + ) + ); + markFragment.appendChild(mark); + + startIndex = matchIndex + term.length; + matchIndex = text.slice(startIndex).search(new RegExp(term, "ig")); + if (matchIndex > -1) { + matchIndex = startIndex + matchIndex; + } + } + if (startIndex < text.length) { + markFragment.appendChild( + document.createTextNode(text.slice(startIndex, text.length)) + ); + } + + el.replaceChild(markFragment, node); + } + } else if (node.nodeType === Node.ELEMENT_NODE) { + // recurse through elements + highlight(term, node); + } + } +} + +/* Link Handling */ +// get the offset from this page for a given site root relative url +function offsetURL(url) { + var offset = getMeta("quarto:offset"); + return offset ? offset + url : url; +} + +// read a meta tag value +function getMeta(metaName) { + var metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; +} + +function algoliaSearch(query, limit, algoliaOptions) { + const { getAlgoliaResults } = window["@algolia/autocomplete-preset-algolia"]; + + const applicationId = algoliaOptions["application-id"]; + const searchOnlyApiKey = algoliaOptions["search-only-api-key"]; + const indexName = algoliaOptions["index-name"]; + const indexFields = algoliaOptions["index-fields"]; + const searchClient = window.algoliasearch(applicationId, searchOnlyApiKey); + const searchParams = algoliaOptions["params"]; + const searchAnalytics = !!algoliaOptions["analytics-events"]; + + return getAlgoliaResults({ + searchClient, + queries: [ + { + indexName: indexName, + query, + params: { + hitsPerPage: limit, + clickAnalytics: searchAnalytics, + ...searchParams, + }, + }, + ], + transformResponse: (response) => { + if (!indexFields) { + return response.hits.map((hit) => { + return hit.map((item) => { + return { + ...item, + text: highlightMatch(query, item.text), + }; + }); + }); + } else { + const remappedHits = response.hits.map((hit) => { + return hit.map((item) => { + const newItem = { ...item }; + ["href", "section", "title", "text"].forEach((keyName) => { + const mappedName = indexFields[keyName]; + if ( + mappedName && + item[mappedName] !== undefined && + mappedName !== keyName + ) { + newItem[keyName] = item[mappedName]; + delete newItem[mappedName]; + } + }); + newItem.text = highlightMatch(query, newItem.text); + return newItem; + }); + }); + return remappedHits; + } + }, + }); +} + +function fuseSearch(query, fuse, fuseOptions) { + return fuse.search(query, fuseOptions).map((result) => { + const addParam = (url, name, value) => { + const anchorParts = url.split("#"); + const baseUrl = anchorParts[0]; + const sep = baseUrl.search("\\?") > 0 ? "&" : "?"; + anchorParts[0] = baseUrl + sep + name + "=" + value; + return anchorParts.join("#"); + }; + + return { + title: result.item.title, + section: result.item.section, + href: addParam(result.item.href, kQueryArg, query), + text: highlightMatch(query, result.item.text), + }; + }); +}