R Notebook: Provides reproducible analysis for Mapping Files in the following manuscript:

Citation: Romanowicz KJ, Resnick C, Hinton SR, Plesa C. (2025) Exploring antibiotic resistance in diverse homologs of the dihydrofolate reductase protein family through broad mutational scanning. Science Advances. https://doi.org/10.1126/sciadv.adw9178

GitHub Repository: https://github.com/PlesaLab/DHFR

NCBI BioProject: https://www.ncbi.nlm.nih.gov/bioproject/1189478

Experiment

This pipeline processes a library of 1,536 DHFR homologs and their associated mutants, with two-fold redundancy (two codon variants per sequence). Fitness scores are derived from a multiplexed in-vivo assay using a trimethoprim concentration gradient, assessing the ability of these homologs and their mutants to complement functionality in an E. coli knockout strain and their tolerance to trimethoprim treatment. This analysis provides insights into how antibiotic resistance evolves across a range of evolutionary starting points. Sequence data were generated using the Illumina NovaSeq platform with 100 bp paired-end sequencing of amplicons.

Methods overview to achieve a broad-mutational scan for DHFR homologs.
Methods overview to achieve a broad-mutational scan for DHFR homologs.

Packages

The following R packages must be installed prior to loading into the R session. See the Reproducibility tab for a complete list of packages and their versions used in this workflow.

# Load the latest version of python (3.10.14) for downstream use:
library(reticulate)
use_python("/Users/krom/miniforge3/bin/python3")

# Make a vector of required packages
required.packages <- c("ape", "bio3d", "Biostrings", "castor", "cowplot", "devtools", "dplyr", "ggExtra", "ggnewscale", "ggplot2", "ggridges", "ggtree", "ggtreeExtra", "glmnet", "gridExtra","igraph", "knitr", "matrixStats", "patchwork", "pheatmap", "purrr", "pscl", "RColorBrewer", "reshape","reshape2", "ROCR", "seqinr", "scales", "stringr", "stringi", "tidyr", "tidytree", "viridis")

# Load required packages with error handling
loaded.packages <- lapply(required.packages, function(package) {
  if (!require(package, character.only = TRUE)) {
    install.packages(package, dependencies = TRUE)
    if (!require(package, character.only = TRUE)) {
      message("Package ", package, " could not be installed and loaded.")
      return(NULL)
    }
  }
  return(package)
})

# Remove NULL entries from loaded packages
loaded.packages <- loaded.packages[!sapply(loaded.packages, is.null)]
Loaded packages: ape, bio3d, Biostrings, castor, cowplot, devtools, dplyr, ggExtra, ggnewscale, ggplot2, ggridges, ggtree, ggtreeExtra, glmnet, gridExtra, igraph, knitr, matrixStats, patchwork, pheatmap, purrr, pscl, RColorBrewer, reshape, reshape2, ROCR, seqinr, scales, stringr, stringi, tidyr, tidytree, viridis 

Mapping Data Analysis

This section is based on the R file: “R_load_data.R”. It describes how to load all of the pre-existing barcode mapping data necessary for downstream analysis.

Pre-Existing Data Files to Import

  • BCinfo: Mapping Information (one for each library)
  • mutIDinfo: Mutant Information (one for each library)
  • BCs: Everything Sequenced (one for each library)
  • BCmut: Only Mapped Barcodes (one for each library)

Import Barcode Info

Begin the analysis by loading in the barcode information for each codon-version library. This data represents each barcode [BC] recovered from the complementation process, linked to each homolog or mutant [mutID], the number of mutations observed in the sequence relative to its designed homolog [mutations], a list of where the mutations occurred along the protein sequence[cigar], and the number of reads associated with each barcode [reads]:

# Library 15 (Codon 1)
BCinfo15 = read.csv("Mapping/map_files_raw/15_HiFi_BC_mutID_all.csv", head=TRUE)  # read csv file

# Library 16 (Codon 2)
BCinfo16 = read.csv("Mapping/map_files_raw/16_HiFi_BC_mutID_all.csv", head=TRUE)  # read csv file

Filter Mutations

Filter each dataset to ensure each mutant has >=0 mutations

## Make sure each mutant has >=0 mutations by removing rows with negative values
BCinfo15 <- BCinfo15 %>%
  filter(mutations >= 0)

# Check mutate count for Lib15 (should be "0"):
min(BCinfo15$mutations)
[1] 0
## Make sure each mutant has >=0 mutations by removing rows with negative values
BCinfo16 <- BCinfo16 %>%
  filter(mutations >= 0)

# Check mutate count for Lib16 (should be "0"):
min(BCinfo16$mutations)
[1] 0

Preview of BCinfo

Unique BC Counts

Total BC Read Counts: Summarize the total number of reads associated with all BCs for both libraries:

#Lib15
BCinfo15.read.count <- sum(BCinfo15$reads)
format(BCinfo15.read.count, big.mark = ",")
[1] "7,379,482"
#Lib16
BCinfo16.read.count <- sum(BCinfo16$reads)
format(BCinfo16.read.count, big.mark = ",")
[1] "7,635,281"

Total BCs: Count the number of unique barcodes for each library

# Count the number of unique barcodes for Library 15
BCinfo15.count <- length(unique(BCinfo15$BC))
format(BCinfo15.count, big.mark = ",")
[1] "1,545,469"
# Count the number of unique barcodes for Library 16
BCinfo16.count <- length(unique(BCinfo16$BC))
format(BCinfo16.count, big.mark = ",")
[1] "1,801,773"

Perfects BCs: Count the number of unique barcodes that have zero mutations (i.e., BCs associated with perfects). Note that many of these barcodes are likely associated with the same protein sequence and do not represent the total number of perfects recovered from the dataset.

# Count the number of rows containing zero (0) mutations for Library 15
BCinfo15.count.zeros <- sum(BCinfo15$mutations == 0)
format(BCinfo15.count.zeros, big.mark = ",")
[1] "417,540"
# Count the number of rows containing zero (0) mutations for Library 16
BCinfo16.count.zeros <- sum(BCinfo16$mutations == 0)
format(BCinfo16.count.zeros, big.mark = ",")
[1] "382,312"

Mutant BCs: Count the number of unique unique barcodes that have at least 1 mutation (i.e., BCs associated with mutants). Note that many of these barcodes are likely associated with the same protein sequence and do not represent the total number of mutants recovered from the dataset.

# Count the number of rows containing >=1 mutation for Library 15
BCinfo15.count.nonzeros <- sum(BCinfo15$mutations != 0)
format(BCinfo15.count.nonzeros, big.mark = ",")
[1] "1,127,929"
# Count the number of rows containing >=1 mutation for Library 16
BCinfo16.count.nonzeros <- sum(BCinfo16$mutations != 0)
format(BCinfo16.count.nonzeros, big.mark = ",")
[1] "1,419,461"

Import Mutant Info

Load in the mutant information for each codon-version library. This data represents each mutant sequence [mutID] from the dataset, the designed homolog it mutated from [IDalign], the number of barcodes associated with each mutant [numBCs], the number of mutations in the sequence relative to the designed homolog [mutations], the full sequence of the mutant [seq], the percent identity of the mutant to the designed homolog [pct_ident], a list of all barcodes associated with the mutant [BCs], and the barcode code [BCcode]:

# Library 15 (Codon 1)
mutIDinfo15 = read.csv("Mapping/map_files_raw/15_HiFi_mutID_info_all.csv", head=TRUE)  # read csv file

# Library 16 (Codon 2)
mutIDinfo16 = read.csv("Mapping/map_files_raw/16_HiFi_mutID_info_all.csv", head=TRUE)  # read csv file

Filter Mutations

Filter each dataset to ensure each mutant has >=0 mutations

## Make sure each mutant has >=0 mutations by removing rows with negative values
mutIDinfo15 <- mutIDinfo15 %>%
  filter(mutations >= 0)

# Check mutate count for Lib15 (should be "0"):
min(mutIDinfo15$mutations)
[1] 0
## Make sure each mutant has >=0 mutations by removing rows with negative values
mutIDinfo16 <- mutIDinfo16 %>%
  filter(mutations >= 0)

# Check mutate count for Lib16 (should be "0"):
min(mutIDinfo16$mutations)
[1] 0

Preview of mutIDinfo

Unique Sequence Counts

Total Sequences: Count the number of unique protein sequences in each library

# Count the number of unique protein sequences for Library 15
mutIDinfo15.count <- length(unique(mutIDinfo15$seq))
format(mutIDinfo15.count, big.mark = ",")
[1] "473,854"
# Count the number of unique protein sequences for Library 16
mutIDinfo16.count <- length(unique(mutIDinfo16$seq))
format(mutIDinfo16.count, big.mark = ",")
[1] "469,672"

Perfect Sequences: Count the number of unique protein sequences that have zero mutations (i.e., sequences associated with perfects). These values designate the number of true homologs (“perfects”) that match the designed homologs without mutations.

# Count the number of rows containing zero (0) mutations for Library 15
mutIDinfo15.count.zeros <- sum(mutIDinfo15$mutations == 0)
format(mutIDinfo15.count.zeros, big.mark = ",")
[1] "1,048"
# Count the number of rows containing zero (0) mutations for Library 16
mutIDinfo16.count.zeros <- sum(mutIDinfo16$mutations == 0)
format(mutIDinfo16.count.zeros, big.mark = ",")
[1] "904"

Mutant Sequences: Count the number of unique protein sequences that have at least 1 mutation (i.e., sequences associated with mutants). These values designate the number of mutants derived from the designed homologs.

# Count the number of rows containing >=1 mutation for Library 15
mutIDinfo15.count.nonzeros <- sum(mutIDinfo15$mutations != 0)
format(mutIDinfo15.count.nonzeros, big.mark = ",")
[1] "472,806"
# Count the number of rows containing >=1 mutation for Library 16
mutIDinfo16.count.nonzeros <- sum(mutIDinfo16$mutations != 0)
format(mutIDinfo16.count.nonzeros, big.mark = ",")
[1] "468,768"

Count the number of shared perfect protein sequences between libraries (mutations == 0).

# Merge the mutIDinfo datasets but keep only the mutIDs shared between libraries
mutIDinfo.15.16.zeros.shared <- merge(mutIDinfo15, mutIDinfo16, by = "mutID", all = FALSE)

# Count the number of perfects (mutations == 0) shared between both libraries
mutIDinfo.15.16.zeros.shared.count <- sum(mutIDinfo.15.16.zeros.shared$mutations.x == 0)
format(mutIDinfo.15.16.zeros.shared.count, big.mark = ",")
[1] "744"

Also count the number of perfect sequences unique to one or the other library (mutations == 0).

# Merge the mutIDinfo datasets but retain only the mutIDs unique to one library or the other
mutIDinfo.15.16.zeros.unique <- bind_rows(
  anti_join(mutIDinfo15, mutIDinfo16, by = "mutID"),
  anti_join(mutIDinfo16, mutIDinfo15, by = "mutID"))

# Count the number of perfects (mutations == 0) unique to one library or the other
mutIDinfo.15.16.zeros.unique.count <- sum(mutIDinfo.15.16.zeros.unique$mutations == 0)
format(mutIDinfo.15.16.zeros.unique.count, big.mark = ",")
[1] "464"

Count the total number of shared and unique perfects between libraries:

mutIDinfo.15.16.zeros.all.count <- sum(mutIDinfo.15.16.zeros.shared.count + mutIDinfo.15.16.zeros.unique.count)
format(mutIDinfo.15.16.zeros.all.count, big.mark = ",")
[1] "1,208"

Add Map Identifiers

Add the IDalign column to the “BCinfo” objects based on shared “mutID” values with the “mutIDinfo” objects:

# Lib 15
BCinfo15$IDalign <- mutIDinfo15$IDalign[match(BCinfo15$mutID, mutIDinfo15$mutID)]

# Lib 16
BCinfo16$IDalign <- mutIDinfo16$IDalign[match(BCinfo16$mutID, mutIDinfo16$mutID)]

Add “Lib” column with value==1 for each BC present in the “BCinfo” object

# Add a new column "NewColumn" with every row value set to 1

# Lib 15
BCinfo15 <- BCinfo15 %>% mutate(Lib15 = 1)

# Lib 16
BCinfo16 <- BCinfo16 %>% mutate(Lib16 = 1)

Merge Mapping Files

Merge the “BCinfo” and “mutIDinfo” mapping files by shared “mutID” values for each library

# Lib15

# Merge mapping files by "mutID"
BCs_mutID_15 <- inner_join(BCinfo15, 
                           mutIDinfo15 %>% select(-BCs), 
                           by = "mutID")

# Select columns of interest to remove duplicates
BCs_mutID_15 <- BCs_mutID_15 %>%
  select(BC, mutID, IDalign.x, mutations.x, cigar, numBCs, seq, pct_ident)

# Rename columns
names(BCs_mutID_15) <- c("BC","mutID","IDalign","mutations","cigar","numBCs","seq","pct_ident")

# Lib16

# Merge mapping files by "mutID"
BCs_mutID_16 <- inner_join(BCinfo16, 
                           mutIDinfo16 %>% select(-BCs), 
                           by = "mutID")

# Select columns of interest to remove duplicates
BCs_mutID_16 <- BCs_mutID_16 %>%
  select(BC, mutID, IDalign.x, mutations.x, cigar, numBCs, seq, pct_ident)

# Rename columns
names(BCs_mutID_16) <- c("BC","mutID","IDalign","mutations","cigar","numBCs","seq","pct_ident")

Save Mapping Files

Save the formatted mapping files to import for downstream analyses

# BCinfo15 (185.4 MB)
write.csv(BCinfo15, "Mapping/map_files_formatted/BCinfo15.csv", row.names = FALSE)

# BCinfo16 (225.7 MB)
write.csv(BCinfo16, "Mapping/map_files_formatted/BCinfo16.csv", row.names = FALSE)

###------------------------------------

# mutIDinfo15 (140 MB)
write.csv(mutIDinfo15, "Mapping/map_files_formatted/mutIDinfo15.csv", row.names = FALSE)

# mutIDinfo16 (144.1 MB)
write.csv(mutIDinfo16, "Mapping/map_files_formatted/mutIDinfo16.csv", row.names = FALSE)

###------------------------------------

# BCs_mutID_15 (367.8 MB | Previously 53.13 GB when including "BCs" column)
write.csv(BCs_mutID_15, "Mapping/map_files_formatted/BCs_mutID_15.csv", row.names = FALSE)

# BCs_mutID_16 (416.8 MB | Previously 211.83 GB when including "BCs" column)
write.csv(BCs_mutID_16, "Mapping/map_files_formatted/BCs_mutID_16.csv", row.names = FALSE)

###------------------------------------

# mutIDinfo.15.16.zeros.shared (19.4 MB)
write.csv(mutIDinfo.15.16.zeros.shared, "Mapping/map_files_formatted/mutIDinfo.15.16.zeros.shared.csv", 
          row.names = FALSE)

# mutIDinfo.15.16.zeros.unique (264.3 MB)
write.csv(mutIDinfo.15.16.zeros.unique, "Mapping/map_files_formatted/mutIDinfo.15.16.zeros.unique.csv", 
          row.names = FALSE)

Reproducibility

The session information is provided for full reproducibility.

devtools::session_info()
─ Session info ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.3.2 (2023-10-31)
 os       macOS 15.5
 system   aarch64, darwin20
 ui       RStudio
 language (EN)
 collate  en_US.UTF-8
 ctype    en_US.UTF-8
 tz       America/Los_Angeles
 date     2025-08-14
 rstudio  2024.09.0+375 Cranberry Hibiscus (desktop)
 pandoc   3.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/aarch64/ (via rmarkdown)
 quarto   1.6.42 @ /usr/local/bin/quarto

─ Packages ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 package          * version    date (UTC) lib source
 ade4               1.7-23     2025-02-14 [1] CRAN (R 4.3.3)
 ape              * 5.8-1      2024-12-16 [1] CRAN (R 4.3.3)
 aplot              0.2.5      2025-02-27 [1] CRAN (R 4.3.3)
 bio3d            * 2.4-5      2024-10-29 [1] CRAN (R 4.3.3)
 BiocGenerics     * 0.46.0     2023-06-04 [1] Bioconductor
 Biostrings       * 2.68.1     2023-05-21 [1] Bioconductor
 bitops             1.0-9      2024-10-03 [1] CRAN (R 4.3.3)
 bslib              0.9.0      2025-01-30 [1] CRAN (R 4.3.3)
 cachem             1.1.0      2024-05-16 [1] CRAN (R 4.3.3)
 castor           * 1.8.3      2024-11-17 [1] CRAN (R 4.3.3)
 cli                3.6.4      2025-02-13 [1] CRAN (R 4.3.3)
 codetools          0.2-20     2024-03-31 [1] CRAN (R 4.3.1)
 colorspace         2.1-1      2024-07-26 [1] CRAN (R 4.3.3)
 cowplot          * 1.1.3      2024-01-22 [1] CRAN (R 4.3.1)
 crayon             1.5.3      2024-06-20 [1] CRAN (R 4.3.3)
 devtools         * 2.4.5      2022-10-11 [1] CRAN (R 4.3.0)
 digest             0.6.37     2024-08-19 [1] CRAN (R 4.3.3)
 dplyr            * 1.1.4      2023-11-17 [1] CRAN (R 4.3.1)
 ellipsis           0.3.2      2021-04-29 [1] CRAN (R 4.3.0)
 evaluate           1.0.3      2025-01-10 [1] CRAN (R 4.3.3)
 farver             2.1.2      2024-05-13 [1] CRAN (R 4.3.3)
 fastmap            1.2.0      2024-05-15 [1] CRAN (R 4.3.3)
 foreach            1.5.2      2022-02-02 [1] CRAN (R 4.3.0)
 fs                 1.6.5      2024-10-30 [1] CRAN (R 4.3.3)
 generics           0.1.3      2022-07-05 [1] CRAN (R 4.3.0)
 GenomeInfoDb     * 1.36.4     2023-10-08 [1] Bioconductor
 GenomeInfoDbData   1.2.10     2023-09-13 [1] Bioconductor
 ggExtra          * 0.10.1     2023-08-21 [1] CRAN (R 4.3.0)
 ggfun              0.1.8      2024-12-03 [1] CRAN (R 4.3.3)
 ggnewscale       * 0.5.1      2025-02-24 [1] CRAN (R 4.3.3)
 ggplot2          * 3.5.1      2024-04-23 [1] CRAN (R 4.3.1)
 ggplotify          0.1.2      2023-08-09 [1] CRAN (R 4.3.0)
 ggridges         * 0.5.6      2024-01-23 [1] CRAN (R 4.3.1)
 ggtree           * 3.8.2      2023-07-30 [1] Bioconductor
 ggtreeExtra      * 1.10.0     2023-04-25 [1] Bioconductor
 glmnet           * 4.1-8      2023-08-22 [1] CRAN (R 4.3.0)
 glue               1.8.0      2024-09-30 [1] CRAN (R 4.3.3)
 gridExtra        * 2.3        2017-09-09 [1] CRAN (R 4.3.0)
 gridGraphics       0.5-1      2020-12-13 [1] CRAN (R 4.3.0)
 gtable             0.3.6      2024-10-25 [1] CRAN (R 4.3.3)
 htmltools          0.5.8.1    2024-04-04 [1] CRAN (R 4.3.1)
 htmlwidgets        1.6.4      2023-12-06 [1] CRAN (R 4.3.1)
 httpuv             1.6.15     2024-03-26 [1] CRAN (R 4.3.1)
 igraph           * 2.1.4      2025-01-23 [1] CRAN (R 4.3.3)
 IRanges          * 2.34.1     2023-07-02 [1] Bioconductor
 iterators          1.0.14     2022-02-05 [1] CRAN (R 4.3.0)
 jquerylib          0.1.4      2021-04-26 [1] CRAN (R 4.3.0)
 jsonlite           1.9.1      2025-03-03 [1] CRAN (R 4.3.3)
 knitr            * 1.50       2025-03-16 [1] CRAN (R 4.3.3)
 later              1.4.1      2024-11-27 [1] CRAN (R 4.3.3)
 lattice            0.22-6     2024-03-20 [1] CRAN (R 4.3.1)
 lazyeval           0.2.2      2019-03-15 [1] CRAN (R 4.3.0)
 lifecycle          1.0.4      2023-11-07 [1] CRAN (R 4.3.1)
 magrittr           2.0.3      2022-03-30 [1] CRAN (R 4.3.0)
 MASS               7.3-60.0.1 2024-01-13 [1] CRAN (R 4.3.1)
 Matrix           * 1.6-5      2024-01-11 [1] CRAN (R 4.3.1)
 matrixStats      * 1.5.0      2025-01-07 [1] CRAN (R 4.3.3)
 memoise            2.0.1      2021-11-26 [1] CRAN (R 4.3.0)
 mime               0.13       2025-03-17 [1] CRAN (R 4.3.3)
 miniUI             0.1.1.1    2018-05-18 [1] CRAN (R 4.3.0)
 munsell            0.5.1      2024-04-01 [1] CRAN (R 4.3.1)
 naturalsort        0.1.3      2016-08-30 [1] CRAN (R 4.3.0)
 nlme               3.1-167    2025-01-27 [1] CRAN (R 4.3.3)
 patchwork        * 1.3.0      2024-09-16 [1] CRAN (R 4.3.3)
 pheatmap         * 1.0.12     2019-01-04 [1] CRAN (R 4.3.0)
 pillar             1.10.1     2025-01-07 [1] CRAN (R 4.3.3)
 pkgbuild           1.4.6      2025-01-16 [1] CRAN (R 4.3.3)
 pkgconfig          2.0.3      2019-09-22 [1] CRAN (R 4.3.0)
 pkgload            1.4.0      2024-06-28 [1] CRAN (R 4.3.3)
 plyr               1.8.9      2023-10-02 [1] CRAN (R 4.3.1)
 png                0.1-8      2022-11-29 [1] CRAN (R 4.3.0)
 profvis            0.4.0      2024-09-20 [1] CRAN (R 4.3.3)
 promises           1.3.2      2024-11-28 [1] CRAN (R 4.3.3)
 pscl             * 1.5.9      2024-01-31 [1] CRAN (R 4.3.1)
 purrr            * 1.0.4      2025-02-05 [1] CRAN (R 4.3.3)
 R6                 2.6.1      2025-02-15 [1] CRAN (R 4.3.3)
 RColorBrewer     * 1.1-3      2022-04-03 [1] CRAN (R 4.3.0)
 Rcpp             * 1.0.14     2025-01-12 [1] CRAN (R 4.3.3)
 RCurl              1.98-1.17  2025-03-22 [1] CRAN (R 4.3.3)
 remotes            2.5.0      2024-03-17 [1] CRAN (R 4.3.1)
 reshape          * 0.8.9      2022-04-12 [1] CRAN (R 4.3.0)
 reshape2         * 1.4.4      2020-04-09 [1] CRAN (R 4.3.0)
 reticulate       * 1.41.0.1   2025-03-09 [1] CRAN (R 4.3.3)
 rlang              1.1.5      2025-01-17 [1] CRAN (R 4.3.3)
 rmarkdown          2.29       2024-11-04 [1] CRAN (R 4.3.3)
 ROCR             * 1.0-11     2020-05-02 [1] CRAN (R 4.3.0)
 RSpectra           0.16-2     2024-07-18 [1] CRAN (R 4.3.3)
 rstudioapi         0.17.1     2024-10-22 [1] CRAN (R 4.3.3)
 S4Vectors        * 0.38.2     2023-09-24 [1] Bioconductor
 sass               0.4.9      2024-03-15 [1] CRAN (R 4.3.1)
 scales           * 1.3.0      2023-11-28 [1] CRAN (R 4.3.1)
 seqinr           * 4.2-36     2023-12-08 [1] CRAN (R 4.3.1)
 sessioninfo        1.2.3      2025-02-05 [1] CRAN (R 4.3.3)
 shape              1.4.6.1    2024-02-23 [1] CRAN (R 4.3.1)
 shiny              1.10.0     2024-12-14 [1] CRAN (R 4.3.3)
 stringi          * 1.8.4      2024-05-06 [1] CRAN (R 4.3.3)
 stringr          * 1.5.1      2023-11-14 [1] CRAN (R 4.3.1)
 survival           3.8-3      2024-12-17 [1] CRAN (R 4.3.3)
 tibble             3.2.1      2023-03-20 [1] CRAN (R 4.3.0)
 tidyr            * 1.3.1      2024-01-24 [1] CRAN (R 4.3.1)
 tidyselect         1.2.1      2024-03-11 [1] CRAN (R 4.3.1)
 tidytree         * 0.4.6      2023-12-12 [1] CRAN (R 4.3.1)
 treeio             1.24.3     2023-07-30 [1] Bioconductor
 urlchecker         1.0.1      2021-11-30 [1] CRAN (R 4.3.0)
 usethis          * 3.1.0      2024-11-26 [1] CRAN (R 4.3.3)
 vctrs              0.6.5      2023-12-01 [1] CRAN (R 4.3.1)
 viridis          * 0.6.5      2024-01-29 [1] CRAN (R 4.3.1)
 viridisLite      * 0.4.2      2023-05-02 [1] CRAN (R 4.3.0)
 withr              3.0.2      2024-10-28 [1] CRAN (R 4.3.3)
 xfun               0.51       2025-02-19 [1] CRAN (R 4.3.3)
 xtable             1.8-4      2019-04-21 [1] CRAN (R 4.3.0)
 XVector          * 0.40.0     2023-05-08 [1] Bioconductor
 yaml               2.3.10     2024-07-26 [1] CRAN (R 4.3.3)
 yulab.utils        0.2.0      2025-01-29 [1] CRAN (R 4.3.3)
 zlibbioc           1.46.0     2023-05-08 [1] Bioconductor

 [1] /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library
 * ── Packages attached to the search path.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
LS0tCnRpdGxlOiAiTWFwcGluZyBGaWxlcyBBbmFseXNpcyIKYXV0aG9yOiAnQXV0aG9yczogW0thcmwgSi4gUm9tYW5vd2ljel0oaHR0cHM6Ly9rcm9tYW5vd2ljei5naXRodWIuaW8vKSwgQ2FybWVuIFJlc25pY2ssIFNhbXVlbCBSLiBIaW50b24sIENhbGluIFBsZXNhJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogJzUnCiAgICBkZl9wcmludDogcGFnZWQKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnNScKLS0tCgoqKlIgTm90ZWJvb2s6KiogPGZvbnQgY29sb3I9ImdyZWVuIj5Qcm92aWRlcyByZXByb2R1Y2libGUgYW5hbHlzaXMgZm9yICoqTWFwcGluZyBGaWxlcyoqIGluIHRoZSBmb2xsb3dpbmcgbWFudXNjcmlwdDo8L2ZvbnQ+CgoqKkNpdGF0aW9uOioqIFJvbWFub3dpY3ogS0osIFJlc25pY2sgQywgSGludG9uIFNSLCBQbGVzYSBDLiAoMjAyNSkgRXhwbG9yaW5nIGFudGliaW90aWMgcmVzaXN0YW5jZSBpbiBkaXZlcnNlIGhvbW9sb2dzIG9mIHRoZSBkaWh5ZHJvZm9sYXRlIHJlZHVjdGFzZSBwcm90ZWluIGZhbWlseSB0aHJvdWdoIGJyb2FkIG11dGF0aW9uYWwgc2Nhbm5pbmcuICoqKlNjaWVuY2UgQWR2YW5jZXMqKiouIFtodHRwczovL2RvaS5vcmcvMTAuMTEyNi9zY2lhZHYuYWR3OTE3OF0oaHR0cHM6Ly93d3cuc2NpZW5jZS5vcmcvZG9pLzEwLjExMjYvc2NpYWR2LmFkdzkxNzgpCgoqKkdpdEh1YiBSZXBvc2l0b3J5OioqIFtodHRwczovL2dpdGh1Yi5jb20vUGxlc2FMYWIvREhGUl0oaHR0cHM6Ly9naXRodWIuY29tL1BsZXNhTGFiL0RIRlIpCgoqKk5DQkkgQmlvUHJvamVjdDoqKiBbaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9iaW9wcm9qZWN0LzExODk0NzhdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvYmlvcHJvamVjdC8xMTg5NDc4KQoKIyBFeHBlcmltZW50CgpUaGlzIHBpcGVsaW5lIHByb2Nlc3NlcyBhIGxpYnJhcnkgb2YgMSw1MzYgREhGUiBob21vbG9ncyBhbmQgdGhlaXIgYXNzb2NpYXRlZCBtdXRhbnRzLCB3aXRoIHR3by1mb2xkIHJlZHVuZGFuY3kgKHR3byBjb2RvbiB2YXJpYW50cyBwZXIgc2VxdWVuY2UpLiBGaXRuZXNzIHNjb3JlcyBhcmUgZGVyaXZlZCBmcm9tIGEgbXVsdGlwbGV4ZWQgaW4tdml2byBhc3NheSB1c2luZyBhIHRyaW1ldGhvcHJpbSBjb25jZW50cmF0aW9uIGdyYWRpZW50LCBhc3Nlc3NpbmcgdGhlIGFiaWxpdHkgb2YgdGhlc2UgaG9tb2xvZ3MgYW5kIHRoZWlyIG11dGFudHMgdG8gY29tcGxlbWVudCBmdW5jdGlvbmFsaXR5IGluIGFuICpFLiBjb2xpKiBrbm9ja291dCBzdHJhaW4gYW5kIHRoZWlyIHRvbGVyYW5jZSB0byB0cmltZXRob3ByaW0gdHJlYXRtZW50LiBUaGlzIGFuYWx5c2lzIHByb3ZpZGVzIGluc2lnaHRzIGludG8gaG93IGFudGliaW90aWMgcmVzaXN0YW5jZSBldm9sdmVzIGFjcm9zcyBhIHJhbmdlIG9mIGV2b2x1dGlvbmFyeSBzdGFydGluZyBwb2ludHMuIFNlcXVlbmNlIGRhdGEgd2VyZSBnZW5lcmF0ZWQgdXNpbmcgdGhlIElsbHVtaW5hIE5vdmFTZXEgcGxhdGZvcm0gd2l0aCAxMDAgYnAgcGFpcmVkLWVuZCBzZXF1ZW5jaW5nIG9mIGFtcGxpY29ucy4KCiFbTWV0aG9kcyBvdmVydmlldyB0byBhY2hpZXZlIGEgYnJvYWQtbXV0YXRpb25hbCBzY2FuIGZvciBESEZSIGhvbW9sb2dzLl0oSW1hZ2VzL0RIRlIuRGlhZ3JhbS5wbmcpCgpgYGB7Y3NzfQouYmFkQ29kZSB7CmJhY2tncm91bmQtY29sb3I6IGxpZ2h0cGluazsKZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCi5nb29kQ29kZSB7CmJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JlZW47CmZvbnQtd2VpZ2h0OiBib2xkOwp9Cgouc2hhcmVkQ29kZSB7CmJhY2tncm91bmQtY29sb3I6IGxpZ2h0Ymx1ZTsKZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCnRhYmxlIHsKICBtYXJnaW46IGF1dG87CiAgYm9yZGVyLXRvcDogMXB4IHNvbGlkICM2NjY7CiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICM2NjY7Cn0KdGFibGUgdGhlYWQgdGggeyBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2RkZDsgfQp0aCwgdGQgeyBwYWRkaW5nOiA1cHg7IH0KdGhlYWQsIHRmb290LCB0cjpudGgtY2hpbGQoZXZlbikgeyBiYWNrZ3JvdW5kOiAjZWVlOyB9CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgU2V0IGdsb2JhbCBvcHRpb25zIGZvciBub3RlYm9vawprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gVFJVRSwgbWVzc2FnZSA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgY2xhc3Muc291cmNlID0gImJnLXN1Y2Nlc3MiKQoKIyBHZXR0aW5nIHRoZSBwYXRoIG9mIHlvdXIgY3VycmVudCBvcGVuIGZpbGUgYW5kIHNldCBhcyB3ZApjdXJyZW50X3BhdGggPSByc3R1ZGlvYXBpOjpnZXRBY3RpdmVEb2N1bWVudENvbnRleHQoKSRwYXRoIApzZXR3ZChkaXJuYW1lKGN1cnJlbnRfcGF0aCkpCnByaW50KGdldHdkKCkpCmBgYAoKIyBQYWNrYWdlcwpUaGUgZm9sbG93aW5nIFIgcGFja2FnZXMgbXVzdCBiZSBpbnN0YWxsZWQgcHJpb3IgdG8gbG9hZGluZyBpbnRvIHRoZSBSIHNlc3Npb24uIFNlZSB0aGUgKipSZXByb2R1Y2liaWxpdHkqKiB0YWIgZm9yIGEgY29tcGxldGUgbGlzdCBvZiBwYWNrYWdlcyBhbmQgdGhlaXIgdmVyc2lvbnMgdXNlZCBpbiB0aGlzIHdvcmtmbG93LgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KIyBMb2FkIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiBweXRob24gKDMuMTAuMTQpIGZvciBkb3duc3RyZWFtIHVzZToKbGlicmFyeShyZXRpY3VsYXRlKQp1c2VfcHl0aG9uKCIvVXNlcnMva3JvbS9taW5pZm9yZ2UzL2Jpbi9weXRob24zIikKCiMgTWFrZSBhIHZlY3RvciBvZiByZXF1aXJlZCBwYWNrYWdlcwpyZXF1aXJlZC5wYWNrYWdlcyA8LSBjKCJhcGUiLCAiYmlvM2QiLCAiQmlvc3RyaW5ncyIsICJjYXN0b3IiLCAiY293cGxvdCIsICJkZXZ0b29scyIsICJkcGx5ciIsICJnZ0V4dHJhIiwgImdnbmV3c2NhbGUiLCAiZ2dwbG90MiIsICJnZ3JpZGdlcyIsICJnZ3RyZWUiLCAiZ2d0cmVlRXh0cmEiLCAiZ2xtbmV0IiwgImdyaWRFeHRyYSIsImlncmFwaCIsICJrbml0ciIsICJtYXRyaXhTdGF0cyIsICJwYXRjaHdvcmsiLCAicGhlYXRtYXAiLCAicHVycnIiLCAicHNjbCIsICJSQ29sb3JCcmV3ZXIiLCAicmVzaGFwZSIsInJlc2hhcGUyIiwgIlJPQ1IiLCAic2VxaW5yIiwgInNjYWxlcyIsICJzdHJpbmdyIiwgInN0cmluZ2kiLCAidGlkeXIiLCAidGlkeXRyZWUiLCAidmlyaWRpcyIpCgojIExvYWQgcmVxdWlyZWQgcGFja2FnZXMgd2l0aCBlcnJvciBoYW5kbGluZwpsb2FkZWQucGFja2FnZXMgPC0gbGFwcGx5KHJlcXVpcmVkLnBhY2thZ2VzLCBmdW5jdGlvbihwYWNrYWdlKSB7CiAgaWYgKCFyZXF1aXJlKHBhY2thZ2UsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsKICAgIGluc3RhbGwucGFja2FnZXMocGFja2FnZSwgZGVwZW5kZW5jaWVzID0gVFJVRSkKICAgIGlmICghcmVxdWlyZShwYWNrYWdlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiAgICAgIG1lc3NhZ2UoIlBhY2thZ2UgIiwgcGFja2FnZSwgIiBjb3VsZCBub3QgYmUgaW5zdGFsbGVkIGFuZCBsb2FkZWQuIikKICAgICAgcmV0dXJuKE5VTEwpCiAgICB9CiAgfQogIHJldHVybihwYWNrYWdlKQp9KQoKIyBSZW1vdmUgTlVMTCBlbnRyaWVzIGZyb20gbG9hZGVkIHBhY2thZ2VzCmxvYWRlZC5wYWNrYWdlcyA8LSBsb2FkZWQucGFja2FnZXNbIXNhcHBseShsb2FkZWQucGFja2FnZXMsIGlzLm51bGwpXQpgYGAKCmBgYHtyIGNsYXNzLm91dHB1dD0ic2hhcmVkQ29kZSIsIGVjaG89RkFMU0V9CiMgUHJpbnQgbG9hZGVkIHBhY2thZ2VzCmNhdCgiTG9hZGVkIHBhY2thZ2VzOiIsIHBhc3RlKGxvYWRlZC5wYWNrYWdlcywgY29sbGFwc2UgPSAiLCAiKSwgIlxuIikKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQojIHNldC5zZWVkIGlzIHVzZWQgdG8gZml4IHRoZSByYW5kb20gbnVtYmVyIGdlbmVyYXRpb24gdG8gbWFrZSB0aGUgcmVzdWx0cyByZXBlYXRhYmxlCnNldC5zZWVkKDEyMykKYGBgCgojIE1hcHBpbmcgRGF0YSBBbmFseXNpcwoKPGZvbnQgY29sb3I9ImJsdWUiPioqVGhpcyBzZWN0aW9uIGlzIGJhc2VkIG9uIHRoZSBSIGZpbGU6ICJSX2xvYWRfZGF0YS5SIi4qKjwvZm9udD4gSXQgZGVzY3JpYmVzIGhvdyB0byBsb2FkIGFsbCBvZiB0aGUgcHJlLWV4aXN0aW5nIGJhcmNvZGUgbWFwcGluZyBkYXRhIG5lY2Vzc2FyeSBmb3IgZG93bnN0cmVhbSBhbmFseXNpcy4KCioqUHJlLUV4aXN0aW5nIERhdGEgRmlsZXMgdG8gSW1wb3J0KioKCiogKipCQ2luZm86KiogTWFwcGluZyBJbmZvcm1hdGlvbiAob25lIGZvciBlYWNoIGxpYnJhcnkpCiogKiptdXRJRGluZm86KiogTXV0YW50IEluZm9ybWF0aW9uIChvbmUgZm9yIGVhY2ggbGlicmFyeSkKKiAqKkJDczoqKiBFdmVyeXRoaW5nIFNlcXVlbmNlZCAob25lIGZvciBlYWNoIGxpYnJhcnkpCiogKipCQ211dDoqKiBPbmx5IE1hcHBlZCBCYXJjb2RlcyAob25lIGZvciBlYWNoIGxpYnJhcnkpCgojIyBJbXBvcnQgQmFyY29kZSBJbmZvCioqQmVnaW4gdGhlIGFuYWx5c2lzIGJ5IGxvYWRpbmcgaW4gdGhlIGJhcmNvZGUgaW5mb3JtYXRpb24gZm9yIGVhY2ggY29kb24tdmVyc2lvbiBsaWJyYXJ5LioqIFRoaXMgZGF0YSByZXByZXNlbnRzIGVhY2ggKipiYXJjb2RlKiogW2BCQ2BdIHJlY292ZXJlZCBmcm9tIHRoZSBjb21wbGVtZW50YXRpb24gcHJvY2VzcywgbGlua2VkIHRvIGVhY2ggKipob21vbG9nIG9yIG11dGFudCoqIFtgbXV0SURgXSwgdGhlICoqbnVtYmVyIG9mIG11dGF0aW9ucyoqIG9ic2VydmVkIGluIHRoZSBzZXF1ZW5jZSByZWxhdGl2ZSB0byBpdHMgZGVzaWduZWQgaG9tb2xvZyBbYG11dGF0aW9uc2BdLCBhIGxpc3Qgb2Ygd2hlcmUgdGhlICoqbXV0YXRpb25zIG9jY3VycmVkKiogYWxvbmcgdGhlIHByb3RlaW4gc2VxdWVuY2VbYGNpZ2FyYF0sIGFuZCB0aGUgKipudW1iZXIgb2YgcmVhZHMqKiBhc3NvY2lhdGVkIHdpdGggZWFjaCBiYXJjb2RlIFtgcmVhZHNgXToKYGBge3J9CiMgTGlicmFyeSAxNSAoQ29kb24gMSkKQkNpbmZvMTUgPSByZWFkLmNzdigiTWFwcGluZy9tYXBfZmlsZXNfcmF3LzE1X0hpRmlfQkNfbXV0SURfYWxsLmNzdiIsIGhlYWQ9VFJVRSkgICMgcmVhZCBjc3YgZmlsZQoKIyBMaWJyYXJ5IDE2IChDb2RvbiAyKQpCQ2luZm8xNiA9IHJlYWQuY3N2KCJNYXBwaW5nL21hcF9maWxlc19yYXcvMTZfSGlGaV9CQ19tdXRJRF9hbGwuY3N2IiwgaGVhZD1UUlVFKSAgIyByZWFkIGNzdiBmaWxlCmBgYAoKIyMjIEZpbHRlciBNdXRhdGlvbnMKCkZpbHRlciBlYWNoIGRhdGFzZXQgdG8gZW5zdXJlIGVhY2ggbXV0YW50IGhhcyA+PTAgbXV0YXRpb25zCmBgYHtyIGNsYXNzLm91dHB1dD0iZ29vZENvZGUifQojIyBNYWtlIHN1cmUgZWFjaCBtdXRhbnQgaGFzID49MCBtdXRhdGlvbnMgYnkgcmVtb3Zpbmcgcm93cyB3aXRoIG5lZ2F0aXZlIHZhbHVlcwpCQ2luZm8xNSA8LSBCQ2luZm8xNSAlPiUKICBmaWx0ZXIobXV0YXRpb25zID49IDApCgojIENoZWNrIG11dGF0ZSBjb3VudCBmb3IgTGliMTUgKHNob3VsZCBiZSAiMCIpOgptaW4oQkNpbmZvMTUkbXV0YXRpb25zKQoKIyMgTWFrZSBzdXJlIGVhY2ggbXV0YW50IGhhcyA+PTAgbXV0YXRpb25zIGJ5IHJlbW92aW5nIHJvd3Mgd2l0aCBuZWdhdGl2ZSB2YWx1ZXMKQkNpbmZvMTYgPC0gQkNpbmZvMTYgJT4lCiAgZmlsdGVyKG11dGF0aW9ucyA+PSAwKQoKIyBDaGVjayBtdXRhdGUgY291bnQgZm9yIExpYjE2IChzaG91bGQgYmUgIjAiKToKbWluKEJDaW5mbzE2JG11dGF0aW9ucykKYGBgCgo8Zm9udCBjb2xvcj0iZ3JlZW4iPioqUHJldmlldyBvZiBCQ2luZm8qKjwvZm9udD4KYGBge3IgZWNobz1GQUxTRX0KIyBMaWJyYXJ5IDE1CmhlYWQoQkNpbmZvMTUpCgojIExpYnJhcnkgMTYKaGVhZChCQ2luZm8xNikKYGBgCgojIyMgVW5pcXVlIEJDIENvdW50cwoKKipUb3RhbCBCQyBSZWFkIENvdW50czoqKiBTdW1tYXJpemUgdGhlIHRvdGFsIG51bWJlciBvZiByZWFkcyBhc3NvY2lhdGVkIHdpdGggYWxsIEJDcyBmb3IgYm90aCBsaWJyYXJpZXM6CmBgYHtyIGNsYXNzLm91dHB1dD0iZ29vZENvZGUifQojTGliMTUKQkNpbmZvMTUucmVhZC5jb3VudCA8LSBzdW0oQkNpbmZvMTUkcmVhZHMpCmZvcm1hdChCQ2luZm8xNS5yZWFkLmNvdW50LCBiaWcubWFyayA9ICIsIikKCiNMaWIxNgpCQ2luZm8xNi5yZWFkLmNvdW50IDwtIHN1bShCQ2luZm8xNiRyZWFkcykKZm9ybWF0KEJDaW5mbzE2LnJlYWQuY291bnQsIGJpZy5tYXJrID0gIiwiKQpgYGAKCioqVG90YWwgQkNzOioqIENvdW50IHRoZSBudW1iZXIgb2YgdW5pcXVlIGJhcmNvZGVzIGZvciBlYWNoIGxpYnJhcnkKYGBge3IgY2xhc3Mub3V0cHV0PSJnb29kQ29kZSJ9CiMgQ291bnQgdGhlIG51bWJlciBvZiB1bmlxdWUgYmFyY29kZXMgZm9yIExpYnJhcnkgMTUKQkNpbmZvMTUuY291bnQgPC0gbGVuZ3RoKHVuaXF1ZShCQ2luZm8xNSRCQykpCmZvcm1hdChCQ2luZm8xNS5jb3VudCwgYmlnLm1hcmsgPSAiLCIpCgojIENvdW50IHRoZSBudW1iZXIgb2YgdW5pcXVlIGJhcmNvZGVzIGZvciBMaWJyYXJ5IDE2CkJDaW5mbzE2LmNvdW50IDwtIGxlbmd0aCh1bmlxdWUoQkNpbmZvMTYkQkMpKQpmb3JtYXQoQkNpbmZvMTYuY291bnQsIGJpZy5tYXJrID0gIiwiKQpgYGAKCioqUGVyZmVjdHMgQkNzOioqIENvdW50IHRoZSBudW1iZXIgb2YgdW5pcXVlIGJhcmNvZGVzIHRoYXQgaGF2ZSB6ZXJvIG11dGF0aW9ucyAoaS5lLiwgQkNzIGFzc29jaWF0ZWQgd2l0aCBwZXJmZWN0cykuIE5vdGUgdGhhdCBtYW55IG9mIHRoZXNlIGJhcmNvZGVzIGFyZSBsaWtlbHkgYXNzb2NpYXRlZCB3aXRoIHRoZSBzYW1lIHByb3RlaW4gc2VxdWVuY2UgYW5kIGRvIG5vdCByZXByZXNlbnQgdGhlIHRvdGFsIG51bWJlciBvZiBwZXJmZWN0cyByZWNvdmVyZWQgZnJvbSB0aGUgZGF0YXNldC4KYGBge3IgY2xhc3Mub3V0cHV0PSJnb29kQ29kZSJ9CiMgQ291bnQgdGhlIG51bWJlciBvZiByb3dzIGNvbnRhaW5pbmcgemVybyAoMCkgbXV0YXRpb25zIGZvciBMaWJyYXJ5IDE1CkJDaW5mbzE1LmNvdW50Lnplcm9zIDwtIHN1bShCQ2luZm8xNSRtdXRhdGlvbnMgPT0gMCkKZm9ybWF0KEJDaW5mbzE1LmNvdW50Lnplcm9zLCBiaWcubWFyayA9ICIsIikKCiMgQ291bnQgdGhlIG51bWJlciBvZiByb3dzIGNvbnRhaW5pbmcgemVybyAoMCkgbXV0YXRpb25zIGZvciBMaWJyYXJ5IDE2CkJDaW5mbzE2LmNvdW50Lnplcm9zIDwtIHN1bShCQ2luZm8xNiRtdXRhdGlvbnMgPT0gMCkKZm9ybWF0KEJDaW5mbzE2LmNvdW50Lnplcm9zLCBiaWcubWFyayA9ICIsIikKYGBgCgoqKk11dGFudCBCQ3M6KiogQ291bnQgdGhlIG51bWJlciBvZiB1bmlxdWUgdW5pcXVlIGJhcmNvZGVzIHRoYXQgaGF2ZSBhdCBsZWFzdCAxIG11dGF0aW9uIChpLmUuLCBCQ3MgYXNzb2NpYXRlZCB3aXRoIG11dGFudHMpLiBOb3RlIHRoYXQgbWFueSBvZiB0aGVzZSBiYXJjb2RlcyBhcmUgbGlrZWx5IGFzc29jaWF0ZWQgd2l0aCB0aGUgc2FtZSBwcm90ZWluIHNlcXVlbmNlIGFuZCBkbyBub3QgcmVwcmVzZW50IHRoZSB0b3RhbCBudW1iZXIgb2YgbXV0YW50cyByZWNvdmVyZWQgZnJvbSB0aGUgZGF0YXNldC4KYGBge3IgY2xhc3Mub3V0cHV0PSJnb29kQ29kZSJ9CiMgQ291bnQgdGhlIG51bWJlciBvZiByb3dzIGNvbnRhaW5pbmcgPj0xIG11dGF0aW9uIGZvciBMaWJyYXJ5IDE1CkJDaW5mbzE1LmNvdW50Lm5vbnplcm9zIDwtIHN1bShCQ2luZm8xNSRtdXRhdGlvbnMgIT0gMCkKZm9ybWF0KEJDaW5mbzE1LmNvdW50Lm5vbnplcm9zLCBiaWcubWFyayA9ICIsIikKCiMgQ291bnQgdGhlIG51bWJlciBvZiByb3dzIGNvbnRhaW5pbmcgPj0xIG11dGF0aW9uIGZvciBMaWJyYXJ5IDE2CkJDaW5mbzE2LmNvdW50Lm5vbnplcm9zIDwtIHN1bShCQ2luZm8xNiRtdXRhdGlvbnMgIT0gMCkKZm9ybWF0KEJDaW5mbzE2LmNvdW50Lm5vbnplcm9zLCBiaWcubWFyayA9ICIsIikKYGBgCgojIyBJbXBvcnQgTXV0YW50IEluZm8KKipMb2FkIGluIHRoZSBtdXRhbnQgaW5mb3JtYXRpb24gZm9yIGVhY2ggY29kb24tdmVyc2lvbiBsaWJyYXJ5LioqIFRoaXMgZGF0YSByZXByZXNlbnRzIGVhY2ggKiptdXRhbnQqKiBzZXF1ZW5jZSBbYG11dElEYF0gZnJvbSB0aGUgZGF0YXNldCwgdGhlICoqZGVzaWduZWQgaG9tb2xvZyoqIGl0IG11dGF0ZWQgZnJvbSBbYElEYWxpZ25gXSwgdGhlICoqbnVtYmVyIG9mIGJhcmNvZGVzKiogYXNzb2NpYXRlZCB3aXRoIGVhY2ggbXV0YW50IFtgbnVtQkNzYF0sIHRoZSAqKm51bWJlciBvZiBtdXRhdGlvbnMqKiBpbiB0aGUgc2VxdWVuY2UgcmVsYXRpdmUgdG8gdGhlIGRlc2lnbmVkIGhvbW9sb2cgW2BtdXRhdGlvbnNgXSwgdGhlICoqZnVsbCBzZXF1ZW5jZSoqIG9mIHRoZSBtdXRhbnQgW2BzZXFgXSwgdGhlICoqcGVyY2VudCBpZGVudGl0eSBvZiB0aGUgbXV0YW50KiogdG8gdGhlIGRlc2lnbmVkIGhvbW9sb2cgW2BwY3RfaWRlbnRgXSwgYSBsaXN0IG9mICoqYWxsIGJhcmNvZGVzKiogYXNzb2NpYXRlZCB3aXRoIHRoZSBtdXRhbnQgW2BCQ3NgXSwgYW5kIHRoZSAqKmJhcmNvZGUgY29kZSoqIFtgQkNjb2RlYF06CmBgYHtyfQojIExpYnJhcnkgMTUgKENvZG9uIDEpCm11dElEaW5mbzE1ID0gcmVhZC5jc3YoIk1hcHBpbmcvbWFwX2ZpbGVzX3Jhdy8xNV9IaUZpX211dElEX2luZm9fYWxsLmNzdiIsIGhlYWQ9VFJVRSkgICMgcmVhZCBjc3YgZmlsZQoKIyBMaWJyYXJ5IDE2IChDb2RvbiAyKQptdXRJRGluZm8xNiA9IHJlYWQuY3N2KCJNYXBwaW5nL21hcF9maWxlc19yYXcvMTZfSGlGaV9tdXRJRF9pbmZvX2FsbC5jc3YiLCBoZWFkPVRSVUUpICAjIHJlYWQgY3N2IGZpbGUKYGBgCgojIyMgRmlsdGVyIE11dGF0aW9ucwoKRmlsdGVyIGVhY2ggZGF0YXNldCB0byBlbnN1cmUgZWFjaCBtdXRhbnQgaGFzID49MCBtdXRhdGlvbnMKYGBge3IgY2xhc3Mub3V0cHV0PSJnb29kQ29kZSJ9CiMjIE1ha2Ugc3VyZSBlYWNoIG11dGFudCBoYXMgPj0wIG11dGF0aW9ucyBieSByZW1vdmluZyByb3dzIHdpdGggbmVnYXRpdmUgdmFsdWVzCm11dElEaW5mbzE1IDwtIG11dElEaW5mbzE1ICU+JQogIGZpbHRlcihtdXRhdGlvbnMgPj0gMCkKCiMgQ2hlY2sgbXV0YXRlIGNvdW50IGZvciBMaWIxNSAoc2hvdWxkIGJlICIwIik6Cm1pbihtdXRJRGluZm8xNSRtdXRhdGlvbnMpCgojIyBNYWtlIHN1cmUgZWFjaCBtdXRhbnQgaGFzID49MCBtdXRhdGlvbnMgYnkgcmVtb3Zpbmcgcm93cyB3aXRoIG5lZ2F0aXZlIHZhbHVlcwptdXRJRGluZm8xNiA8LSBtdXRJRGluZm8xNiAlPiUKICBmaWx0ZXIobXV0YXRpb25zID49IDApCgojIENoZWNrIG11dGF0ZSBjb3VudCBmb3IgTGliMTYgKHNob3VsZCBiZSAiMCIpOgptaW4obXV0SURpbmZvMTYkbXV0YXRpb25zKQpgYGAKCjxmb250IGNvbG9yPSJncmVlbiI+KipQcmV2aWV3IG9mIG11dElEaW5mbyoqPC9mb250PgpgYGB7ciBlY2hvPUZBTFNFfQojIExpYnJhcnkgMTUKaGVhZChtdXRJRGluZm8xNSkKCiMgTGlicmFyeSAxNgpoZWFkKG11dElEaW5mbzE2KQpgYGAKCiMjIyBVbmlxdWUgU2VxdWVuY2UgQ291bnRzCgoqKlRvdGFsIFNlcXVlbmNlczoqKiBDb3VudCB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBwcm90ZWluIHNlcXVlbmNlcyBpbiBlYWNoIGxpYnJhcnkKYGBge3IgY2xhc3Mub3V0cHV0PSJnb29kQ29kZSJ9CiMgQ291bnQgdGhlIG51bWJlciBvZiB1bmlxdWUgcHJvdGVpbiBzZXF1ZW5jZXMgZm9yIExpYnJhcnkgMTUKbXV0SURpbmZvMTUuY291bnQgPC0gbGVuZ3RoKHVuaXF1ZShtdXRJRGluZm8xNSRzZXEpKQpmb3JtYXQobXV0SURpbmZvMTUuY291bnQsIGJpZy5tYXJrID0gIiwiKQoKIyBDb3VudCB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBwcm90ZWluIHNlcXVlbmNlcyBmb3IgTGlicmFyeSAxNgptdXRJRGluZm8xNi5jb3VudCA8LSBsZW5ndGgodW5pcXVlKG11dElEaW5mbzE2JHNlcSkpCmZvcm1hdChtdXRJRGluZm8xNi5jb3VudCwgYmlnLm1hcmsgPSAiLCIpCmBgYAoKKipQZXJmZWN0IFNlcXVlbmNlczoqKiBDb3VudCB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBwcm90ZWluIHNlcXVlbmNlcyB0aGF0IGhhdmUgemVybyBtdXRhdGlvbnMgKGkuZS4sIHNlcXVlbmNlcyBhc3NvY2lhdGVkIHdpdGggcGVyZmVjdHMpLiBUaGVzZSB2YWx1ZXMgZGVzaWduYXRlIHRoZSBudW1iZXIgb2YgdHJ1ZSBob21vbG9ncyAoInBlcmZlY3RzIikgdGhhdCBtYXRjaCB0aGUgZGVzaWduZWQgaG9tb2xvZ3Mgd2l0aG91dCBtdXRhdGlvbnMuCmBgYHtyIGNsYXNzLm91dHB1dD0iZ29vZENvZGUifQojIENvdW50IHRoZSBudW1iZXIgb2Ygcm93cyBjb250YWluaW5nIHplcm8gKDApIG11dGF0aW9ucyBmb3IgTGlicmFyeSAxNQptdXRJRGluZm8xNS5jb3VudC56ZXJvcyA8LSBzdW0obXV0SURpbmZvMTUkbXV0YXRpb25zID09IDApCmZvcm1hdChtdXRJRGluZm8xNS5jb3VudC56ZXJvcywgYmlnLm1hcmsgPSAiLCIpCgojIENvdW50IHRoZSBudW1iZXIgb2Ygcm93cyBjb250YWluaW5nIHplcm8gKDApIG11dGF0aW9ucyBmb3IgTGlicmFyeSAxNgptdXRJRGluZm8xNi5jb3VudC56ZXJvcyA8LSBzdW0obXV0SURpbmZvMTYkbXV0YXRpb25zID09IDApCmZvcm1hdChtdXRJRGluZm8xNi5jb3VudC56ZXJvcywgYmlnLm1hcmsgPSAiLCIpCmBgYAoKKipNdXRhbnQgU2VxdWVuY2VzOioqIENvdW50IHRoZSBudW1iZXIgb2YgdW5pcXVlIHByb3RlaW4gc2VxdWVuY2VzIHRoYXQgaGF2ZSBhdCBsZWFzdCAxIG11dGF0aW9uIChpLmUuLCBzZXF1ZW5jZXMgYXNzb2NpYXRlZCB3aXRoIG11dGFudHMpLiBUaGVzZSB2YWx1ZXMgZGVzaWduYXRlIHRoZSBudW1iZXIgb2YgbXV0YW50cyBkZXJpdmVkIGZyb20gdGhlIGRlc2lnbmVkIGhvbW9sb2dzLgpgYGB7ciBjbGFzcy5vdXRwdXQ9Imdvb2RDb2RlIn0KIyBDb3VudCB0aGUgbnVtYmVyIG9mIHJvd3MgY29udGFpbmluZyA+PTEgbXV0YXRpb24gZm9yIExpYnJhcnkgMTUKbXV0SURpbmZvMTUuY291bnQubm9uemVyb3MgPC0gc3VtKG11dElEaW5mbzE1JG11dGF0aW9ucyAhPSAwKQpmb3JtYXQobXV0SURpbmZvMTUuY291bnQubm9uemVyb3MsIGJpZy5tYXJrID0gIiwiKQoKIyBDb3VudCB0aGUgbnVtYmVyIG9mIHJvd3MgY29udGFpbmluZyA+PTEgbXV0YXRpb24gZm9yIExpYnJhcnkgMTYKbXV0SURpbmZvMTYuY291bnQubm9uemVyb3MgPC0gc3VtKG11dElEaW5mbzE2JG11dGF0aW9ucyAhPSAwKQpmb3JtYXQobXV0SURpbmZvMTYuY291bnQubm9uemVyb3MsIGJpZy5tYXJrID0gIiwiKQpgYGAKCkNvdW50IHRoZSBudW1iZXIgb2Ygc2hhcmVkIHBlcmZlY3QgcHJvdGVpbiBzZXF1ZW5jZXMgYmV0d2VlbiBsaWJyYXJpZXMgKG11dGF0aW9ucyA9PSAwKS4KYGBge3IgY2xhc3Mub3V0cHV0PSJnb29kQ29kZSJ9CiMgTWVyZ2UgdGhlIG11dElEaW5mbyBkYXRhc2V0cyBidXQga2VlcCBvbmx5IHRoZSBtdXRJRHMgc2hhcmVkIGJldHdlZW4gbGlicmFyaWVzCm11dElEaW5mby4xNS4xNi56ZXJvcy5zaGFyZWQgPC0gbWVyZ2UobXV0SURpbmZvMTUsIG11dElEaW5mbzE2LCBieSA9ICJtdXRJRCIsIGFsbCA9IEZBTFNFKQoKIyBDb3VudCB0aGUgbnVtYmVyIG9mIHBlcmZlY3RzIChtdXRhdGlvbnMgPT0gMCkgc2hhcmVkIGJldHdlZW4gYm90aCBsaWJyYXJpZXMKbXV0SURpbmZvLjE1LjE2Lnplcm9zLnNoYXJlZC5jb3VudCA8LSBzdW0obXV0SURpbmZvLjE1LjE2Lnplcm9zLnNoYXJlZCRtdXRhdGlvbnMueCA9PSAwKQpmb3JtYXQobXV0SURpbmZvLjE1LjE2Lnplcm9zLnNoYXJlZC5jb3VudCwgYmlnLm1hcmsgPSAiLCIpCmBgYAoKQWxzbyBjb3VudCB0aGUgbnVtYmVyIG9mIHBlcmZlY3Qgc2VxdWVuY2VzIHVuaXF1ZSB0byBvbmUgb3IgdGhlIG90aGVyIGxpYnJhcnkgKG11dGF0aW9ucyA9PSAwKS4KYGBge3IgY2xhc3Mub3V0cHV0PSJnb29kQ29kZSJ9CiMgTWVyZ2UgdGhlIG11dElEaW5mbyBkYXRhc2V0cyBidXQgcmV0YWluIG9ubHkgdGhlIG11dElEcyB1bmlxdWUgdG8gb25lIGxpYnJhcnkgb3IgdGhlIG90aGVyCm11dElEaW5mby4xNS4xNi56ZXJvcy51bmlxdWUgPC0gYmluZF9yb3dzKAogIGFudGlfam9pbihtdXRJRGluZm8xNSwgbXV0SURpbmZvMTYsIGJ5ID0gIm11dElEIiksCiAgYW50aV9qb2luKG11dElEaW5mbzE2LCBtdXRJRGluZm8xNSwgYnkgPSAibXV0SUQiKSkKCiMgQ291bnQgdGhlIG51bWJlciBvZiBwZXJmZWN0cyAobXV0YXRpb25zID09IDApIHVuaXF1ZSB0byBvbmUgbGlicmFyeSBvciB0aGUgb3RoZXIKbXV0SURpbmZvLjE1LjE2Lnplcm9zLnVuaXF1ZS5jb3VudCA8LSBzdW0obXV0SURpbmZvLjE1LjE2Lnplcm9zLnVuaXF1ZSRtdXRhdGlvbnMgPT0gMCkKZm9ybWF0KG11dElEaW5mby4xNS4xNi56ZXJvcy51bmlxdWUuY291bnQsIGJpZy5tYXJrID0gIiwiKQpgYGAKCkNvdW50IHRoZSB0b3RhbCBudW1iZXIgb2Ygc2hhcmVkIGFuZCB1bmlxdWUgcGVyZmVjdHMgYmV0d2VlbiBsaWJyYXJpZXM6CmBgYHtyIGNsYXNzLm91dHB1dD0iZ29vZENvZGUifQptdXRJRGluZm8uMTUuMTYuemVyb3MuYWxsLmNvdW50IDwtIHN1bShtdXRJRGluZm8uMTUuMTYuemVyb3Muc2hhcmVkLmNvdW50ICsgbXV0SURpbmZvLjE1LjE2Lnplcm9zLnVuaXF1ZS5jb3VudCkKZm9ybWF0KG11dElEaW5mby4xNS4xNi56ZXJvcy5hbGwuY291bnQsIGJpZy5tYXJrID0gIiwiKQpgYGAKCiMjIEFkZCBNYXAgSWRlbnRpZmllcnMKCkFkZCB0aGUgSURhbGlnbiBjb2x1bW4gdG8gdGhlICJCQ2luZm8iIG9iamVjdHMgYmFzZWQgb24gc2hhcmVkICJtdXRJRCIgdmFsdWVzIHdpdGggdGhlICJtdXRJRGluZm8iIG9iamVjdHM6CmBgYHtyfQojIExpYiAxNQpCQ2luZm8xNSRJRGFsaWduIDwtIG11dElEaW5mbzE1JElEYWxpZ25bbWF0Y2goQkNpbmZvMTUkbXV0SUQsIG11dElEaW5mbzE1JG11dElEKV0KCiMgTGliIDE2CkJDaW5mbzE2JElEYWxpZ24gPC0gbXV0SURpbmZvMTYkSURhbGlnblttYXRjaChCQ2luZm8xNiRtdXRJRCwgbXV0SURpbmZvMTYkbXV0SUQpXQpgYGAKCkFkZCAiTGliIiBjb2x1bW4gd2l0aCB2YWx1ZT09MSBmb3IgZWFjaCBCQyBwcmVzZW50IGluIHRoZSAiQkNpbmZvIiBvYmplY3QKYGBge3J9CiMgQWRkIGEgbmV3IGNvbHVtbiAiTmV3Q29sdW1uIiB3aXRoIGV2ZXJ5IHJvdyB2YWx1ZSBzZXQgdG8gMQoKIyBMaWIgMTUKQkNpbmZvMTUgPC0gQkNpbmZvMTUgJT4lIG11dGF0ZShMaWIxNSA9IDEpCgojIExpYiAxNgpCQ2luZm8xNiA8LSBCQ2luZm8xNiAlPiUgbXV0YXRlKExpYjE2ID0gMSkKYGBgCgojIyBNZXJnZSBNYXBwaW5nIEZpbGVzCgpNZXJnZSB0aGUgIkJDaW5mbyIgYW5kICJtdXRJRGluZm8iIG1hcHBpbmcgZmlsZXMgYnkgc2hhcmVkICJtdXRJRCIgdmFsdWVzIGZvciBlYWNoIGxpYnJhcnkKYGBge3J9CiMgTGliMTUKCiMgTWVyZ2UgbWFwcGluZyBmaWxlcyBieSAibXV0SUQiCkJDc19tdXRJRF8xNSA8LSBpbm5lcl9qb2luKEJDaW5mbzE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0SURpbmZvMTUgJT4lIHNlbGVjdCgtQkNzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIm11dElEIikKCiMgU2VsZWN0IGNvbHVtbnMgb2YgaW50ZXJlc3QgdG8gcmVtb3ZlIGR1cGxpY2F0ZXMKQkNzX211dElEXzE1IDwtIEJDc19tdXRJRF8xNSAlPiUKICBzZWxlY3QoQkMsIG11dElELCBJRGFsaWduLngsIG11dGF0aW9ucy54LCBjaWdhciwgbnVtQkNzLCBzZXEsIHBjdF9pZGVudCkKCiMgUmVuYW1lIGNvbHVtbnMKbmFtZXMoQkNzX211dElEXzE1KSA8LSBjKCJCQyIsIm11dElEIiwiSURhbGlnbiIsIm11dGF0aW9ucyIsImNpZ2FyIiwibnVtQkNzIiwic2VxIiwicGN0X2lkZW50IikKCiMgTGliMTYKCiMgTWVyZ2UgbWFwcGluZyBmaWxlcyBieSAibXV0SUQiCkJDc19tdXRJRF8xNiA8LSBpbm5lcl9qb2luKEJDaW5mbzE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0SURpbmZvMTYgJT4lIHNlbGVjdCgtQkNzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIm11dElEIikKCiMgU2VsZWN0IGNvbHVtbnMgb2YgaW50ZXJlc3QgdG8gcmVtb3ZlIGR1cGxpY2F0ZXMKQkNzX211dElEXzE2IDwtIEJDc19tdXRJRF8xNiAlPiUKICBzZWxlY3QoQkMsIG11dElELCBJRGFsaWduLngsIG11dGF0aW9ucy54LCBjaWdhciwgbnVtQkNzLCBzZXEsIHBjdF9pZGVudCkKCiMgUmVuYW1lIGNvbHVtbnMKbmFtZXMoQkNzX211dElEXzE2KSA8LSBjKCJCQyIsIm11dElEIiwiSURhbGlnbiIsIm11dGF0aW9ucyIsImNpZ2FyIiwibnVtQkNzIiwic2VxIiwicGN0X2lkZW50IikKYGBgCgojIFNhdmUgTWFwcGluZyBGaWxlcwoKU2F2ZSB0aGUgZm9ybWF0dGVkIG1hcHBpbmcgZmlsZXMgdG8gaW1wb3J0IGZvciBkb3duc3RyZWFtIGFuYWx5c2VzCmBgYHtyfQojIEJDaW5mbzE1ICgxODUuNCBNQikKd3JpdGUuY3N2KEJDaW5mbzE1LCAiTWFwcGluZy9tYXBfZmlsZXNfZm9ybWF0dGVkL0JDaW5mbzE1LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKIyBCQ2luZm8xNiAoMjI1LjcgTUIpCndyaXRlLmNzdihCQ2luZm8xNiwgIk1hcHBpbmcvbWFwX2ZpbGVzX2Zvcm1hdHRlZC9CQ2luZm8xNi5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCiMjIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBtdXRJRGluZm8xNSAoMTQwIE1CKQp3cml0ZS5jc3YobXV0SURpbmZvMTUsICJNYXBwaW5nL21hcF9maWxlc19mb3JtYXR0ZWQvbXV0SURpbmZvMTUuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgojIG11dElEaW5mbzE2ICgxNDQuMSBNQikKd3JpdGUuY3N2KG11dElEaW5mbzE2LCAiTWFwcGluZy9tYXBfZmlsZXNfZm9ybWF0dGVkL211dElEaW5mbzE2LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKIyMjLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIEJDc19tdXRJRF8xNSAoMzY3LjggTUIgfCBQcmV2aW91c2x5IDUzLjEzIEdCIHdoZW4gaW5jbHVkaW5nICJCQ3MiIGNvbHVtbikKd3JpdGUuY3N2KEJDc19tdXRJRF8xNSwgIk1hcHBpbmcvbWFwX2ZpbGVzX2Zvcm1hdHRlZC9CQ3NfbXV0SURfMTUuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgojIEJDc19tdXRJRF8xNiAoNDE2LjggTUIgfCBQcmV2aW91c2x5IDIxMS44MyBHQiB3aGVuIGluY2x1ZGluZyAiQkNzIiBjb2x1bW4pCndyaXRlLmNzdihCQ3NfbXV0SURfMTYsICJNYXBwaW5nL21hcF9maWxlc19mb3JtYXR0ZWQvQkNzX211dElEXzE2LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKIyMjLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIG11dElEaW5mby4xNS4xNi56ZXJvcy5zaGFyZWQgKDE5LjQgTUIpCndyaXRlLmNzdihtdXRJRGluZm8uMTUuMTYuemVyb3Muc2hhcmVkLCAiTWFwcGluZy9tYXBfZmlsZXNfZm9ybWF0dGVkL211dElEaW5mby4xNS4xNi56ZXJvcy5zaGFyZWQuY3N2IiwgCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKCiMgbXV0SURpbmZvLjE1LjE2Lnplcm9zLnVuaXF1ZSAoMjY0LjMgTUIpCndyaXRlLmNzdihtdXRJRGluZm8uMTUuMTYuemVyb3MudW5pcXVlLCAiTWFwcGluZy9tYXBfZmlsZXNfZm9ybWF0dGVkL211dElEaW5mby4xNS4xNi56ZXJvcy51bmlxdWUuY3N2IiwgCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIFJlcHJvZHVjaWJpbGl0eQoKVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcHJvdmlkZWQgZm9yIGZ1bGwgcmVwcm9kdWNpYmlsaXR5LgpgYGB7cn0KZGV2dG9vbHM6OnNlc3Npb25faW5mbygpCmBgYA==