##################################################################################
##### DESeq2 R script for Differential Expression using pairwise comparisons #####
##################################################################################
## Set working directory
setwd("/Users/kuroko/Dropbox (Partners HealthCare)/Weinstock NTC Collab/Experiments/TCL Cell Lines/Data/ALCL/Full R project scripts")
getwd()
[1] "/Users/kuroko/Dropbox (Partners HealthCare)/Weinstock NTC Collab/Experiments/TCL Cell Lines/Data/ALCL/Full R project scripts"
## Before running this script start by transferring the necessary files to the working directory set above:
# All .out.bam files: these were generated from the NTC standard pipeline
# .gtf file with annotations of genome of interest: can be downloaded from multiple sources; or there are dedicated R packages
## Load DESeq2 and Rsubread packages
library(DESeq2) # Loads DESeq2 package
library(Rsubread) # Loads Rsubread package (counts fragments for each feature)
library(tidyverse) # Loads tidyverse which allows various convenient data manipulations
library(RColorBrewer)
library(pheatmap)
library(ggplot2)
library(ggrepel)
library(EnhancedVolcano)
library(ggpubr)
### featureCount steps performed on O2 to avoid having to make local copies of .sam files
### shell script used to run feature count ###
# Import gene body counts table generated in O2 into R
fc <- read.table("PRO_ALCL_featurecounts", sep="\t", header=TRUE, row.names=1)
# Import SAF file for later use mapping tx_id to gene names. convert to tibble. If you are able to get annotation from your counts table, this may not be necessary.
#gtf <- read.table(".gtf", sep = "\t", header = TRUE, row.names=1)
### Give nice names to the columns in counts
# Store original colnames
#orig_names <- colnames(fc)
### Renaming columns. This is really inelegant but it worked. Depending on naming, may need to adjust trim length.
# Trim 38 char from left side, delete "_sorted.sam" from right, replace . with _
#new_sample_colnames <- str_sub(colnames(fc), 29, str_length(colnames(fc))) %>% str_replace("_sorted.sam","") %>% str_replace("\\.","_")
#names_col1_5 <- colnames(fc)[1:5] # save the names of columns 1-5
#new_names <- c(names_col1_5, new_sample_colnames[6:length(new_sample_colnames)]) # combine names of cols 1-5 with shortened samples names
#new_names
#colnames(fc) <- new_names # replace old column names with new names
colnames(fc)[6:14] <- c("KARAS299", "L82", "SUPM2", "SUDHL1", "KIJK", "SR786", "FEPD", "DL40", "MAC2A")
colnames(fc) # check names
[1] "Chr" "Start" "End" "Strand" "Length" "KARAS299" "L82" "SUPM2" "SUDHL1"
[10] "KIJK" "SR786" "FEPD" "DL40" "MAC2A"
### Create metadata object to categorize samples:
metadata <- data.frame(row.names = colnames(fc[, 6:ncol(fc)]),
subtype = c(rep("ALK_positive",6),rep("ALK_negative",3))
) # genotype+timepoint, used for DEseq conditions
metadata # verify the table looks ok
#confirm that row and column names match
all(rownames(metadata) %in% colnames(fc))
[1] TRUE
all(rownames(metadata) == colnames(fc)[6:ncol(fc)])
[1] TRUE
## Create DESeq Data Set from the count table, and sample list:
dds <- DESeqDataSetFromMatrix(countData = fc[, 6:ncol(fc)], # the matrix of counts from featureCounts;
colData = metadata, # the sample table created in the last step;
design= ~subtype) # determine what value you'd like DEseq to compare
Warning in DESeqDataSet(se, design = design, ignoreRank) :
some variables in design formula are characters, converting to factors
dds <- estimateSizeFactors(dds)
deseq_sizes <- as.data.frame(sizeFactors(dds))
deseq_sizes
keep <- rowMax(counts(dds, normalize=TRUE)) >= 20
dds <- dds[keep,]
saveRDS(dds, file="ALCL_DEseq_dds.rds")
#dREG_readFilt <- dREG[dREG$dREGpeakID %in% rownames(dds),]
#write.table(dREG_readFilt, file="dREGpeaks.readFilt.bed", sep="\t", col.names=FALSE, row.names=FALSE,
# quote=FALSE)
# sizeFactors(dds) <- spike_factors
## Estimate and plot dispersions for standard normalization DESeq data set:
dds <- estimateDispersions(dds)
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
pdf("Dispersion_ALCL.pdf")
plotDispEsts(dds)
# check results of normalization
colSums(counts(dds)) # raw read counts per sample
KARAS299 L82 SUPM2 SUDHL1 KIJK SR786 FEPD DL40 MAC2A
27955213 11405038 6390226 7076909 8115871 8363398 7897084 5772651 14835319
colSums(counts(dds, normalized=T)) # Total number of normalized counts per sample
KARAS299 L82 SUPM2 SUDHL1 KIJK SR786 FEPD DL40 MAC2A
9735115 9581010 8993572 9074870 9153605 9419018 8840723 8847171 10752376
data.frame(colSums(counts(dds)), (colSums(counts(dds, normalized=T))), row.names=colnames(counts(dds)))
# For these samples, spike ratios are close so DEseq2 normalization will be used.
#run DESeq
dds <- DESeq(dds)
using pre-existing size factors
estimating dispersions
found already estimated dispersions, replacing these
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
dds <- nbinomWaldTest(dds) # Wald test for differential expression
found results columns, replacing these
# user requested comparisons
# ALK+ v. ALK-
# create results objects for each requested contrast
res_neg_v_pos <- results(dds, contrast = c("subtype","ALK_negative","ALK_positive"), alpha = 0.01)
# Calculate mean normalized counts for each condition
AvgNorm_pos <- as.data.frame(counts(dds, normalized = TRUE)) %>% select(contains("ALK_positive")) %>% rowMeans(.)
AvgNorm_neg <- as.data.frame(counts(dds, normalized = TRUE)) %>% select(contains("ALK_negative")) %>% rowMeans(.)
# extract gene names from saf annotation file
#geneNames <- dplyr::select(row.names(fc), c("EnsemblID"))
# Start to build results tables
# Results table for comparisons
resTable <- data.frame("EnsemblID"=as.data.frame(rownames(dds)))
#resTable$geneNames <- geneNames$GeneName
resTable$AvgNormCounts_ALK_positive <- AvgNorm_pos
resTable$AvgNormCounts_ALK_negative <- AvgNorm_neg
resTable$baseMean <- as.data.frame(res_neg_v_pos)$baseMean
# VS positive
resTable$log2FoldChange_neg_v_pos <- as.data.frame(res_neg_v_pos)$log2FoldChange
resTable$log2fcSE_neg_v_pos <- as.data.frame(res_neg_v_pos)$lfcSE
resTable$pvalue_neg_v_pos <- as.data.frame(res_neg_v_pos)$pvalue
resTable$padj_neg_v_pos <- as.data.frame(res_neg_v_pos)$padj
# Write data tables to text files
write.csv(counts(dds, normalized=FALSE), file="ALK_positive_and_negative_WholeGene_raw_counts.csv")
write.csv(counts(dds, normalized=TRUE), file="ALK_positive_and_negative_DEseq2normalized_counts.csv")
write_tsv(resTable,"ALCL_results.txt",
append = FALSE,
col_names = TRUE,
na = "NA"
)
#### PLOTS ####
# EnhancedVolcano plots
ProjectName <- "PROseq_ALCL"
padjCutoff <- 1e-6
FCcutoff <- 1.32
pdf("ALCL_volcano.pdf")
EnhancedVolcano(res_neg_v_pos,
lab = resTable$rownames.dds.,
title = '_',
x = 'log2FoldChange',
y = 'padj',
#xlim = c(-6,6),
xlab = bquote(~Log[2]~ 'fold change'),
ylab = bquote('-'~Log[10]~ 'adj p-val'),
pCutoff = padjCutoff,
FCcutoff = FCcutoff,
pointSize = 1.0,
labSize = 2.0,
colAlpha = 0.5,
legendPosition = 'right',
legendLabSize = 6,
legendIconSize = 3.0,
drawConnectors = TRUE,
widthConnectors = 0.2,
colConnectors = 'grey30')
Warning: ggrepel: 93 unlabeled data points (too many overlaps). Consider increasing max.overlaps
## MA plots
# vs positive
pdf("ALCL_MA.pdf")
DESeq2::plotMA(res_neg_v_pos, alpha = 0.01, main = "_")
# plotDispEsts(dds)
vsd<-vst(dds,blind=FALSE)
rld<-rlog(dds,blind=FALSE)
pdf("ALCL_PCA.pdf")
plotPCA(vsd, intgroup=c("subtype")) #same as before for analysis
# distance plot
sampleDists<-dist(t(assay(vsd)))
sampleDistMatrix<-as.matrix(sampleDists)
#row.names(sampleDistMatrix)<-paste(vsd$subtype, rep, sep="_")
colnames(sampleDistMatrix)<-NULL
colors <- colorRampPalette(rev(brewer.pal(9,"Blues")))(255)
pheatmap(sampleDistMatrix, col=colors, border_color=NA, show_colnames=FALSE, show_rownames=TRUE)
sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Big Sur 11.6
Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] parallel stats4 stats graphics grDevices utils datasets methods base
other attached packages:
[1] ggpubr_0.4.0 EnhancedVolcano_1.10.0 ggrepel_0.9.1
[4] pheatmap_1.0.12 RColorBrewer_1.1-2 forcats_0.5.1
[7] stringr_1.4.0 dplyr_1.0.7 purrr_0.3.4
[10] readr_2.1.1 tidyr_1.1.4 tibble_3.1.6
[13] ggplot2_3.3.5 tidyverse_1.3.1 Rsubread_2.6.4
[16] DESeq2_1.32.0 SummarizedExperiment_1.22.0 Biobase_2.52.0
[19] MatrixGenerics_1.4.3 matrixStats_0.61.0 GenomicRanges_1.44.0
[22] GenomeInfoDb_1.28.4 IRanges_2.26.0 S4Vectors_0.30.2
[25] BiocGenerics_0.38.0
loaded via a namespace (and not attached):
[1] ggbeeswarm_0.6.0 colorspace_2.0-2 ggsignif_0.6.3 ellipsis_0.3.2
[5] XVector_0.32.0 fs_1.5.2 rstudioapi_0.13 farver_2.1.0
[9] bit64_4.0.5 AnnotationDbi_1.54.1 fansi_0.5.0 lubridate_1.8.0
[13] xml2_1.3.3 splines_4.1.1 extrafont_0.17 cachem_1.0.6
[17] geneplotter_1.70.0 knitr_1.36 jsonlite_1.7.2 broom_0.7.10
[21] Rttf2pt1_1.3.9 annotate_1.70.0 dbplyr_2.1.1 png_0.1-7
[25] compiler_4.1.1 httr_1.4.2 backports_1.4.1 assertthat_0.2.1
[29] Matrix_1.4-0 fastmap_1.1.0 cli_3.1.0 htmltools_0.5.2
[33] tools_4.1.1 gtable_0.3.0 glue_1.5.1 GenomeInfoDbData_1.2.6
[37] maps_3.4.0 Rcpp_1.0.7 carData_3.0-4 cellranger_1.1.0
[41] jquerylib_0.1.4 vctrs_0.3.8 Biostrings_2.60.2 ggalt_0.4.0
[45] extrafontdb_1.0 xfun_0.29 rvest_1.0.2 lifecycle_1.0.1
[49] rstatix_0.7.0 XML_3.99-0.8 zlibbioc_1.38.0 MASS_7.3-54
[53] scales_1.1.1 vroom_1.5.7 hms_1.1.1 proj4_1.0-10.1
[57] yaml_2.2.1 memoise_2.0.1 ggrastr_1.0.1 stringi_1.7.6
[61] RSQLite_2.2.9 genefilter_1.74.1 BiocParallel_1.26.2 rlang_0.4.12
[65] pkgconfig_2.0.3 bitops_1.0-7 evaluate_0.14 lattice_0.20-45
[69] labeling_0.4.2 bit_4.0.4 tidyselect_1.1.1 magrittr_2.0.1
[73] R6_2.5.1 generics_0.1.1 DelayedArray_0.18.0 DBI_1.1.1
[77] pillar_1.6.4 haven_2.4.3 withr_2.4.3 abind_1.4-5
[81] survival_3.2-13 KEGGREST_1.32.0 RCurl_1.98-1.5 ash_1.0-15
[85] car_3.0-12 modelr_0.1.8 crayon_1.4.2 KernSmooth_2.23-20
[89] utf8_1.2.2 tzdb_0.2.0 rmarkdown_2.11 locfit_1.5-9.4
[93] grid_4.1.1 readxl_1.3.1 blob_1.2.2 reprex_2.0.1
[97] digest_0.6.29 xtable_1.8-4 munsell_0.5.0 beeswarm_0.4.0
[101] vipor_0.4.5
LS0tCnRpdGxlOiAiUFJPIEFMQ0wgREVzZXEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIERFU2VxMiBSIHNjcmlwdCBmb3IgRGlmZmVyZW50aWFsIEV4cHJlc3Npb24gdXNpbmcgcGFpcndpc2UgY29tcGFyaXNvbnMgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyMgU2V0IHdvcmtpbmcgZGlyZWN0b3J5CnNldHdkKCIvVXNlcnMva3Vyb2tvL0Ryb3Bib3ggKFBhcnRuZXJzIEhlYWx0aENhcmUpL1dlaW5zdG9jayBOVEMgQ29sbGFiL0V4cGVyaW1lbnRzL1RDTCBDZWxsIExpbmVzL0RhdGEvQUxDTC9GdWxsIFIgcHJvamVjdCBzY3JpcHRzIikKZ2V0d2QoKQoKIyMgQmVmb3JlIHJ1bm5pbmcgdGhpcyBzY3JpcHQgc3RhcnQgYnkgdHJhbnNmZXJyaW5nIHRoZSBuZWNlc3NhcnkgZmlsZXMgdG8gdGhlIHdvcmtpbmcgZGlyZWN0b3J5IHNldCBhYm92ZToKIyBBbGwgLm91dC5iYW0gZmlsZXM6IHRoZXNlIHdlcmUgZ2VuZXJhdGVkIGZyb20gdGhlIE5UQyBzdGFuZGFyZCBwaXBlbGluZQojIC5ndGYgZmlsZSB3aXRoIGFubm90YXRpb25zIG9mIGdlbm9tZSBvZiBpbnRlcmVzdDogY2FuIGJlIGRvd25sb2FkZWQgZnJvbSBtdWx0aXBsZSBzb3VyY2VzOyBvciB0aGVyZSBhcmUgZGVkaWNhdGVkIFIgcGFja2FnZXMKCiMjIExvYWQgREVTZXEyIGFuZCBSc3VicmVhZCBwYWNrYWdlcwoKbGlicmFyeShERVNlcTIpICAgICAgICAjIExvYWRzIERFU2VxMiBwYWNrYWdlCmxpYnJhcnkoUnN1YnJlYWQpICAgICAgIyBMb2FkcyBSc3VicmVhZCBwYWNrYWdlIChjb3VudHMgZnJhZ21lbnRzIGZvciBlYWNoIGZlYXR1cmUpCmxpYnJhcnkodGlkeXZlcnNlKSAgICAgIyBMb2FkcyB0aWR5dmVyc2Ugd2hpY2ggYWxsb3dzIHZhcmlvdXMgY29udmVuaWVudCBkYXRhIG1hbmlwdWxhdGlvbnMKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKbGlicmFyeShnZ3B1YnIpCgojIyMgZmVhdHVyZUNvdW50IHN0ZXBzIHBlcmZvcm1lZCBvbiBPMiB0byBhdm9pZCBoYXZpbmcgdG8gbWFrZSBsb2NhbCBjb3BpZXMgb2YgLnNhbSBmaWxlcwoKIyMjIHNoZWxsIHNjcmlwdCB1c2VkIHRvIHJ1biBmZWF0dXJlIGNvdW50ICMjIyAgCgojIEltcG9ydCBnZW5lIGJvZHkgY291bnRzIHRhYmxlIGdlbmVyYXRlZCBpbiBPMiBpbnRvIFIKZmMgPC0gcmVhZC50YWJsZSgiUFJPX0FMQ0xfZmVhdHVyZWNvdW50cyIsIHNlcD0iXHQiLCBoZWFkZXI9VFJVRSwgcm93Lm5hbWVzPTEpCgojIEltcG9ydCBTQUYgZmlsZSBmb3IgbGF0ZXIgdXNlIG1hcHBpbmcgdHhfaWQgdG8gZ2VuZSBuYW1lcy4gIGNvbnZlcnQgdG8gdGliYmxlLiAgSWYgeW91IGFyZSBhYmxlIHRvIGdldCBhbm5vdGF0aW9uIGZyb20geW91ciBjb3VudHMgdGFibGUsIHRoaXMgbWF5IG5vdCBiZSBuZWNlc3NhcnkuCiNndGYgPC0gcmVhZC50YWJsZSgiLmd0ZiIsIHNlcCA9ICJcdCIsIGhlYWRlciA9IFRSVUUsIHJvdy5uYW1lcz0xKSAKIyMjICBHaXZlIG5pY2UgbmFtZXMgdG8gdGhlIGNvbHVtbnMgaW4gY291bnRzCgojIFN0b3JlIG9yaWdpbmFsIGNvbG5hbWVzCiNvcmlnX25hbWVzIDwtIGNvbG5hbWVzKGZjKQoKIyMjIFJlbmFtaW5nIGNvbHVtbnMuICBUaGlzIGlzIHJlYWxseSBpbmVsZWdhbnQgYnV0IGl0IHdvcmtlZC4gIERlcGVuZGluZyBvbiBuYW1pbmcsIG1heSBuZWVkIHRvIGFkanVzdCB0cmltIGxlbmd0aC4KCiMgVHJpbSAzOCBjaGFyIGZyb20gbGVmdCBzaWRlLCBkZWxldGUgIl9zb3J0ZWQuc2FtIiBmcm9tIHJpZ2h0LCByZXBsYWNlIC4gd2l0aCBfCiNuZXdfc2FtcGxlX2NvbG5hbWVzIDwtIHN0cl9zdWIoY29sbmFtZXMoZmMpLCAyOSwgc3RyX2xlbmd0aChjb2xuYW1lcyhmYykpKSAlPiUgc3RyX3JlcGxhY2UoIl9zb3J0ZWQuc2FtIiwiIikgJT4lIHN0cl9yZXBsYWNlKCJcXC4iLCJfIikKI25hbWVzX2NvbDFfNSA8LSBjb2xuYW1lcyhmYylbMTo1XSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc2F2ZSB0aGUgbmFtZXMgb2YgY29sdW1ucyAxLTUKI25ld19uYW1lcyA8LSBjKG5hbWVzX2NvbDFfNSwgbmV3X3NhbXBsZV9jb2xuYW1lc1s2Omxlbmd0aChuZXdfc2FtcGxlX2NvbG5hbWVzKV0pICAgICAjIGNvbWJpbmUgbmFtZXMgb2YgY29scyAxLTUgd2l0aCBzaG9ydGVuZWQgc2FtcGxlcyBuYW1lcwojbmV3X25hbWVzCgojY29sbmFtZXMoZmMpIDwtIG5ld19uYW1lcyAgICAgICAgICAgICAjIHJlcGxhY2Ugb2xkIGNvbHVtbiBuYW1lcyB3aXRoIG5ldyBuYW1lcwpjb2xuYW1lcyhmYylbNjoxNF0gPC0gYygiS0FSQVMyOTkiLCAiTDgyIiwgIlNVUE0yIiwgIlNVREhMMSIsICJLSUpLIiwgIlNSNzg2IiwgIkZFUEQiLCAiREw0MCIsICJNQUMyQSIpCmNvbG5hbWVzKGZjKSAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjaGVjayBuYW1lcwojIyMgQ3JlYXRlIG1ldGFkYXRhIG9iamVjdCB0byBjYXRlZ29yaXplIHNhbXBsZXM6CgptZXRhZGF0YSA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGNvbG5hbWVzKGZjWywgNjpuY29sKGZjKV0pLAogICAgICAgICAgICAgICAgICAgICAgIHN1YnR5cGUgPSBjKHJlcCgiQUxLX3Bvc2l0aXZlIiw2KSxyZXAoIkFMS19uZWdhdGl2ZSIsMykpCikgICMgZ2Vub3R5cGUrdGltZXBvaW50LCB1c2VkIGZvciBERXNlcSBjb25kaXRpb25zCm1ldGFkYXRhICMgdmVyaWZ5IHRoZSB0YWJsZSBsb29rcyBvawoKI2NvbmZpcm0gdGhhdCByb3cgYW5kIGNvbHVtbiBuYW1lcyBtYXRjaAphbGwocm93bmFtZXMobWV0YWRhdGEpICVpbiUgY29sbmFtZXMoZmMpKQphbGwocm93bmFtZXMobWV0YWRhdGEpID09IGNvbG5hbWVzKGZjKVs2Om5jb2woZmMpXSkKCgojIyBDcmVhdGUgREVTZXEgRGF0YSBTZXQgZnJvbSB0aGUgY291bnQgdGFibGUsIGFuZCBzYW1wbGUgbGlzdDoKCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGZjWywgNjpuY29sKGZjKV0sICAgICAgIyB0aGUgbWF0cml4IG9mIGNvdW50cyBmcm9tIGZlYXR1cmVDb3VudHM7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBtZXRhZGF0YSwgICAgICAgICAgICAgICAgICAgICAjIHRoZSBzYW1wbGUgdGFibGUgY3JlYXRlZCBpbiB0aGUgbGFzdCBzdGVwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ249IH5zdWJ0eXBlKSAgICAgICAgICAgICMgZGV0ZXJtaW5lIHdoYXQgdmFsdWUgeW91J2QgbGlrZSBERXNlcSB0byBjb21wYXJlCgpkZHMgPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhkZHMpCmRlc2VxX3NpemVzIDwtIGFzLmRhdGEuZnJhbWUoc2l6ZUZhY3RvcnMoZGRzKSkKZGVzZXFfc2l6ZXMKCmtlZXAgPC0gcm93TWF4KGNvdW50cyhkZHMsIG5vcm1hbGl6ZT1UUlVFKSkgPj0gMjAKZGRzIDwtIGRkc1trZWVwLF0Kc2F2ZVJEUyhkZHMsIGZpbGU9IkFMQ0xfREVzZXFfZGRzLnJkcyIpCiNkUkVHX3JlYWRGaWx0IDwtIGRSRUdbZFJFRyRkUkVHcGVha0lEICVpbiUgcm93bmFtZXMoZGRzKSxdCiN3cml0ZS50YWJsZShkUkVHX3JlYWRGaWx0LCBmaWxlPSJkUkVHcGVha3MucmVhZEZpbHQuYmVkIiwgc2VwPSJcdCIsIGNvbC5uYW1lcz1GQUxTRSwgcm93Lm5hbWVzPUZBTFNFLAogICAgICAgICAgICMgcXVvdGU9RkFMU0UpCiMgc2l6ZUZhY3RvcnMoZGRzKSA8LSBzcGlrZV9mYWN0b3JzCgojIyBFc3RpbWF0ZSBhbmQgcGxvdCBkaXNwZXJzaW9ucyBmb3Igc3RhbmRhcmQgbm9ybWFsaXphdGlvbiBERVNlcSBkYXRhIHNldDoKZGRzIDwtIGVzdGltYXRlRGlzcGVyc2lvbnMoZGRzKQpwZGYoIkRpc3BlcnNpb25fQUxDTC5wZGYiKQpwbG90RGlzcEVzdHMoZGRzKQpkZXYub2ZmKCkKCgojIGNoZWNrIHJlc3VsdHMgb2Ygbm9ybWFsaXphdGlvbgpjb2xTdW1zKGNvdW50cyhkZHMpKSAgICAgICAgICAgICAgICAjIHJhdyByZWFkIGNvdW50cyBwZXIgc2FtcGxlCmNvbFN1bXMoY291bnRzKGRkcywgbm9ybWFsaXplZD1UKSkgICMgVG90YWwgbnVtYmVyIG9mIG5vcm1hbGl6ZWQgY291bnRzIHBlciBzYW1wbGUKZGF0YS5mcmFtZShjb2xTdW1zKGNvdW50cyhkZHMpKSwgKGNvbFN1bXMoY291bnRzKGRkcywgbm9ybWFsaXplZD1UKSkpLCByb3cubmFtZXM9Y29sbmFtZXMoY291bnRzKGRkcykpKQoKIyBGb3IgdGhlc2Ugc2FtcGxlcywgc3Bpa2UgcmF0aW9zIGFyZSBjbG9zZSBzbyBERXNlcTIgbm9ybWFsaXphdGlvbiB3aWxsIGJlIHVzZWQuCgojcnVuIERFU2VxCmRkcyA8LSBERVNlcShkZHMpCmRkcyA8LSBuYmlub21XYWxkVGVzdChkZHMpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgV2FsZCB0ZXN0IGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgoKIyB1c2VyIHJlcXVlc3RlZCBjb21wYXJpc29ucwoKIyAgIEFMSysgdi4gQUxLLQoKIyBjcmVhdGUgcmVzdWx0cyBvYmplY3RzIGZvciBlYWNoIHJlcXVlc3RlZCBjb250cmFzdAoKcmVzX25lZ192X3BvcyAgPC0gcmVzdWx0cyhkZHMsIGNvbnRyYXN0ID0gYygic3VidHlwZSIsIkFMS19uZWdhdGl2ZSIsIkFMS19wb3NpdGl2ZSIpLCBhbHBoYSA9IDAuMDEpCgojIENhbGN1bGF0ZSBtZWFuIG5vcm1hbGl6ZWQgY291bnRzIGZvciBlYWNoIGNvbmRpdGlvbgoKQXZnTm9ybV9wb3MgICAgICAgIDwtIGFzLmRhdGEuZnJhbWUoY291bnRzKGRkcywgbm9ybWFsaXplZCA9IFRSVUUpKSAlPiUgc2VsZWN0KGNvbnRhaW5zKCJBTEtfcG9zaXRpdmUiKSkgJT4lIHJvd01lYW5zKC4pCkF2Z05vcm1fbmVnICAgICAgICA8LSBhcy5kYXRhLmZyYW1lKGNvdW50cyhkZHMsIG5vcm1hbGl6ZWQgPSBUUlVFKSkgJT4lIHNlbGVjdChjb250YWlucygiQUxLX25lZ2F0aXZlIikpICU+JSByb3dNZWFucyguKQoKIyBleHRyYWN0IGdlbmUgbmFtZXMgZnJvbSBzYWYgYW5ub3RhdGlvbiBmaWxlCiNnZW5lTmFtZXMgPC0gZHBseXI6OnNlbGVjdChyb3cubmFtZXMoZmMpLCBjKCJFbnNlbWJsSUQiKSkKCiMgU3RhcnQgdG8gYnVpbGQgcmVzdWx0cyB0YWJsZXMKCiMgUmVzdWx0cyB0YWJsZSBmb3IgY29tcGFyaXNvbnMgCgpyZXNUYWJsZSA8LSBkYXRhLmZyYW1lKCJFbnNlbWJsSUQiPWFzLmRhdGEuZnJhbWUocm93bmFtZXMoZGRzKSkpCiNyZXNUYWJsZSRnZW5lTmFtZXMgPC0gZ2VuZU5hbWVzJEdlbmVOYW1lCgpyZXNUYWJsZSRBdmdOb3JtQ291bnRzX0FMS19wb3NpdGl2ZSAgICAgIDwtIEF2Z05vcm1fcG9zCnJlc1RhYmxlJEF2Z05vcm1Db3VudHNfQUxLX25lZ2F0aXZlICAgICAgICAgPC0gQXZnTm9ybV9uZWcKcmVzVGFibGUkYmFzZU1lYW4gICAgICAgICAgICAgICAgICAgPC0gYXMuZGF0YS5mcmFtZShyZXNfbmVnX3ZfcG9zKSRiYXNlTWVhbgoKIyBWUyBwb3NpdGl2ZQoKcmVzVGFibGUkbG9nMkZvbGRDaGFuZ2VfbmVnX3ZfcG9zICAgICAgICA8LSBhcy5kYXRhLmZyYW1lKHJlc19uZWdfdl9wb3MpJGxvZzJGb2xkQ2hhbmdlCnJlc1RhYmxlJGxvZzJmY1NFX25lZ192X3BvcyAgICAgICAgICAgICAgPC0gYXMuZGF0YS5mcmFtZShyZXNfbmVnX3ZfcG9zKSRsZmNTRQpyZXNUYWJsZSRwdmFsdWVfbmVnX3ZfcG9zICAgICAgICAgICAgICAgIDwtIGFzLmRhdGEuZnJhbWUocmVzX25lZ192X3BvcykkcHZhbHVlCnJlc1RhYmxlJHBhZGpfbmVnX3ZfcG9zICAgICAgICAgICAgICAgICAgPC0gYXMuZGF0YS5mcmFtZShyZXNfbmVnX3ZfcG9zKSRwYWRqCgojIFdyaXRlIGRhdGEgdGFibGVzIHRvIHRleHQgZmlsZXMKCndyaXRlLmNzdihjb3VudHMoZGRzLCBub3JtYWxpemVkPUZBTFNFKSwgZmlsZT0iQUxLX3Bvc2l0aXZlX2FuZF9uZWdhdGl2ZV9XaG9sZUdlbmVfcmF3X2NvdW50cy5jc3YiKQp3cml0ZS5jc3YoY291bnRzKGRkcywgbm9ybWFsaXplZD1UUlVFKSwgZmlsZT0iQUxLX3Bvc2l0aXZlX2FuZF9uZWdhdGl2ZV9ERXNlcTJub3JtYWxpemVkX2NvdW50cy5jc3YiKQoKd3JpdGVfdHN2KHJlc1RhYmxlLCJBTENMX3Jlc3VsdHMudHh0IiwKICAgICAgICAgIGFwcGVuZCA9IEZBTFNFLAogICAgICAgICAgY29sX25hbWVzID0gVFJVRSwKICAgICAgICAgIG5hID0gIk5BIgopCgojIyMjIFBMT1RTICMjIyMKCiMgRW5oYW5jZWRWb2xjYW5vIHBsb3RzCgpQcm9qZWN0TmFtZSA8LSAiUFJPc2VxX0FMQ0wiCnBhZGpDdXRvZmYgPC0gMWUtNgpGQ2N1dG9mZiA8LSAxLjMyCgpwZGYoIkFMQ0xfdm9sY2Fuby5wZGYiKQpFbmhhbmNlZFZvbGNhbm8ocmVzX25lZ192X3BvcywKICAgICAgICAgICAgICAgIGxhYiA9IHJlc1RhYmxlJHJvd25hbWVzLmRkcy4sCiAgICAgICAgICAgICAgICB0aXRsZSA9ICdfJywKICAgICAgICAgICAgICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLAogICAgICAgICAgICAgICAgeSA9ICdwYWRqJywKICAgICAgICAgICAgICAgICN4bGltID0gYygtNiw2KSwKICAgICAgICAgICAgICAgIHhsYWIgPSBicXVvdGUofkxvZ1syXX4gJ2ZvbGQgY2hhbmdlJyksCiAgICAgICAgICAgICAgICB5bGFiID0gYnF1b3RlKCctJ35Mb2dbMTBdfiAnYWRqIHAtdmFsJyksCiAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gcGFkakN1dG9mZiwKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gRkNjdXRvZmYsCiAgICAgICAgICAgICAgICBwb2ludFNpemUgPSAxLjAsCiAgICAgICAgICAgICAgICBsYWJTaXplID0gMi4wLAogICAgICAgICAgICAgICAgY29sQWxwaGEgPSAwLjUsCiAgICAgICAgICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgICAgICAgICAgICAgICBsZWdlbmRMYWJTaXplID0gNiwKICAgICAgICAgICAgICAgIGxlZ2VuZEljb25TaXplID0gMy4wLAogICAgICAgICAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgd2lkdGhDb25uZWN0b3JzID0gMC4yLAogICAgICAgICAgICAgICAgY29sQ29ubmVjdG9ycyA9ICdncmV5MzAnKQpkZXYub2ZmKCkKCgojIyBNQSBwbG90cwoKIyB2cyBwb3NpdGl2ZQoKcGRmKCJBTENMX01BLnBkZiIpCkRFU2VxMjo6cGxvdE1BKHJlc19uZWdfdl9wb3MsIGFscGhhID0gMC4wMSwgbWFpbiA9ICJfIikKZGV2Lm9mZigpCgojIHBsb3REaXNwRXN0cyhkZHMpCnZzZDwtdnN0KGRkcyxibGluZD1GQUxTRSkKcmxkPC1ybG9nKGRkcyxibGluZD1GQUxTRSkKcGRmKCJBTENMX1BDQS5wZGYiKQpwbG90UENBKHZzZCwgaW50Z3JvdXA9Yygic3VidHlwZSIpKSAjc2FtZSBhcyBiZWZvcmUgZm9yIGFuYWx5c2lzCmRldi5vZmYoKQoKIyBkaXN0YW5jZSBwbG90CnNhbXBsZURpc3RzPC1kaXN0KHQoYXNzYXkodnNkKSkpCnNhbXBsZURpc3RNYXRyaXg8LWFzLm1hdHJpeChzYW1wbGVEaXN0cykKI3Jvdy5uYW1lcyhzYW1wbGVEaXN0TWF0cml4KTwtcGFzdGUodnNkJHN1YnR5cGUsIHJlcCwgc2VwPSJfIikKY29sbmFtZXMoc2FtcGxlRGlzdE1hdHJpeCk8LU5VTEwKY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwoOSwiQmx1ZXMiKSkpKDI1NSkKcGhlYXRtYXAoc2FtcGxlRGlzdE1hdHJpeCwgY29sPWNvbG9ycywgYm9yZGVyX2NvbG9yPU5BLCBzaG93X2NvbG5hbWVzPUZBTFNFLCBzaG93X3Jvd25hbWVzPVRSVUUpCgoKc2Vzc2lvbkluZm8oKQpgYGAK