1 Introduction

Dr. Mosser approached us with a query about what genes are changing in human macrophages shortly after stimulation. We have a couple/few experiments which may help address this. Therefore, I think I will copy my master sample sheet and extract only the ~20 samples which are relevant rather than read in all ~400 samples and subset down to the 20 of interest.

However, the sheet he gave me has a subset of the samples from these experiments, I think I will keep them all and subset down in case it turns out we want to consider some of them.

sample_sheet <- "sample_sheets/mosser_samples_202110.xlsx"
file_column <- "hg3891salmon"

2 Gather annotation data

meta_info <- check_metadata_year(metadata = sample_sheet, column = file_column)
## Checking the creation time on the first count table.
## hs_annot <- load_biomart_annotations(year = meta_info[["year"]],
##                                      overwrite=TRUE)$annotation
hs_annot <- load_biomart_annotations(year = meta_info[["year"]], month = 10)$annotation
## The biomart annotations file already exists, loading from it.
rownames(hs_annot) <- make.names(
  paste0(hs_annot[["ensembl_transcript_id"]], ".",
         hs_annot[["transcript_version"]]),
  unique = TRUE)
hs_tx_gene <- hs_annot[, c("ensembl_gene_id", "ensembl_transcript_id")]
hs_tx_gene[["id"]] <- rownames(hs_tx_gene)
hs_tx_gene <- hs_tx_gene[, c("id", "ensembl_gene_id")]
new_hs_annot <- hs_annot
rownames(new_hs_annot) <- make.names(hs_annot[["ensembl_gene_id"]], unique = TRUE)

3 Create expressionset

Including the samples I decided to keep from the two experiments in question, there are 94 remaining in these experiments.

The actual sample IDs which are of interest are:

  • Kajal’s 4hr M-CSF LPS stimulated: HPGL0917, HPGL0918, HPGL0919, HPGL0920, HPGL0921 (these have the ‘state’ column set to ‘lps’ and ‘expt_time’ set to ‘t4h’)
  • M-CSF LPS 12hr stimulated: HPGL0932, HPGL0933, HPGL0934, HPGL0935, HPGL0936 (these have state set to ‘lps’ and time to ‘t12h’.
  • Medimmune grown ex-vivo: HPGL0732, HPGL0741, HPGL0733, HPGL0742, HPGL0735, HPGL0744, HPGL0737, HPGL0746, HPGL0739, and HPGL0748 (these have state set to ‘uninfected’ and time across a range from t4h->t24h).
stimulators <- create_expt(sample_sheet, file_column="hg3891salmon",
                           gene_info=new_hs_annot, tx_gene_map=hs_tx_gene)
## Reading the sample metadata.
## The sample definitions comprises: 94 rows(samples) and 24 columns(metadata fields).
## Matched 19803 annotations and counts.
## Bringing together the count matrix and gene information.
## The mapped IDs are not the rownames of your gene information, changing them now.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 19803 rows and 94 columns.
## Quick check to see if my check_metadata_year worked
## I know a priori that ENSG00000169245 has changed version multiple
## times since 2018 and that it was not being included if I use a
## newer set of annotations.
"ENSG00000169245" %in% rownames(exprs(stimulators))
## [1] TRUE
## YAY

time_state <- paste0(pData(stimulators)[["expttime"]], "_",
                     pData(stimulators)[["state"]])
stimv2 <- set_expt_conditions(stimulators, fact=time_state)

4 Before subsetting

I want to look at these two groups of samples together before I focus in on the times/samples that Dr. Mosser is interested in. My reasoning: I should be able to tell if they are pathologically batched more easily now than after taking a bunch of samples away.

time_factor <- factor(pData(stimv2)[["expttime"]],
                      levels=c("t0h", "t4h", "t6h", "t8h", "t12h", "t24h", "t48h"))
pData(stimv2)[["expttime"]] <- time_factor

stim_norm <- normalize_expt(stimv2, norm="quant", convert="cpm", transform="log2",
                            filter=TRUE)
## Removing 7218 low-count genes (12585 remaining).
## transform_counts: Found 7811 values equal to 0, adding 1 to the matrix.
plot_pca(stim_norm, size_column="expttime", plot_labels=FALSE)$plot

stim_nb <- normalize_expt(stimv2, norm="quant", convert="cpm", transform="log2",
                            batch="svaseq", filter=TRUE)
## Warning in normalize_expt(stimv2, norm = "quant", convert = "cpm", transform =
## "log2", : Quantile normalization and sva do not always play well together.
## Removing 7218 low-count genes (12585 remaining).
## batch_counts: Before batch/surrogate estimation, 7811 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 124516 entries are 0<x<1: 11%.
## Setting 5709 low elements to zero.
## transform_counts: Found 5709 values equal to 0, adding 1 to the matrix.
plot_pca(stim_nb, size_column="expttime", plot_labels=FALSE)$plot

Ok, so it takes a while of staring at it to get a sense of what is going on, but I think it is eventually pretty clear that the various other stimulation types are confusing things pretty significantly.

stimv3 <- stimv2 %>%
  subset_expt(subset="expttime!='t0h'") %>%
  subset_expt(subset="expttime!='t6h'") %>%
  subset_expt(subset="expttime!='t48h'") %>%
  subset_expt(subset="state!='lpsado'") %>%
  subset_expt(subset="state!='lpspge'") %>%
  subset_expt(subset="state!='il4'")
## subset_expt(): There were 94, now there are 91 samples.
## subset_expt(): There were 91, now there are 87 samples.
## subset_expt(): There were 87, now there are 85 samples.
## subset_expt(): There were 85, now there are 74 samples.
## subset_expt(): There were 74, now there are 63 samples.
## subset_expt(): There were 63, now there are 63 samples.
pData(stimv3)[, c("sampleid", "expttime", "condition")]
##          sampleid expttime       condition
## hpgl0732 hpgl0732      t4h  t4h_uninfected
## hpgl0733 hpgl0733      t4h         t4h_lps
## hpgl0734 hpgl0734      t8h  t8h_uninfected
## hpgl0735 hpgl0735      t8h         t8h_lps
## hpgl0736 hpgl0736     t12h t12h_uninfected
## hpgl0737 hpgl0737     t12h        t12h_lps
## hpgl0738 hpgl0738     t24h t24h_uninfected
## hpgl0739 hpgl0739     t24h        t24h_lps
## hpgl0741 hpgl0741      t4h  t4h_uninfected
## hpgl0742 hpgl0742      t4h         t4h_lps
## hpgl0743 hpgl0743      t8h  t8h_uninfected
## hpgl0744 hpgl0744      t8h         t8h_lps
## hpgl0745 hpgl0745     t12h t12h_uninfected
## hpgl0746 hpgl0746     t12h        t12h_lps
## hpgl0747 hpgl0747     t24h t24h_uninfected
## hpgl0748 hpgl0748     t24h        t24h_lps
## hpgl0754 hpgl0754      t4h  t4h_uninfected
## hpgl0755 hpgl0755      t4h         t4h_lps
## hpgl0756 hpgl0756      t8h  t8h_uninfected
## hpgl0757 hpgl0757      t8h         t8h_lps
## hpgl0758 hpgl0758     t12h t12h_uninfected
## hpgl0759 hpgl0759     t12h        t12h_lps
## hpgl0760 hpgl0760     t24h t24h_uninfected
## hpgl0761 hpgl0761     t24h        t24h_lps
## hpgl0912 hpgl0912      t4h  t4h_uninfected
## hpgl0913 hpgl0913      t4h  t4h_uninfected
## hpgl0914 hpgl0914      t4h  t4h_uninfected
## hpgl0915 hpgl0915      t4h  t4h_uninfected
## hpgl0916 hpgl0916      t4h  t4h_uninfected
## hpgl0917 hpgl0917      t4h         t4h_lps
## hpgl0918 hpgl0918      t4h         t4h_lps
## hpgl0919 hpgl0919      t4h         t4h_lps
## hpgl0920 hpgl0920      t4h         t4h_lps
## hpgl0921 hpgl0921      t4h         t4h_lps
## hpgl0932 hpgl0932     t12h        t12h_lps
## hpgl0933 hpgl0933     t12h        t12h_lps
## hpgl0934 hpgl0934     t12h        t12h_lps
## hpgl0935 hpgl0935     t12h        t12h_lps
## hpgl0936 hpgl0936     t12h        t12h_lps
## hpgl0937 hpgl0937     t12h t12h_uninfected
## hpgl0938 hpgl0938     t12h t12h_uninfected
## hpgl0939 hpgl0939     t12h t12h_uninfected
## hpgl0940 hpgl0940     t12h t12h_uninfected
## hpgl0941 hpgl0941     t12h t12h_uninfected
## hpgl0942 hpgl0942      t4h  t4h_uninfected
## hpgl0943 hpgl0943      t4h  t4h_uninfected
## hpgl0944 hpgl0944      t4h  t4h_uninfected
## hpgl0945 hpgl0945      t4h  t4h_uninfected
## hpgl0946 hpgl0946      t4h         t4h_lps
## hpgl0947 hpgl0947      t4h         t4h_lps
## hpgl0948 hpgl0948      t4h         t4h_lps
## hpgl0949 hpgl0949      t4h         t4h_lps
## hpgl0950 hpgl0950      t4h         t4h_lps
## hpgl0961 hpgl0961     t12h        t12h_lps
## hpgl0962 hpgl0962     t12h        t12h_lps
## hpgl0963 hpgl0963     t12h        t12h_lps
## hpgl0964 hpgl0964     t12h        t12h_lps
## hpgl0965 hpgl0965     t12h        t12h_lps
## hpgl0966 hpgl0966     t12h t12h_uninfected
## hpgl0967 hpgl0967     t12h t12h_uninfected
## hpgl0968 hpgl0968     t12h t12h_uninfected
## hpgl0969 hpgl0969     t12h t12h_uninfected
## hpgl0970 hpgl0970     t12h t12h_uninfected
time_state <- paste0(pData(stimv3)[["expttime"]], "_",
                     pData(stimv3)[["state"]])
stimv3 <- set_expt_conditions(stimv3, fact=time_state)

stimv3_norm <- normalize_expt(stimv3, transform="log2", convert="cpm", norm="quant", filter=TRUE)
## Removing 7366 low-count genes (12437 remaining).
## transform_counts: Found 5153 values equal to 0, adding 1 to the matrix.
plot_pca(stimv3_norm, plot_labels=FALSE)$plot

stimv3_nb <- normalize_expt(stimv3, transform="log2", convert="cpm", norm="quant", filter=TRUE, batch="svaseq")
## Warning in normalize_expt(stimv3, transform = "log2", convert = "cpm", norm =
## "quant", : Quantile normalization and sva do not always play well together.
## Removing 7366 low-count genes (12437 remaining).
## batch_counts: Before batch/surrogate estimation, 5153 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 75317 entries are 0<x<1: 10%.
## Setting 4581 low elements to zero.
## transform_counts: Found 4581 values equal to 0, adding 1 to the matrix.
plot_pca(stimv3_nb)$plot

plot_pca(stimv3_nb, size_column="expttime")$plot

5 Smallest group

After a conversation with Najib, he suggested working with a very limited set of 4 and 8 hour samples, probably exclusively from the medimmune experiment.

stimv4 <- stimv3 %>%
  subset_expt(subset="expttime=='t4h'|expttime=='t8h'")
## subset_expt(): There were 63, now there are 31 samples.
stimv4_norm <- normalize_expt(stimv4, transform="log2", convert="cpm", norm="quant", filter=TRUE)
## Removing 7745 low-count genes (12058 remaining).
## transform_counts: Found 1751 values equal to 0, adding 1 to the matrix.
plot_pca(stimv4_norm)$plot

stimv4_nb <- normalize_expt(stimv4, transform="log2", convert="cpm", norm="quant",
                            batch="svaseq", filter=TRUE)
## Warning in normalize_expt(stimv4, transform = "log2", convert = "cpm", norm =
## "quant", : Quantile normalization and sva do not always play well together.
## Removing 7745 low-count genes (12058 remaining).
## batch_counts: Before batch/surrogate estimation, 1751 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 29518 entries are 0<x<1: 8%.
## Setting 1585 low elements to zero.
## transform_counts: Found 1585 values equal to 0, adding 1 to the matrix.
plot_pca(stimv4_nb)$plot

5.1 Consider only 4 and 12 hours

stimv412 <- stimv3 %>%
  subset_expt(subset="expttime=='t4h'|expttime=='t12h'")
## subset_expt(): There were 63, now there are 51 samples.
stimv412_norm <- normalize_expt(stimv412, transform="log2", convert="cpm", norm="quant", filter=TRUE)
## Removing 7497 low-count genes (12306 remaining).
## transform_counts: Found 4186 values equal to 0, adding 1 to the matrix.
plot_pca(stimv412_norm)$plot

stimv412_nb <- normalize_expt(stimv412, transform="log2", convert="cpm", norm="quant",
                              batch="svaseq", filter=TRUE)
## Warning in normalize_expt(stimv412, transform = "log2", convert = "cpm", :
## Quantile normalization and sva do not always play well together.
## Removing 7497 low-count genes (12306 remaining).
## batch_counts: Before batch/surrogate estimation, 4186 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 52968 entries are 0<x<1: 8%.
## Setting 3045 low elements to zero.
## transform_counts: Found 3045 values equal to 0, adding 1 to the matrix.
plot_pca(stimv412_nb)$plot

st_filt <- normalize_expt(stimv412, filter="simple")
## Removing 2617 low-count genes (17186 remaining).
initial <- all_pairwise(
    st_filt, model_batch=TRUE, force=TRUE,
    extra_contrasts="t12v4_lpsvuninf=(t12h_lps-t12h_uninfected)-(t4h_lps-t4h_uninfected)")
## Plotting a PCA before surrogate/batch inclusion.
## Using limma's removeBatchEffect to visualize with(out) batch inclusion.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.

keepers <- list(
    "12v4_uninfected" = c("t12h_uninfected", "t4h_uninfected"),
    "12v4_lps" = c("t12h_lps", "t4h_lps"),
    "lpsvuninf_4hr" = c("t4h_lps", "t4h_uninfected"),
    "lpsvuninf_12hr" = c("t12h_lps", "t12h_uninfected"),
    "t12v4_lpsvuninf" = NULL)
funkytown <- combine_de_tables(initial, keepers=keepers, excel="lps_vs_infected.xlsx")
## Deleting the file lps_vs_infected.xlsx before writing the tables.
## Assuming t12v4_lpsvuninf is a table from extra_contrasts.
## Unable to find the table in the set of possible tables.
## The possible tables are: t12h_uninfected_vs_t12h_lps, t4h_lps_vs_t12h_lps, t4h_uninfected_vs_t12h_lps, t4h_lps_vs_t12h_uninfected, t4h_uninfected_vs_t12h_uninfected, t4h_uninfected_vs_t4h_lps
## Unable to find the table in the set of possible tables.
## The possible tables are: t12h_uninfected_vs_t12h_lps, t4h_lps_vs_t12h_lps, t4h_uninfected_vs_t12h_lps, t4h_lps_vs_t12h_uninfected, t4h_uninfected_vs_t12h_uninfected, t4h_uninfected_vs_t4h_lps, t12v4_lpsvuninf
## Unable to find the table in the set of possible tables.
## The possible tables are: t12h_uninfected_vs_t12h_lps, t4h_lps_vs_t12h_lps, t4h_uninfected_vs_t12h_lps, t4h_lps_vs_t12h_uninfected, t4h_uninfected_vs_t12h_uninfected, t4h_uninfected_vs_t4h_lps

Take top n genes from LPSvNS at 4 hours, plot their abundance at 4 and 12 hours as a scatter plot.

topn <- 50

t4hr_start <- funkytown[["data"]][["lpsvuninf_4hr"]]
descending_idx <- order(t4hr_start[["edger_logfc"]], decreasing = TRUE)
t4hr_start <- t4hr_start[descending_idx, ]

t12hr_start <- funkytown[["data"]][["lpsvuninf_12hr"]]
t12hr_start <- t12hr_start[descending_idx, ]

topn_4hr <- head(t4hr_start, n=topn)
topn_12hr <- head(t12hr_start, n=topn)

combined <- as.data.frame(cbind(topn_4hr[["edger_logfc"]], topn_12hr[["edger_logfc"]]))
rownames(combined) <- make.names(head(t12hr_start[["hgncsymbol"]],
                                      n=topn), unique=TRUE)

plotted <- plot_scatter(combined) +
  scale_x_continuous(limits = c(0, 12)) +
  scale_y_continuous(limits = c(0, 12)) +
  ggplot2::geom_abline(slope=1, intercept=0)

## ggplotly(plotted)

all <- ggplt(plotted, filename="fifty_genes.html")

5.2 Comparing to Dr. Mosser’s previous table

Dr. Mosser provided me a table of previous results, the first two genes listed are CXCL10 and CXCL11 (ENSG00000169245 and 169248). I am not finding these two genes in any of my result tables. I think they got filtered out, even when I use a less restrictive filter. Let us try to understand what is going on.

"ENSG00000169245" %in% rownames(exprs(stimv412))
## [1] TRUE
## Hmm ok...
names <- fData(stimv412)[["hgnc_symbol"]]
cxcl_names <- grep(pattern="CXCL", x=names)
names[cxcl_names]
##  [1] "CXCL2"  "CXCL12" "CXCL6"  "CXCL9"  "CXCL14" "CXCL13" "CXCL16" "CXCL3" 
##  [9] "CXCL5"  "CXCL1"  "CXCL10" "CXCL11" "CXCL8"  "CXCL17"
## So, does this mean that something changed with the annotations such
## that CXCL10 is no longer included, or was it not included in the
## salmon mapping?  Well, I still have my annotations loaded, lets
## check there first...
names <- hs_annot[["hgnc_symbol"]]
cxcl_names <- grep(pattern="CXCL", x=names)
names[cxcl_names]
##  [1] "CXCL6"   "CXCL9"   "CXCL13"  "CXCL16"  "CXCL3"   "CXCL5"   "CXCL2"  
##  [8] "CXCL10"  "CXCL11"  "CXCL8"   "CXCL14"  "CXCL17"  "CXCL12"  "CXCL12" 
## [15] "CXCL12"  "CXCL1"   "CXCL12"  "CXCL12"  "CXCL12"  "CXCL8"   "CXCL8"  
## [22] "CXCL12"  "CXCL12"  "CXCL1P1" "CXCL3"   "CXCL6"   "CXCL11"  "CXCL13" 
## [29] "CXCL2"   "CXCL1"   "CXCL2"   "CXCL3"   "CXCL3"   "CXCL14"  "CXCL6"  
## [36] "CXCL16"  "CXCL16"  "CXCL16"  "CXCL16"  "CXCL17"
## ok, so the salmon quantification did not include CXCL10.

## Lets look at the salmon tables...
## I see that CXCL10 has 1 transcript: ENST00000306602.3
## Looking at one of the relevant count tables (hpgl0968) for hg38_99,
## I see that this transcript was included (but with 0 counts).
## Looking at other samples, I see that it was observed a small number
## of times -- but it definitely _was_ included.

## Let us check that the tx_gene_map is ok...
"ENST00000306602.3" %in% rownames(hs_tx_gene)
## [1] FALSE
## ok, so it is definitely there, double-check the annotations.
"ENSG00000169245" %in% rownames(new_hs_annot)
## [1] TRUE
stimulators <- create_expt(sample_sheet, file_column="hg3891salmon")
## Reading the sample metadata.
## The sample definitions comprises: 94 rows(samples) and 24 columns(metadata fields).
## Matched 86451 annotations and counts.
## Bringing together the count matrix and gene information.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 86451 rows and 94 columns.
"ENST00000306602.2" %in% rownames(exprs(stimulators))
## [1] TRUE

5.3 Compare 12 hour subtraction to 4 hour

t12hr_df <- funkytown[["data"]][["lpsvuninf_12hr"]]
t4hr_df <- funkytown[["data"]][["lpsvuninf_4hr"]]

cpm_df <- merge(t12hr_df, t4hr_df, by="row.names")
rownames(cpm_df) <- make.names(cpm_df[["hgncsymbol.x"]], unique=TRUE)
cpm_df[["Row.names"]] <- NULL

test <- plot_scatter(cpm_df[, c("deseq_logfc.x", "deseq_logfc.y")])

6 Clarification

Take the top-n most increased genes at 4 hours after LPS stimulation. Given this set, ask the question: what happened to them?

One way to provide this answer is to pull out their average cpm/rpkm values at each of the 4 relevant times/conditions and make a table.

topn <- 100
lps_order <- order(t4hr_df[["deseq_logfc"]], decreasing=TRUE)
lps_reordered <- head(t4hr_df[lps_order, ], n=topn)

ids_of_interest <- rownames(lps_reordered)
annot_interest <- lps_reordered[, c("hgncsymbol", "description")]

## We can cheat a little and get the average cpm just to get an initial sense
t4h_lpsvcontrol_cpm <- lps_reordered[, c("basic_nummed", "basic_denmed")]
t12h_lpsvcontrol_cpm <- t12hr_df[ids_of_interest, c("basic_nummed", "basic_denmed")]

combined_lpsvcontrol <- merge(t4h_lpsvcontrol_cpm, t12h_lpsvcontrol_cpm, by="row.names")
combined_lpsvcontrol <- merge(annot_interest, combined_lpsvcontrol, by.x="row.names", by.y="Row.names")
colnames(combined_lpsvcontrol) <- c("rownames", "hgncsymbol", "description",
                                    "t4h_lps", "t4h_control", "t12h_lps", "t12h_control")
written <- write_xlsx(combined_lpsvcontrol, excel="cpm_lpsvcontrol_t4hvt12h.xlsx")
wanted <- c("hpgl0732", "hpgl0741", "hpgl0733", "hpgl0742", "hpgl0734", "hpgl0743", "hpgl0735", "hpgl0744")
stimv5 <- stimv2 %>%
  subset_expt(ids=wanted)
## subset_expt(): There were 94, now there are 8 samples.
stimv5_norm <- normalize_expt(stimv5, transform="log2", convert="cpm", norm="quant", filter=TRUE)
## Removing 8840 low-count genes (10963 remaining).
## transform_counts: Found 71 values equal to 0, adding 1 to the matrix.
plot_pca(stimv5_norm)$plot

pander::pander(sessionInfo())

R version 4.1.2 (2021-11-01)

Platform: x86_64-pc-linux-gnu (64-bit)

locale: LC_CTYPE=en_US.UTF-8, LC_NUMERIC=C, LC_TIME=en_US.UTF-8, LC_COLLATE=en_US.UTF-8, LC_MONETARY=en_US.UTF-8, LC_MESSAGES=en_US.UTF-8, LC_PAPER=en_US.UTF-8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_US.UTF-8 and LC_IDENTIFICATION=C

attached base packages: stats4, stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: ruv(v.0.9.7.1), ggplot2(v.3.3.5), hpgltools(v.1.0), testthat(v.3.1.1), SummarizedExperiment(v.1.24.0), GenomicRanges(v.1.46.1), GenomeInfoDb(v.1.30.0), IRanges(v.2.28.0), S4Vectors(v.0.32.3), MatrixGenerics(v.1.6.0), matrixStats(v.0.61.0), Biobase(v.2.54.0) and BiocGenerics(v.0.40.0)

loaded via a namespace (and not attached): rappdirs(v.0.3.3), rtracklayer(v.1.54.0), R.methodsS3(v.1.8.1), tidyr(v.1.1.4), bit64(v.4.0.5), knitr(v.1.37), R.utils(v.2.11.0), DelayedArray(v.0.20.0), data.table(v.1.14.2), KEGGREST(v.1.34.0), RCurl(v.1.98-1.5), doParallel(v.1.0.16), generics(v.0.1.1), GenomicFeatures(v.1.46.1), preprocessCore(v.1.56.0), callr(v.3.7.0), usethis(v.2.1.5), RSQLite(v.2.2.9), shadowtext(v.0.1.0), bit(v.4.0.4), tzdb(v.0.2.0), enrichplot(v.1.14.1), xml2(v.1.3.3), httpuv(v.1.6.4), assertthat(v.0.2.1), viridis(v.0.6.2), xfun(v.0.29), tximport(v.1.22.0), hms(v.1.1.1), jquerylib(v.0.1.4), evaluate(v.0.14), promises(v.1.2.0.1), IHW(v.1.22.0), DEoptimR(v.1.0-9), fansi(v.0.5.0), restfulr(v.0.0.13), progress(v.1.2.2), caTools(v.1.18.2), dbplyr(v.2.1.1), igraph(v.1.2.10), DBI(v.1.1.2), geneplotter(v.1.72.0), htmlwidgets(v.1.5.4), purrr(v.0.3.4), ellipsis(v.0.3.2), crosstalk(v.1.2.0), dplyr(v.1.0.7), backports(v.1.4.1), annotate(v.1.72.0), biomaRt(v.2.50.1), vctrs(v.0.3.8), remotes(v.2.4.2), cachem(v.1.0.6), withr(v.2.4.3), ggforce(v.0.3.3), robustbase(v.0.93-9), vroom(v.1.5.7), GenomicAlignments(v.1.30.0), treeio(v.1.18.1), fdrtool(v.1.2.17), prettyunits(v.1.1.1), DOSE(v.3.20.1), ape(v.5.6), lazyeval(v.0.2.2), crayon(v.1.4.2), genefilter(v.1.76.0), edgeR(v.3.36.0), pkgconfig(v.2.0.3), slam(v.0.1-49), labeling(v.0.4.2), tweenr(v.1.0.2), nlme(v.3.1-153), pkgload(v.1.2.4), devtools(v.2.4.3), rlang(v.0.4.12), lifecycle(v.1.0.1), downloader(v.0.4), filelock(v.1.0.2), BiocFileCache(v.2.2.0), rprojroot(v.2.0.2), polyclip(v.1.10-0), graph(v.1.72.0), Matrix(v.1.3-4), aplot(v.0.1.1), lpsymphony(v.1.22.0), boot(v.1.3-28), processx(v.3.5.2), png(v.0.1-7), viridisLite(v.0.4.0), rjson(v.0.2.20), bitops(v.1.0-7), R.oo(v.1.24.0), KernSmooth(v.2.23-20), pander(v.0.6.4), Biostrings(v.2.62.0), blob(v.1.2.2), stringr(v.1.4.0), qvalue(v.2.26.0), readr(v.2.1.1), gridGraphics(v.0.5-1), scales(v.1.1.1), memoise(v.2.0.1), magrittr(v.2.0.1), plyr(v.1.8.6), gplots(v.3.1.1), zlibbioc(v.1.40.0), compiler(v.4.1.2), scatterpie(v.0.1.7), BiocIO(v.1.4.0), RColorBrewer(v.1.1-2), lme4(v.1.1-27.1), DESeq2(v.1.34.0), Rsamtools(v.2.10.0), cli(v.3.1.0), XVector(v.0.34.0), patchwork(v.1.1.1), ps(v.1.6.0), MASS(v.7.3-54), mgcv(v.1.8-38), tidyselect(v.1.1.1), stringi(v.1.7.6), highr(v.0.9), yaml(v.2.2.1), GOSemSim(v.2.20.0), locfit(v.1.5-9.4), ggrepel(v.0.9.1), grid(v.4.1.2), sass(v.0.4.0), fastmatch(v.1.1-3), tools(v.4.1.2), parallel(v.4.1.2), rstudioapi(v.0.13), foreach(v.1.5.1), gridExtra(v.2.3), farver(v.2.1.0), ggraph(v.2.0.5), digest(v.0.6.29), shiny(v.1.7.1), Rcpp(v.1.0.7), broom(v.0.7.10), later(v.1.3.0), httr(v.1.4.2), AnnotationDbi(v.1.56.2), colorspace(v.2.0-2), XML(v.3.99-0.8), fs(v.1.5.2), splines(v.4.1.2), RBGL(v.1.70.0), yulab.utils(v.0.0.4), PROPER(v.1.26.0), tidytree(v.0.3.6), graphlayouts(v.0.7.2), ggplotify(v.0.1.0), plotly(v.4.10.0), sessioninfo(v.1.2.2), xtable(v.1.8-4), jsonlite(v.1.7.2), nloptr(v.1.2.2.3), ggtree(v.3.2.1), tidygraph(v.1.2.0), corpcor(v.1.6.10), ggfun(v.0.0.4), R6(v.2.5.1), Vennerable(v.3.1.0.9000), pillar(v.1.6.4), htmltools(v.0.5.2), mime(v.0.12), glue(v.1.6.0), fastmap(v.1.1.0), minqa(v.1.2.4), clusterProfiler(v.4.2.1), BiocParallel(v.1.28.3), codetools(v.0.2-18), fgsea(v.1.20.0), pkgbuild(v.1.3.1), utf8(v.1.2.2), lattice(v.0.20-45), bslib(v.0.3.1), tibble(v.3.1.6), sva(v.3.42.0), pbkrtest(v.0.5.1), curl(v.4.3.2), gtools(v.3.9.2), zip(v.2.2.0), GO.db(v.3.14.0), openxlsx(v.4.2.5), survival(v.3.2-13), limma(v.3.50.0), rmarkdown(v.2.11), desc(v.1.4.0), munsell(v.0.5.0), DO.db(v.2.9), GenomeInfoDbData(v.1.2.7), iterators(v.1.0.13), variancePartition(v.1.24.0), reshape2(v.1.4.4) and gtable(v.0.3.0)

message(paste0("This is hpgltools commit: ", get_git_commit()))
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 1c414fc2f002f2eb5020f3753fa29439b55b8a33
## This is hpgltools commit: Tue Jan 18 14:27:47 2022 -0500: 1c414fc2f002f2eb5020f3753fa29439b55b8a33
message(paste0("Saving to ", savefile))
## Error in paste0("Saving to ", savefile): object 'savefile' not found
tmp <- sm(saveme(filename = savefile))
## Error in file.path(getwd(), directory, filename): object 'savefile' not found
## Use me to reload the data
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiMjAyMTEwIFJldmlzaXRpbmcgc29tZSBxdWVyaWVzIGFib3V0IHN0aW11bGF0aW9uIHJlc3BvbnNlcyBhdCA0LzgvMTIgaG91cnMiCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogcGFnZWQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIHdpZHRoOiAzMDAKICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKICBCaW9jU3R5bGU6Omh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgo8c3R5bGUgdHlwZSA9ICJ0ZXh0L2NzcyI+CmJvZHksIHRkIHsKICBmb250LXNpemU6IDE2cHg7Cn0KY29kZS5yewogIGZvbnQtc2l6ZTogMTZweDsKfQpwcmUgewogZm9udC1zaXplOiAxNnB4Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShocGdsdG9vbHMpCnR0IDwtIHNtKGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKSkKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAxMjAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3IgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoID0gOCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQgPSA4LAogICAgICAgICAgICAgICAgICAgICAgZHBpID0gOTYpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzID0gNCwKICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsID0gImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSkKdmVyIDwtICIyMDIxMTAiCnJ1bmRhdGUgPC0gZm9ybWF0KFN5cy5EYXRlKCksIGZvcm1hdCA9ICIlWSVtJWQiKQpybWRfZmlsZSA8LSBwYXN0ZTAoIjIwMjExMF9tb3NzZXJfc3RpbXVsYXRpb24uUm1kIikKbGlicmFyeShnZ3Bsb3QyKQpgYGAKCiMgSW50cm9kdWN0aW9uCgpEci4gTW9zc2VyIGFwcHJvYWNoZWQgdXMgd2l0aCBhIHF1ZXJ5IGFib3V0IHdoYXQgZ2VuZXMgYXJlIGNoYW5naW5nIGluCmh1bWFuIG1hY3JvcGhhZ2VzIHNob3J0bHkgYWZ0ZXIgc3RpbXVsYXRpb24uIFdlIGhhdmUgYSBjb3VwbGUvZmV3CmV4cGVyaW1lbnRzIHdoaWNoIG1heSBoZWxwIGFkZHJlc3MgdGhpcy4gIFRoZXJlZm9yZSwgSSB0aGluayBJIHdpbGwKY29weSBteSBtYXN0ZXIgc2FtcGxlIHNoZWV0IGFuZCBleHRyYWN0IG9ubHkgdGhlIH4yMCBzYW1wbGVzIHdoaWNoIGFyZQpyZWxldmFudCByYXRoZXIgdGhhbiByZWFkIGluIGFsbCB+NDAwIHNhbXBsZXMgYW5kIHN1YnNldCBkb3duIHRvIHRoZQoyMCBvZiBpbnRlcmVzdC4KCkhvd2V2ZXIsIHRoZSBzaGVldCBoZSBnYXZlIG1lIGhhcyBhIHN1YnNldCBvZiB0aGUgc2FtcGxlcyBmcm9tIHRoZXNlCmV4cGVyaW1lbnRzLCBJIHRoaW5rIEkgd2lsbCBrZWVwIHRoZW0gYWxsIGFuZCBzdWJzZXQgZG93biBpbiBjYXNlIGl0CnR1cm5zIG91dCB3ZSB3YW50IHRvIGNvbnNpZGVyIHNvbWUgb2YgdGhlbS4KCmBgYHtyIHNhbXBsZV9zaGVldH0Kc2FtcGxlX3NoZWV0IDwtICJzYW1wbGVfc2hlZXRzL21vc3Nlcl9zYW1wbGVzXzIwMjExMC54bHN4IgpmaWxlX2NvbHVtbiA8LSAiaGczODkxc2FsbW9uIgpgYGAKCiMgR2F0aGVyIGFubm90YXRpb24gZGF0YQoKYGBge3IgYW5ub3RhdGlvbnN9Cm1ldGFfaW5mbyA8LSBjaGVja19tZXRhZGF0YV95ZWFyKG1ldGFkYXRhID0gc2FtcGxlX3NoZWV0LCBjb2x1bW4gPSBmaWxlX2NvbHVtbikKCiMjIGhzX2Fubm90IDwtIGxvYWRfYmlvbWFydF9hbm5vdGF0aW9ucyh5ZWFyID0gbWV0YV9pbmZvW1sieWVhciJdXSwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJ3cml0ZT1UUlVFKSRhbm5vdGF0aW9uCmhzX2Fubm90IDwtIGxvYWRfYmlvbWFydF9hbm5vdGF0aW9ucyh5ZWFyID0gbWV0YV9pbmZvW1sieWVhciJdXSwgbW9udGggPSAxMCkkYW5ub3RhdGlvbgpyb3duYW1lcyhoc19hbm5vdCkgPC0gbWFrZS5uYW1lcygKICBwYXN0ZTAoaHNfYW5ub3RbWyJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiXV0sICIuIiwKICAgICAgICAgaHNfYW5ub3RbWyJ0cmFuc2NyaXB0X3ZlcnNpb24iXV0pLAogIHVuaXF1ZSA9IFRSVUUpCmhzX3R4X2dlbmUgPC0gaHNfYW5ub3RbLCBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiZW5zZW1ibF90cmFuc2NyaXB0X2lkIildCmhzX3R4X2dlbmVbWyJpZCJdXSA8LSByb3duYW1lcyhoc190eF9nZW5lKQpoc190eF9nZW5lIDwtIGhzX3R4X2dlbmVbLCBjKCJpZCIsICJlbnNlbWJsX2dlbmVfaWQiKV0KbmV3X2hzX2Fubm90IDwtIGhzX2Fubm90CnJvd25hbWVzKG5ld19oc19hbm5vdCkgPC0gbWFrZS5uYW1lcyhoc19hbm5vdFtbImVuc2VtYmxfZ2VuZV9pZCJdXSwgdW5pcXVlID0gVFJVRSkKYGBgCgojIENyZWF0ZSBleHByZXNzaW9uc2V0CgpJbmNsdWRpbmcgdGhlIHNhbXBsZXMgSSBkZWNpZGVkIHRvIGtlZXAgZnJvbSB0aGUgdHdvIGV4cGVyaW1lbnRzIGluCnF1ZXN0aW9uLCB0aGVyZSBhcmUgOTQgcmVtYWluaW5nIGluIHRoZXNlIGV4cGVyaW1lbnRzLgoKVGhlIGFjdHVhbCBzYW1wbGUgSURzIHdoaWNoIGFyZSBvZiBpbnRlcmVzdCBhcmU6CgoqIEthamFsJ3MgNGhyIE0tQ1NGIExQUyBzdGltdWxhdGVkOiBIUEdMMDkxNywgSFBHTDA5MTgsIEhQR0wwOTE5LCBIUEdMMDkyMCwKICBIUEdMMDkyMSAodGhlc2UgaGF2ZSB0aGUgJ3N0YXRlJyBjb2x1bW4gc2V0IHRvICdscHMnIGFuZCAnZXhwdF90aW1lJwogIHNldCB0byAndDRoJykKKiBNLUNTRiBMUFMgMTJociBzdGltdWxhdGVkOiBIUEdMMDkzMiwgSFBHTDA5MzMsIEhQR0wwOTM0LCBIUEdMMDkzNSwKICBIUEdMMDkzNiAodGhlc2UgaGF2ZSBzdGF0ZSBzZXQgdG8gJ2xwcycgYW5kIHRpbWUgdG8gJ3QxMmgnLgoqIE1lZGltbXVuZSBncm93biBleC12aXZvOiBIUEdMMDczMiwgSFBHTDA3NDEsIEhQR0wwNzMzLCBIUEdMMDc0MiwKICBIUEdMMDczNSwgSFBHTDA3NDQsIEhQR0wwNzM3LCBIUEdMMDc0NiwgSFBHTDA3MzksIGFuZCBIUEdMMDc0OAogICh0aGVzZSBoYXZlIHN0YXRlIHNldCB0byAndW5pbmZlY3RlZCcgYW5kIHRpbWUgYWNyb3NzIGEgcmFuZ2UgZnJvbQogIHQ0aC0+dDI0aCkuCgpgYGB7ciBleHByZXNzaW9uc2V0fQpzdGltdWxhdG9ycyA8LSBjcmVhdGVfZXhwdChzYW1wbGVfc2hlZXQsIGZpbGVfY29sdW1uPSJoZzM4OTFzYWxtb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm89bmV3X2hzX2Fubm90LCB0eF9nZW5lX21hcD1oc190eF9nZW5lKQoKIyMgUXVpY2sgY2hlY2sgdG8gc2VlIGlmIG15IGNoZWNrX21ldGFkYXRhX3llYXIgd29ya2VkCiMjIEkga25vdyBhIHByaW9yaSB0aGF0IEVOU0cwMDAwMDE2OTI0NSBoYXMgY2hhbmdlZCB2ZXJzaW9uIG11bHRpcGxlCiMjIHRpbWVzIHNpbmNlIDIwMTggYW5kIHRoYXQgaXQgd2FzIG5vdCBiZWluZyBpbmNsdWRlZCBpZiBJIHVzZSBhCiMjIG5ld2VyIHNldCBvZiBhbm5vdGF0aW9ucy4KIkVOU0cwMDAwMDE2OTI0NSIgJWluJSByb3duYW1lcyhleHBycyhzdGltdWxhdG9ycykpCiMjIFlBWQoKdGltZV9zdGF0ZSA8LSBwYXN0ZTAocERhdGEoc3RpbXVsYXRvcnMpW1siZXhwdHRpbWUiXV0sICJfIiwKICAgICAgICAgICAgICAgICAgICAgcERhdGEoc3RpbXVsYXRvcnMpW1sic3RhdGUiXV0pCnN0aW12MiA8LSBzZXRfZXhwdF9jb25kaXRpb25zKHN0aW11bGF0b3JzLCBmYWN0PXRpbWVfc3RhdGUpCmBgYAoKIyBCZWZvcmUgc3Vic2V0dGluZwoKSSB3YW50IHRvIGxvb2sgYXQgdGhlc2UgdHdvIGdyb3VwcyBvZiBzYW1wbGVzIHRvZ2V0aGVyIGJlZm9yZSBJIGZvY3VzCmluIG9uIHRoZSB0aW1lcy9zYW1wbGVzIHRoYXQgRHIuIE1vc3NlciBpcyBpbnRlcmVzdGVkIGluLiAgTXkKcmVhc29uaW5nOiBJIHNob3VsZCBiZSBhYmxlIHRvIHRlbGwgaWYgdGhleSBhcmUgcGF0aG9sb2dpY2FsbHkgYmF0Y2hlZAptb3JlIGVhc2lseSBub3cgdGhhbiBhZnRlciB0YWtpbmcgYSBidW5jaCBvZiBzYW1wbGVzIGF3YXkuCgpgYGB7ciBwcmVfc3Vic2V0fQp0aW1lX2ZhY3RvciA8LSBmYWN0b3IocERhdGEoc3RpbXYyKVtbImV4cHR0aW1lIl1dLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWMoInQwaCIsICJ0NGgiLCAidDZoIiwgInQ4aCIsICJ0MTJoIiwgInQyNGgiLCAidDQ4aCIpKQpwRGF0YShzdGltdjIpW1siZXhwdHRpbWUiXV0gPC0gdGltZV9mYWN0b3IKCnN0aW1fbm9ybSA8LSBub3JtYWxpemVfZXhwdChzdGltdjIsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFKQpwbG90X3BjYShzdGltX25vcm0sIHNpemVfY29sdW1uPSJleHB0dGltZSIsIHBsb3RfbGFiZWxzPUZBTFNFKSRwbG90CgpzdGltX25iIDwtIG5vcm1hbGl6ZV9leHB0KHN0aW12Miwgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iLCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKQpwbG90X3BjYShzdGltX25iLCBzaXplX2NvbHVtbj0iZXhwdHRpbWUiLCBwbG90X2xhYmVscz1GQUxTRSkkcGxvdApgYGAKCk9rLCBzbyBpdCB0YWtlcyBhIHdoaWxlIG9mIHN0YXJpbmcgYXQgaXQgdG8gZ2V0IGEgc2Vuc2Ugb2Ygd2hhdCBpcwpnb2luZyBvbiwgYnV0IEkgdGhpbmsgaXQgaXMgZXZlbnR1YWxseSBwcmV0dHkgY2xlYXIgdGhhdCB0aGUgdmFyaW91cwpvdGhlciBzdGltdWxhdGlvbiB0eXBlcyBhcmUgY29uZnVzaW5nIHRoaW5ncyBwcmV0dHkgc2lnbmlmaWNhbnRseS4KCmBgYHtyIHN1YnNldH0Kc3RpbXYzIDwtIHN0aW12MiAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9ImV4cHR0aW1lIT0ndDBoJyIpICU+JQogIHN1YnNldF9leHB0KHN1YnNldD0iZXhwdHRpbWUhPSd0NmgnIikgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0PSJleHB0dGltZSE9J3Q0OGgnIikgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0PSJzdGF0ZSE9J2xwc2FkbyciKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9InN0YXRlIT0nbHBzcGdlJyIpICU+JQogIHN1YnNldF9leHB0KHN1YnNldD0ic3RhdGUhPSdpbDQnIikKCnBEYXRhKHN0aW12MylbLCBjKCJzYW1wbGVpZCIsICJleHB0dGltZSIsICJjb25kaXRpb24iKV0KCnRpbWVfc3RhdGUgPC0gcGFzdGUwKHBEYXRhKHN0aW12MylbWyJleHB0dGltZSJdXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICBwRGF0YShzdGltdjMpW1sic3RhdGUiXV0pCnN0aW12MyA8LSBzZXRfZXhwdF9jb25kaXRpb25zKHN0aW12MywgZmFjdD10aW1lX3N0YXRlKQoKc3RpbXYzX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoc3RpbXYzLCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLCBub3JtPSJxdWFudCIsIGZpbHRlcj1UUlVFKQpwbG90X3BjYShzdGltdjNfbm9ybSwgcGxvdF9sYWJlbHM9RkFMU0UpJHBsb3QKCnN0aW12M19uYiA8LSBub3JtYWxpemVfZXhwdChzdGltdjMsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUsIGJhdGNoPSJzdmFzZXEiKQpwbG90X3BjYShzdGltdjNfbmIpJHBsb3QKcGxvdF9wY2Eoc3RpbXYzX25iLCBzaXplX2NvbHVtbj0iZXhwdHRpbWUiKSRwbG90CmBgYAoKIyBTbWFsbGVzdCBncm91cAoKQWZ0ZXIgYSBjb252ZXJzYXRpb24gd2l0aCBOYWppYiwgaGUgc3VnZ2VzdGVkIHdvcmtpbmcgd2l0aCBhIHZlcnkKbGltaXRlZCBzZXQgb2YgNCBhbmQgOCBob3VyIHNhbXBsZXMsIHByb2JhYmx5IGV4Y2x1c2l2ZWx5IGZyb20gdGhlCm1lZGltbXVuZSBleHBlcmltZW50LgoKYGBge3Igc21hbGxlcn0Kc3RpbXY0IDwtIHN0aW12MyAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9ImV4cHR0aW1lPT0ndDRoJ3xleHB0dGltZT09J3Q4aCciKQoKc3RpbXY0X25vcm0gPC0gbm9ybWFsaXplX2V4cHQoc3RpbXY0LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLCBub3JtPSJxdWFudCIsIGZpbHRlcj1UUlVFKQpwbG90X3BjYShzdGltdjRfbm9ybSkkcGxvdAoKc3RpbXY0X25iIDwtIG5vcm1hbGl6ZV9leHB0KHN0aW12NCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwgbm9ybT0icXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKQpwbG90X3BjYShzdGltdjRfbmIpJHBsb3QKYGBgCgojIyBDb25zaWRlciBvbmx5IDQgYW5kIDEyIGhvdXJzCgpgYGB7ciBhbm90aGVyX3NtYWxsZXJ9CnN0aW12NDEyIDwtIHN0aW12MyAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9ImV4cHR0aW1lPT0ndDRoJ3xleHB0dGltZT09J3QxMmgnIikKCnN0aW12NDEyX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoc3RpbXY0MTIsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpCnBsb3RfcGNhKHN0aW12NDEyX25vcm0pJHBsb3QKCnN0aW12NDEyX25iIDwtIG5vcm1hbGl6ZV9leHB0KHN0aW12NDEyLCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLCBub3JtPSJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkKcGxvdF9wY2Eoc3RpbXY0MTJfbmIpJHBsb3QKCnN0X2ZpbHQgPC0gbm9ybWFsaXplX2V4cHQoc3RpbXY0MTIsIGZpbHRlcj0ic2ltcGxlIikKaW5pdGlhbCA8LSBhbGxfcGFpcndpc2UoCiAgICBzdF9maWx0LCBtb2RlbF9iYXRjaD1UUlVFLCBmb3JjZT1UUlVFLAogICAgZXh0cmFfY29udHJhc3RzPSJ0MTJ2NF9scHN2dW5pbmY9KHQxMmhfbHBzLXQxMmhfdW5pbmZlY3RlZCktKHQ0aF9scHMtdDRoX3VuaW5mZWN0ZWQpIikKCmtlZXBlcnMgPC0gbGlzdCgKICAgICIxMnY0X3VuaW5mZWN0ZWQiID0gYygidDEyaF91bmluZmVjdGVkIiwgInQ0aF91bmluZmVjdGVkIiksCiAgICAiMTJ2NF9scHMiID0gYygidDEyaF9scHMiLCAidDRoX2xwcyIpLAogICAgImxwc3Z1bmluZl80aHIiID0gYygidDRoX2xwcyIsICJ0NGhfdW5pbmZlY3RlZCIpLAogICAgImxwc3Z1bmluZl8xMmhyIiA9IGMoInQxMmhfbHBzIiwgInQxMmhfdW5pbmZlY3RlZCIpLAogICAgInQxMnY0X2xwc3Z1bmluZiIgPSBOVUxMKQpmdW5reXRvd24gPC0gY29tYmluZV9kZV90YWJsZXMoaW5pdGlhbCwga2VlcGVycz1rZWVwZXJzLCBleGNlbD0ibHBzX3ZzX2luZmVjdGVkLnhsc3giKQpgYGAKClRha2UgdG9wIG4gZ2VuZXMgZnJvbSBMUFN2TlMgYXQgNCBob3VycywgcGxvdCB0aGVpciBhYnVuZGFuY2UgYXQgNCBhbmQKMTIgaG91cnMgYXMgYSBzY2F0dGVyIHBsb3QuCgpgYGB7ciB0b3BuXzR0bzEyfQp0b3BuIDwtIDUwCgp0NGhyX3N0YXJ0IDwtIGZ1bmt5dG93bltbImRhdGEiXV1bWyJscHN2dW5pbmZfNGhyIl1dCmRlc2NlbmRpbmdfaWR4IDwtIG9yZGVyKHQ0aHJfc3RhcnRbWyJlZGdlcl9sb2dmYyJdXSwgZGVjcmVhc2luZyA9IFRSVUUpCnQ0aHJfc3RhcnQgPC0gdDRocl9zdGFydFtkZXNjZW5kaW5nX2lkeCwgXQoKdDEyaHJfc3RhcnQgPC0gZnVua3l0b3duW1siZGF0YSJdXVtbImxwc3Z1bmluZl8xMmhyIl1dCnQxMmhyX3N0YXJ0IDwtIHQxMmhyX3N0YXJ0W2Rlc2NlbmRpbmdfaWR4LCBdCgp0b3BuXzRociA8LSBoZWFkKHQ0aHJfc3RhcnQsIG49dG9wbikKdG9wbl8xMmhyIDwtIGhlYWQodDEyaHJfc3RhcnQsIG49dG9wbikKCmNvbWJpbmVkIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQodG9wbl80aHJbWyJlZGdlcl9sb2dmYyJdXSwgdG9wbl8xMmhyW1siZWRnZXJfbG9nZmMiXV0pKQpyb3duYW1lcyhjb21iaW5lZCkgPC0gbWFrZS5uYW1lcyhoZWFkKHQxMmhyX3N0YXJ0W1siaGduY3N5bWJvbCJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuPXRvcG4pLCB1bmlxdWU9VFJVRSkKCnBsb3R0ZWQgPC0gcGxvdF9zY2F0dGVyKGNvbWJpbmVkKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMTIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMTIpKSArCiAgZ2dwbG90Mjo6Z2VvbV9hYmxpbmUoc2xvcGU9MSwgaW50ZXJjZXB0PTApCgojIyBnZ3Bsb3RseShwbG90dGVkKQoKYWxsIDwtIGdncGx0KHBsb3R0ZWQsIGZpbGVuYW1lPSJmaWZ0eV9nZW5lcy5odG1sIikKYGBgCgojIyBDb21wYXJpbmcgdG8gRHIuIE1vc3NlcidzIHByZXZpb3VzIHRhYmxlCgpEci4gTW9zc2VyIHByb3ZpZGVkIG1lIGEgdGFibGUgb2YgcHJldmlvdXMgcmVzdWx0cywgdGhlIGZpcnN0IHR3bwpnZW5lcyBsaXN0ZWQgYXJlIENYQ0wxMCBhbmQgQ1hDTDExIChFTlNHMDAwMDAxNjkyNDUgYW5kIDE2OTI0OCkuICBJIGFtCm5vdCBmaW5kaW5nIHRoZXNlIHR3byBnZW5lcyBpbiBhbnkgb2YgbXkgcmVzdWx0IHRhYmxlcy4gIEkgdGhpbmsgdGhleQpnb3QgZmlsdGVyZWQgb3V0LCBldmVuIHdoZW4gSSB1c2UgYSBsZXNzIHJlc3RyaWN0aXZlIGZpbHRlci4gIExldCB1cwp0cnkgdG8gdW5kZXJzdGFuZCB3aGF0IGlzIGdvaW5nIG9uLgoKYGBge3IgY3hjbF9odW50fQoiRU5TRzAwMDAwMTY5MjQ1IiAlaW4lIHJvd25hbWVzKGV4cHJzKHN0aW12NDEyKSkKIyMgSG1tIG9rLi4uCm5hbWVzIDwtIGZEYXRhKHN0aW12NDEyKVtbImhnbmNfc3ltYm9sIl1dCmN4Y2xfbmFtZXMgPC0gZ3JlcChwYXR0ZXJuPSJDWENMIiwgeD1uYW1lcykKbmFtZXNbY3hjbF9uYW1lc10KCiMjIFNvLCBkb2VzIHRoaXMgbWVhbiB0aGF0IHNvbWV0aGluZyBjaGFuZ2VkIHdpdGggdGhlIGFubm90YXRpb25zIHN1Y2gKIyMgdGhhdCBDWENMMTAgaXMgbm8gbG9uZ2VyIGluY2x1ZGVkLCBvciB3YXMgaXQgbm90IGluY2x1ZGVkIGluIHRoZQojIyBzYWxtb24gbWFwcGluZz8gIFdlbGwsIEkgc3RpbGwgaGF2ZSBteSBhbm5vdGF0aW9ucyBsb2FkZWQsIGxldHMKIyMgY2hlY2sgdGhlcmUgZmlyc3QuLi4KbmFtZXMgPC0gaHNfYW5ub3RbWyJoZ25jX3N5bWJvbCJdXQpjeGNsX25hbWVzIDwtIGdyZXAocGF0dGVybj0iQ1hDTCIsIHg9bmFtZXMpCm5hbWVzW2N4Y2xfbmFtZXNdCiMjIG9rLCBzbyB0aGUgc2FsbW9uIHF1YW50aWZpY2F0aW9uIGRpZCBub3QgaW5jbHVkZSBDWENMMTAuCgojIyBMZXRzIGxvb2sgYXQgdGhlIHNhbG1vbiB0YWJsZXMuLi4KIyMgSSBzZWUgdGhhdCBDWENMMTAgaGFzIDEgdHJhbnNjcmlwdDogRU5TVDAwMDAwMzA2NjAyLjMKIyMgTG9va2luZyBhdCBvbmUgb2YgdGhlIHJlbGV2YW50IGNvdW50IHRhYmxlcyAoaHBnbDA5NjgpIGZvciBoZzM4Xzk5LAojIyBJIHNlZSB0aGF0IHRoaXMgdHJhbnNjcmlwdCB3YXMgaW5jbHVkZWQgKGJ1dCB3aXRoIDAgY291bnRzKS4KIyMgTG9va2luZyBhdCBvdGhlciBzYW1wbGVzLCBJIHNlZSB0aGF0IGl0IHdhcyBvYnNlcnZlZCBhIHNtYWxsIG51bWJlcgojIyBvZiB0aW1lcyAtLSBidXQgaXQgZGVmaW5pdGVseSBfd2FzXyBpbmNsdWRlZC4KCiMjIExldCB1cyBjaGVjayB0aGF0IHRoZSB0eF9nZW5lX21hcCBpcyBvay4uLgoiRU5TVDAwMDAwMzA2NjAyLjMiICVpbiUgcm93bmFtZXMoaHNfdHhfZ2VuZSkKIyMgb2ssIHNvIGl0IGlzIGRlZmluaXRlbHkgdGhlcmUsIGRvdWJsZS1jaGVjayB0aGUgYW5ub3RhdGlvbnMuCiJFTlNHMDAwMDAxNjkyNDUiICVpbiUgcm93bmFtZXMobmV3X2hzX2Fubm90KQoKc3RpbXVsYXRvcnMgPC0gY3JlYXRlX2V4cHQoc2FtcGxlX3NoZWV0LCBmaWxlX2NvbHVtbj0iaGczODkxc2FsbW9uIikKIkVOU1QwMDAwMDMwNjYwMi4yIiAlaW4lIHJvd25hbWVzKGV4cHJzKHN0aW11bGF0b3JzKSkKYGBgCgojIyBDb21wYXJlIDEyIGhvdXIgc3VidHJhY3Rpb24gdG8gNCBob3VyCgpgYGB7ciBjb21wYXJlX2NvbnRyYXN0c30KdDEyaHJfZGYgPC0gZnVua3l0b3duW1siZGF0YSJdXVtbImxwc3Z1bmluZl8xMmhyIl1dCnQ0aHJfZGYgPC0gZnVua3l0b3duW1siZGF0YSJdXVtbImxwc3Z1bmluZl80aHIiXV0KCmNwbV9kZiA8LSBtZXJnZSh0MTJocl9kZiwgdDRocl9kZiwgYnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKGNwbV9kZikgPC0gbWFrZS5uYW1lcyhjcG1fZGZbWyJoZ25jc3ltYm9sLngiXV0sIHVuaXF1ZT1UUlVFKQpjcG1fZGZbWyJSb3cubmFtZXMiXV0gPC0gTlVMTAoKdGVzdCA8LSBwbG90X3NjYXR0ZXIoY3BtX2RmWywgYygiZGVzZXFfbG9nZmMueCIsICJkZXNlcV9sb2dmYy55IildKQpgYGAKCiMgQ2xhcmlmaWNhdGlvbgoKVGFrZSB0aGUgdG9wLW4gbW9zdCBpbmNyZWFzZWQgZ2VuZXMgYXQgNCBob3VycyBhZnRlciBMUFMgc3RpbXVsYXRpb24uCkdpdmVuIHRoaXMgc2V0LCBhc2sgdGhlIHF1ZXN0aW9uOiB3aGF0IGhhcHBlbmVkIHRvIHRoZW0/CgpPbmUgd2F5IHRvIHByb3ZpZGUgdGhpcyBhbnN3ZXIgaXMgdG8gcHVsbCBvdXQgdGhlaXIgYXZlcmFnZSBjcG0vcnBrbQp2YWx1ZXMgYXQgZWFjaCBvZiB0aGUgNCByZWxldmFudCB0aW1lcy9jb25kaXRpb25zIGFuZCBtYWtlIGEgdGFibGUuCgpgYGB7ciBscHNfZmF0ZXN9CnRvcG4gPC0gMTAwCmxwc19vcmRlciA8LSBvcmRlcih0NGhyX2RmW1siZGVzZXFfbG9nZmMiXV0sIGRlY3JlYXNpbmc9VFJVRSkKbHBzX3Jlb3JkZXJlZCA8LSBoZWFkKHQ0aHJfZGZbbHBzX29yZGVyLCBdLCBuPXRvcG4pCgppZHNfb2ZfaW50ZXJlc3QgPC0gcm93bmFtZXMobHBzX3Jlb3JkZXJlZCkKYW5ub3RfaW50ZXJlc3QgPC0gbHBzX3Jlb3JkZXJlZFssIGMoImhnbmNzeW1ib2wiLCAiZGVzY3JpcHRpb24iKV0KCiMjIFdlIGNhbiBjaGVhdCBhIGxpdHRsZSBhbmQgZ2V0IHRoZSBhdmVyYWdlIGNwbSBqdXN0IHRvIGdldCBhbiBpbml0aWFsIHNlbnNlCnQ0aF9scHN2Y29udHJvbF9jcG0gPC0gbHBzX3Jlb3JkZXJlZFssIGMoImJhc2ljX251bW1lZCIsICJiYXNpY19kZW5tZWQiKV0KdDEyaF9scHN2Y29udHJvbF9jcG0gPC0gdDEyaHJfZGZbaWRzX29mX2ludGVyZXN0LCBjKCJiYXNpY19udW1tZWQiLCAiYmFzaWNfZGVubWVkIildCgpjb21iaW5lZF9scHN2Y29udHJvbCA8LSBtZXJnZSh0NGhfbHBzdmNvbnRyb2xfY3BtLCB0MTJoX2xwc3Zjb250cm9sX2NwbSwgYnk9InJvdy5uYW1lcyIpCmNvbWJpbmVkX2xwc3Zjb250cm9sIDwtIG1lcmdlKGFubm90X2ludGVyZXN0LCBjb21iaW5lZF9scHN2Y29udHJvbCwgYnkueD0icm93Lm5hbWVzIiwgYnkueT0iUm93Lm5hbWVzIikKY29sbmFtZXMoY29tYmluZWRfbHBzdmNvbnRyb2wpIDwtIGMoInJvd25hbWVzIiwgImhnbmNzeW1ib2wiLCAiZGVzY3JpcHRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidDRoX2xwcyIsICJ0NGhfY29udHJvbCIsICJ0MTJoX2xwcyIsICJ0MTJoX2NvbnRyb2wiKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goY29tYmluZWRfbHBzdmNvbnRyb2wsIGV4Y2VsPSJjcG1fbHBzdmNvbnRyb2xfdDRodnQxMmgueGxzeCIpCmBgYAoKCgpgYGB7ciBzbWFsbGVzdH0Kd2FudGVkIDwtIGMoImhwZ2wwNzMyIiwgImhwZ2wwNzQxIiwgImhwZ2wwNzMzIiwgImhwZ2wwNzQyIiwgImhwZ2wwNzM0IiwgImhwZ2wwNzQzIiwgImhwZ2wwNzM1IiwgImhwZ2wwNzQ0IikKc3RpbXY1IDwtIHN0aW12MiAlPiUKICBzdWJzZXRfZXhwdChpZHM9d2FudGVkKQoKc3RpbXY1X25vcm0gPC0gbm9ybWFsaXplX2V4cHQoc3RpbXY1LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLCBub3JtPSJxdWFudCIsIGZpbHRlcj1UUlVFKQpwbG90X3BjYShzdGltdjVfbm9ybSkkcGxvdApgYGAKCmBgYHtyIHNhdmVtZX0KcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKbWVzc2FnZShwYXN0ZTAoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkpCm1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgc2F2ZWZpbGUpKQp0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpKQpgYGAKCmBgYHtyIGxvYWRtZSwgZXZhbD1GQUxTRX0KIyMgVXNlIG1lIHRvIHJlbG9hZCB0aGUgZGF0YQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpCmBgYAo=