Going to run the Day 135 samples through the Macau pipeline, similarly to the Day 10 samples I did last week.

First, some housekeeping stuff, setting workign directories, making subdirectories to hold things, and a vector of sample names

setwd("~/Documents/Day135/Day135Cutoff/")

samples.vec <- c("EPI-151", "EPI-152", "EPI-153", "EPI-154", "EPI-159", "EPI-160", "EPI-161", "EPI-162", "EPI-167", "EPI-168", "EPI-169", "EPI-170")

library(readr)
setwd("~/Documents/Day135/Day135Cutoff/CGoutput")

data <- list.files(path = ".", pattern = "*.output")
print(data)

db <- read_delim("~/Documents/Day135/Day135Cutoff/CGoutput/EPI-151_CG.output", "\t", escape_double = FALSE, trim_ws = TRUE, na = ".")

db <- as.data.table(db)

db$EPI103Meth <- rowSums(cbind(db[,4], db[,7]), na.rm = TRUE)
db$EPI103TotCov <- rowSums(cbind(db[,5], db[,8]), na.rm = TRUE)
meth.db <- db[,c(1,2,3,10)]
totcov.db <- db[,c(1,2,3,11)]

for(i in 2:length(data))   {
  
  temp <- read_delim(paste0("~/Documents/Day135/Day135Cutoff/CGoutput/", data[i]), "\t", escape_double = FALSE, trim_ws = TRUE, na = ".")
  temp <- as.data.table(temp)
  temp$Meth <- rowSums(cbind(temp[,4], temp[,7]), na.rm = TRUE)
  temp$TotCov <- rowSums(cbind(temp[,5], temp[,8]), na.rm = TRUE)

  meth.db <- merge(meth.db, temp[,c(1,2,3,10)], by = names(meth.db[,c(1,2,3)]), all = TRUE)
  colnames(meth.db)[ncol(meth.db)] <- paste0(substr(data[i], 1, 7), "Meth")
  meth.db <- as.data.table(meth.db)
  
  totcov.db <- merge(totcov.db, temp[,c(1,2,3,11)], by = names(totcov.db[,c(1,2,3)]), all = TRUE)
  colnames(totcov.db)[ncol(totcov.db)] <- paste0(substr(data[i], 1, 7), "TotCov")
  totcov.db <- as.data.table(totcov.db)
}
setwd("~/Documents/Day135/Day135Cutoff/macau")
meth.db2 <- meth.db[complete.cases(meth.db[,c(4:15)]),]

totcov.db2 <- totcov.db[complete.cases(totcov.db[,c(4:15)]),]

meth.db3 <- meth.db2[apply(meth.db2[, c(4:15)], MARGIN = 1, function(x) all(x > 3)), ]
totcov.db3 <- totcov.db2[apply(totcov.db2[, c(4:15)], MARGIN = 1, function(x) all(x > 3)), ]

meth.db4 <- as.data.table(cbind(paste0(meth.db3$`#CHROM`, "-", meth.db3$POS), meth.db3[,4:ncol(meth.db3)]))
colnames(meth.db4)[1] <- "Site"
totcov.db4 <- as.data.table(cbind(paste0(totcov.db3$`#CHROM`, "-", totcov.db3$POS), totcov.db3[,4:ncol(totcov.db3)]))
colnames(totcov.db4)[1] <- "Site"

totcov.db5 <- totcov.db4[totcov.db4$Site %in% meth.db4$Site,]

nrow(meth.db4)
nrow(totcov.db5)
length(totcov.db5$Site %in% meth.db4$Site)

write.table(meth.db4, file = "threex.macau.meth.txt", sep = " ", quote = FALSE, row.names = FALSE)
write.table(totcov.db5, file = "threex.macau.totalcov.txt", sep = " ", quote = FALSE, row.names = FALSE)

system("head threex.macau.meth.txt")
system("head threex.macau.totalcov.txt")

I’ve been doing this on my macbook, and macau requires linux to run properly, so the below code was run on Emu. The output isn’t super interesting, so I won’t bother copying it over. If you want to see what it looks like, look at my Day 10 notebook

setwd("~/Documents/Day135/Day135Cutoff/macau/")
system("/home/shared/macau/macau -g threex.macau.meth.txt -t threex.macau.totalcov.txt -p Predictor.csv -k day135-relate-finished.csv -o threex")
setwd("~/Documents/Day135/Day135Cutoff/macau/")

threex_assoc <- read_delim("~/Documents/Day135/Day135Cutoff/macau/output/threex.assoc.txt", 
    "\t", escape_double = FALSE, trim_ws = TRUE)

sig.results <- threex_assoc[threex_assoc$pvalue <= 0.05,]

 for(i in 1:nrow(sig.results))   {
   temp <- strsplit(sig.results$id[i], "-") 
   sig.results[i,13] <- temp[[1]][1]
   sig.results[i,14] <- temp[[1]][2]
   
 }
 
 colnames(sig.results)[c(13,14)] <- c("Scaffold", "Loc")
 
 bed.test <- as.data.frame(cbind(sig.results[,13], (sig.results[,14]), (sig.results[,14]), sig.results$beta))
 colnames(bed.test)[4] <- "beta"
 write.table(bed.test, file = "threex.DiffMethRegions.bed", sep = ",", quote = FALSE, col.names = FALSE, row.names = FALSE)

Set Working Directory, and make sure the files I want are there.

 setwd("~/Documents/Day135/Day135Cutoff/")
 
 list.files(path = ".")
 

Read in the DiffMethRegions file, which has scaffold number, location, and beta values from the MACAU model. Also, make a vector of the individual sample files to iterate over.

 library(data.table)
 library(readr)
 DiffMethRegions <- read_delim("~/Documents/Day135/Day135Cutoff/threex.DiffMethRegions.bed", 
     ",", escape_double = FALSE, col_names = FALSE, 
     trim_ws = TRUE)
 
 DiffMethRegions$Loc <- paste0(DiffMethRegions$X1, "-", DiffMethRegions$X2)
 
 head(DiffMethRegions)
 
 sample.files <- list.files(path = "~/Documents/Day135/Day135Cutoff/", pattern = "*.bedgraph")
 
 print(sample.files)

my DMR file looks good, and I have sample file names to iterate over

Start the first post for my fence. I have to specify that the column type for the 4th column, which contains proportion of methylation data is a double, as R assumes it to be an integer valued vector, which results in only 1s and 0s, which wouldn’t be informative.


 EPI_103_percmeth_bedgraph <- read_delim("~/Documents/Day135/Day135Cutoff/EPI-151-percmeth.bedgraph", 
     "\t", escape_double = FALSE, col_names = FALSE, 
     col_types = cols(X4 = col_double()), 
     trim_ws = TRUE)
 
 EPI_103_percmeth_bedgraph <- as.data.table(EPI_103_percmeth_bedgraph)
 
 head(EPI_103_percmeth_bedgraph)
 
 print(EPI_103_percmeth_bedgraph[7,])

I tossed an extra print statement in, just to verify that something that’s double valued really is.

Next I extract information only on the 41 DMRs, since that’s all thats of interest


EPI_103_DMRs <- EPI_103_percmeth_bedgraph[EPI_103_percmeth_bedgraph$X1 %in% DiffMethRegions$X1,]


EPI_103_DMRs$Loc <- paste0(EPI_103_DMRs$X1, "-", EPI_103_DMRs$X2)


head(EPI_103_DMRs)

EPI_103_DMRs <- EPI_103_DMRs[EPI_103_DMRs$Loc %in% DiffMethRegions$Loc,]

head(EPI_103_DMRs)

EPI_DMRs <- as.data.table(cbind(EPI_103_DMRs$Loc, EPI_103_DMRs$X4))



colnames(EPI_DMRs)[1] <- "DMRLoc"
colnames(EPI_DMRs)[2] <- "EPI_151"
head(EPI_DMRs)

Now I get to do the whole loop thing, iterating over the remaining samples and reading them in, extracting the DMRs and saving them to my DMR matrix.


for(i in 2:length(sample.files))   {

  temp <- read_delim(paste0("~/Documents/Day135/Day135Cutoff/", sample.files[i]),
    "\t", escape_double = FALSE, col_names = FALSE,
    col_types = cols(X4 = col_double()),
    trim_ws = TRUE)

  temp <- as.data.table(temp)

  temp_DMRs <- temp[temp$X1 %in% DiffMethRegions$X1,]


  temp_DMRs$Loc <- paste0(temp_DMRs$X1, "-", temp_DMRs$X2)


  temp_DMRs <- temp_DMRs[temp_DMRs$Loc %in% DiffMethRegions$Loc,]

  EPI_DMRs$temp <- temp_DMRs$X4

  colnames(EPI_DMRs)[ncol(EPI_DMRs)] <- substr(sample.files[i], 1, 7)


}

head(EPI_DMRs)

## This is here because for osme reason EPI_103 gets brught in as characters as opposed to doubles. Need to figure out why, but this fixes it for now
EPI_DMRs$EPI_151 <- as.numeric(EPI_DMRs$EPI_151)

Here I calculate treatment means and save them to a vector of treatment means by location


treatment.means <- as.data.frame(EPI_DMRs$DMRLoc)

treatment.means$Ambient <- apply(cbind(EPI_DMRs$`EPI-151`, EPI_DMRs$`EPI-152`, EPI_DMRs$`EPI-153`, EPI_DMRs$`EPI-154`) ,MARGIN = 1, FUN = mean)

treatment.means$Low <- apply(cbind(EPI_DMRs$`EPI-159`, EPI_DMRs$`EPI-160`, EPI_DMRs$`EPI-161`, EPI_DMRs$`EPI-162`) ,MARGIN = 1, FUN = mean)

treatment.means$SuperLow <- apply(cbind(EPI_DMRs$`EPI-167`, EPI_DMRs$`EPI-168`, EPI_DMRs$`EPI-169`, EPI_DMRs$`EPI-170`) ,MARGIN = 1, FUN = mean)

head(treatment.means)

This… makes a really ugly and hard to read graph. On the X axis is the DMR location, and the Y axis is proportion emthylated. Bars are ambient, Green dots are low treatments, and red dots are Super low treatments.

It’s not really informative, but I made it, so I figured I’d show it.


 plot(treatment.means$`EPI_DMRs$DMRLoc`, treatment.means$Ambient, col = "blue", pch = 16)
 
 points(treatment.means$`EPI_DMRs$DMRLoc`, treatment.means$Low, col = "green", pch = 16)
 
 points(treatment.means$`EPI_DMRs$DMRLoc`, treatment.means$SuperLow, col = "red", pch = 16)

I like this a lot better, it makes boxplots for each DMR with each treatment. I like how this shows the variaiblity between samples, as well as location information. The below code outputs to R-studio, as well as a PDF for easier viewing.




#  for(i in 1:nrow(treatment.means))   {
#    
# 
#   boxplot(t(cbind(EPI_DMRs[i,2], EPI_DMRs[i,3], EPI_DMRs[i,4], EPI_DMRs[i,5])),xlim = c(0.5, 3.5), ylim = c(min(EPI_DMRs[i,2:13]), max(EPI_DMRs[i,2:13])), boxfill = "blue", names = "Ambient", show.names = TRUE, ylab = "Proportion of reads methylated")
# 
# boxplot(t(cbind(EPI_DMRs[i,6], EPI_DMRs[i,7], EPI_DMRs[i,8], EPI_DMRs[i,9])), xaxt = "n", add = TRUE, at = 2, boxfill = "green")
# 
# boxplot(t(cbind(EPI_DMRs[i,10], EPI_DMRs[i,11], EPI_DMRs[i,12], EPI_DMRs[i,13])), xaxt = "n", add = TRUE, at = 3, boxfill = "red")
# 
# axis(side = 1, at = 2, labels = "Low")
# axis(side = 1, at = 3, labels = "Super Low")
# 
# title(paste0("Proportion of Methylated reads for DMR \n located at ", EPI_DMRs[i,1]))
# 
# 
# }


pdf(file = "threex-DMR-Box-Plots.pdf")

for(i in 1:nrow(treatment.means))   {


  boxplot(t(cbind(EPI_DMRs[i,6], EPI_DMRs[i,7], EPI_DMRs[i,10], EPI_DMRs[i,11])),xlim = c(0.5, 3.5), ylim = c(min(EPI_DMRs[i,2:13]), max(EPI_DMRs[i,2:13])), boxfill = "blue", names = "Ambient", show.names = TRUE, ylab = "Proportion of reads methylated")

boxplot(t(cbind(EPI_DMRs[i,2], EPI_DMRs[i,3], EPI_DMRs[i,8], EPI_DMRs[i,9])), xaxt = "n", add = TRUE, at = 2, boxfill = "green")

boxplot(t(cbind(EPI_DMRs[i,4], EPI_DMRs[i,5], EPI_DMRs[i,12], EPI_DMRs[i,13])), xaxt = "n", add = TRUE, at = 3, boxfill = "red")

axis(side = 1, at = 2, labels = "Low")
axis(side = 1, at = 3, labels = "Super Low")

title(paste0("Proportion of Methylated reads for DMR \n located at ", EPI_DMRs[i,1]))


}

dev.off()

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

LS0tCnRpdGxlOiAiRGF5IDEzNSBTYW1wbGVzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpHb2luZyB0byBydW4gdGhlIERheSAxMzUgc2FtcGxlcyB0aHJvdWdoIHRoZSBNYWNhdSBwaXBlbGluZSwgc2ltaWxhcmx5IHRvIHRoZSBEYXkgMTAgc2FtcGxlcyBJIGRpZCBsYXN0IHdlZWsuCgpGaXJzdCwgc29tZSBob3VzZWtlZXBpbmcgc3R1ZmYsIHNldHRpbmcgd29ya2lnbiBkaXJlY3RvcmllcywgbWFraW5nIHN1YmRpcmVjdG9yaWVzIHRvIGhvbGQgdGhpbmdzLCBhbmQgYSB2ZWN0b3Igb2Ygc2FtcGxlIG5hbWVzCgpgYGB7cn0Kc2V0d2QoIn4vRG9jdW1lbnRzL0RheTEzNS9EYXkxMzVDdXRvZmYvIikKCnNhbXBsZXMudmVjIDwtIGMoIkVQSS0xNTEiLCAiRVBJLTE1MiIsICJFUEktMTUzIiwgIkVQSS0xNTQiLCAiRVBJLTE1OSIsICJFUEktMTYwIiwgIkVQSS0xNjEiLCAiRVBJLTE2MiIsICJFUEktMTY3IiwgIkVQSS0xNjgiLCAiRVBJLTE2OSIsICJFUEktMTcwIikKCmBgYAoKCmBgYHtyfQoKbGlicmFyeShyZWFkcikKc2V0d2QoIn4vRG9jdW1lbnRzL0RheTEzNS9EYXkxMzVDdXRvZmYvQ0dvdXRwdXQiKQoKZGF0YSA8LSBsaXN0LmZpbGVzKHBhdGggPSAiLiIsIHBhdHRlcm4gPSAiKi5vdXRwdXQiKQpwcmludChkYXRhKQoKZGIgPC0gcmVhZF9kZWxpbSgifi9Eb2N1bWVudHMvRGF5MTM1L0RheTEzNUN1dG9mZi9DR291dHB1dC9FUEktMTUxX0NHLm91dHB1dCIsICJcdCIsIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwgdHJpbV93cyA9IFRSVUUsIG5hID0gIi4iKQoKZGIgPC0gYXMuZGF0YS50YWJsZShkYikKCmRiJEVQSTEwM01ldGggPC0gcm93U3VtcyhjYmluZChkYlssNF0sIGRiWyw3XSksIG5hLnJtID0gVFJVRSkKZGIkRVBJMTAzVG90Q292IDwtIHJvd1N1bXMoY2JpbmQoZGJbLDVdLCBkYlssOF0pLCBuYS5ybSA9IFRSVUUpCm1ldGguZGIgPC0gZGJbLGMoMSwyLDMsMTApXQp0b3Rjb3YuZGIgPC0gZGJbLGMoMSwyLDMsMTEpXQoKZm9yKGkgaW4gMjpsZW5ndGgoZGF0YSkpICAgewogIAogIHRlbXAgPC0gcmVhZF9kZWxpbShwYXN0ZTAoIn4vRG9jdW1lbnRzL0RheTEzNS9EYXkxMzVDdXRvZmYvQ0dvdXRwdXQvIiwgZGF0YVtpXSksICJcdCIsIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwgdHJpbV93cyA9IFRSVUUsIG5hID0gIi4iKQogIHRlbXAgPC0gYXMuZGF0YS50YWJsZSh0ZW1wKQogIHRlbXAkTWV0aCA8LSByb3dTdW1zKGNiaW5kKHRlbXBbLDRdLCB0ZW1wWyw3XSksIG5hLnJtID0gVFJVRSkKICB0ZW1wJFRvdENvdiA8LSByb3dTdW1zKGNiaW5kKHRlbXBbLDVdLCB0ZW1wWyw4XSksIG5hLnJtID0gVFJVRSkKCiAgbWV0aC5kYiA8LSBtZXJnZShtZXRoLmRiLCB0ZW1wWyxjKDEsMiwzLDEwKV0sIGJ5ID0gbmFtZXMobWV0aC5kYlssYygxLDIsMyldKSwgYWxsID0gVFJVRSkKICBjb2xuYW1lcyhtZXRoLmRiKVtuY29sKG1ldGguZGIpXSA8LSBwYXN0ZTAoc3Vic3RyKGRhdGFbaV0sIDEsIDcpLCAiTWV0aCIpCiAgbWV0aC5kYiA8LSBhcy5kYXRhLnRhYmxlKG1ldGguZGIpCiAgCiAgdG90Y292LmRiIDwtIG1lcmdlKHRvdGNvdi5kYiwgdGVtcFssYygxLDIsMywxMSldLCBieSA9IG5hbWVzKHRvdGNvdi5kYlssYygxLDIsMyldKSwgYWxsID0gVFJVRSkKICBjb2xuYW1lcyh0b3Rjb3YuZGIpW25jb2wodG90Y292LmRiKV0gPC0gcGFzdGUwKHN1YnN0cihkYXRhW2ldLCAxLCA3KSwgIlRvdENvdiIpCiAgdG90Y292LmRiIDwtIGFzLmRhdGEudGFibGUodG90Y292LmRiKQp9CgoKCmBgYAoKCgpgYGB7cn0Kc2V0d2QoIn4vRG9jdW1lbnRzL0RheTEzNS9EYXkxMzVDdXRvZmYvbWFjYXUiKQptZXRoLmRiMiA8LSBtZXRoLmRiW2NvbXBsZXRlLmNhc2VzKG1ldGguZGJbLGMoNDoxNSldKSxdCgp0b3Rjb3YuZGIyIDwtIHRvdGNvdi5kYltjb21wbGV0ZS5jYXNlcyh0b3Rjb3YuZGJbLGMoNDoxNSldKSxdCgptZXRoLmRiMyA8LSBtZXRoLmRiMlthcHBseShtZXRoLmRiMlssIGMoNDoxNSldLCBNQVJHSU4gPSAxLCBmdW5jdGlvbih4KSBhbGwoeCA+IDMpKSwgXQp0b3Rjb3YuZGIzIDwtIHRvdGNvdi5kYjJbYXBwbHkodG90Y292LmRiMlssIGMoNDoxNSldLCBNQVJHSU4gPSAxLCBmdW5jdGlvbih4KSBhbGwoeCA+IDMpKSwgXQoKbWV0aC5kYjQgPC0gYXMuZGF0YS50YWJsZShjYmluZChwYXN0ZTAobWV0aC5kYjMkYCNDSFJPTWAsICItIiwgbWV0aC5kYjMkUE9TKSwgbWV0aC5kYjNbLDQ6bmNvbChtZXRoLmRiMyldKSkKY29sbmFtZXMobWV0aC5kYjQpWzFdIDwtICJTaXRlIgp0b3Rjb3YuZGI0IDwtIGFzLmRhdGEudGFibGUoY2JpbmQocGFzdGUwKHRvdGNvdi5kYjMkYCNDSFJPTWAsICItIiwgdG90Y292LmRiMyRQT1MpLCB0b3Rjb3YuZGIzWyw0Om5jb2wodG90Y292LmRiMyldKSkKY29sbmFtZXModG90Y292LmRiNClbMV0gPC0gIlNpdGUiCgp0b3Rjb3YuZGI1IDwtIHRvdGNvdi5kYjRbdG90Y292LmRiNCRTaXRlICVpbiUgbWV0aC5kYjQkU2l0ZSxdCgpucm93KG1ldGguZGI0KQpucm93KHRvdGNvdi5kYjUpCmxlbmd0aCh0b3Rjb3YuZGI1JFNpdGUgJWluJSBtZXRoLmRiNCRTaXRlKQoKd3JpdGUudGFibGUobWV0aC5kYjQsIGZpbGUgPSAidGhyZWV4Lm1hY2F1Lm1ldGgudHh0Iiwgc2VwID0gIiAiLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSBGQUxTRSkKd3JpdGUudGFibGUodG90Y292LmRiNSwgZmlsZSA9ICJ0aHJlZXgubWFjYXUudG90YWxjb3YudHh0Iiwgc2VwID0gIiAiLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSBGQUxTRSkKCnN5c3RlbSgiaGVhZCB0aHJlZXgubWFjYXUubWV0aC50eHQiKQpzeXN0ZW0oImhlYWQgdGhyZWV4Lm1hY2F1LnRvdGFsY292LnR4dCIpCmBgYAoKSSd2ZSBiZWVuIGRvaW5nIHRoaXMgb24gbXkgbWFjYm9vaywgYW5kIG1hY2F1IHJlcXVpcmVzIGxpbnV4IHRvIHJ1biBwcm9wZXJseSwgc28gdGhlIGJlbG93IGNvZGUgd2FzIHJ1biBvbiBFbXUuIFRoZSBvdXRwdXQgaXNuJ3Qgc3VwZXIgaW50ZXJlc3RpbmcsIHNvIEkgd29uJ3QgYm90aGVyIGNvcHlpbmcgaXQgb3Zlci4gSWYgeW91IHdhbnQgdG8gc2VlIHdoYXQgaXQgbG9va3MgbGlrZSwgbG9vayBhdCBteSBEYXkgMTAgbm90ZWJvb2sKCmBgYHtyfQpzZXR3ZCgifi9Eb2N1bWVudHMvRGF5MTM1L0RheTEzNUN1dG9mZi9tYWNhdS8iKQpzeXN0ZW0oIi9ob21lL3NoYXJlZC9tYWNhdS9tYWNhdSAtZyB0aHJlZXgubWFjYXUubWV0aC50eHQgLXQgdGhyZWV4Lm1hY2F1LnRvdGFsY292LnR4dCAtcCBQcmVkaWN0b3IuY3N2IC1rIGRheTEzNS1yZWxhdGUtZmluaXNoZWQuY3N2IC1vIHRocmVleCIpCgpgYGAKCgoKCmBgYHtyfQpzZXR3ZCgifi9Eb2N1bWVudHMvRGF5MTM1L0RheTEzNUN1dG9mZi9tYWNhdS8iKQoKdGhyZWV4X2Fzc29jIDwtIHJlYWRfZGVsaW0oIn4vRG9jdW1lbnRzL0RheTEzNS9EYXkxMzVDdXRvZmYvbWFjYXUvb3V0cHV0L3RocmVleC5hc3NvYy50eHQiLCAKICAgICJcdCIsIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwgdHJpbV93cyA9IFRSVUUpCgpzaWcucmVzdWx0cyA8LSB0aHJlZXhfYXNzb2NbdGhyZWV4X2Fzc29jJHB2YWx1ZSA8PSAwLjA1LF0KCiBmb3IoaSBpbiAxOm5yb3coc2lnLnJlc3VsdHMpKSAgIHsKICAgdGVtcCA8LSBzdHJzcGxpdChzaWcucmVzdWx0cyRpZFtpXSwgIi0iKSAKICAgc2lnLnJlc3VsdHNbaSwxM10gPC0gdGVtcFtbMV1dWzFdCiAgIHNpZy5yZXN1bHRzW2ksMTRdIDwtIHRlbXBbWzFdXVsyXQogICAKIH0KIAogY29sbmFtZXMoc2lnLnJlc3VsdHMpW2MoMTMsMTQpXSA8LSBjKCJTY2FmZm9sZCIsICJMb2MiKQogCiBiZWQudGVzdCA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKHNpZy5yZXN1bHRzWywxM10sIChzaWcucmVzdWx0c1ssMTRdKSwgKHNpZy5yZXN1bHRzWywxNF0pLCBzaWcucmVzdWx0cyRiZXRhKSkKIGNvbG5hbWVzKGJlZC50ZXN0KVs0XSA8LSAiYmV0YSIKIHdyaXRlLnRhYmxlKGJlZC50ZXN0LCBmaWxlID0gInRocmVleC5EaWZmTWV0aFJlZ2lvbnMuYmVkIiwgc2VwID0gIiwiLCBxdW90ZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UpCgpgYGAKCgpTZXQgV29ya2luZyBEaXJlY3RvcnksIGFuZCBtYWtlIHN1cmUgdGhlIGZpbGVzIEkgd2FudCBhcmUgdGhlcmUuCgpgYGB7cn0KIHNldHdkKCJ+L0RvY3VtZW50cy9EYXkxMzUvRGF5MTM1Q3V0b2ZmLyIpCiAKIGxpc3QuZmlsZXMocGF0aCA9ICIuIikKIAoKYGBgCgpSZWFkIGluIHRoZSBEaWZmTWV0aFJlZ2lvbnMgZmlsZSwgd2hpY2ggaGFzIHNjYWZmb2xkIG51bWJlciwgbG9jYXRpb24sIGFuZCBiZXRhIHZhbHVlcyBmcm9tIHRoZSBNQUNBVSBtb2RlbC4gQWxzbywgbWFrZSBhIHZlY3RvciBvZiB0aGUgaW5kaXZpZHVhbCBzYW1wbGUgZmlsZXMgdG8gaXRlcmF0ZSBvdmVyLiAKCmBgYHtyfQogbGlicmFyeShkYXRhLnRhYmxlKQogbGlicmFyeShyZWFkcikKIERpZmZNZXRoUmVnaW9ucyA8LSByZWFkX2RlbGltKCJ+L0RvY3VtZW50cy9EYXkxMzUvRGF5MTM1Q3V0b2ZmL3RocmVleC5EaWZmTWV0aFJlZ2lvbnMuYmVkIiwgCiAgICAgIiwiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIGNvbF9uYW1lcyA9IEZBTFNFLCAKICAgICB0cmltX3dzID0gVFJVRSkKIAogRGlmZk1ldGhSZWdpb25zJExvYyA8LSBwYXN0ZTAoRGlmZk1ldGhSZWdpb25zJFgxLCAiLSIsIERpZmZNZXRoUmVnaW9ucyRYMikKIAogaGVhZChEaWZmTWV0aFJlZ2lvbnMpCiAKIHNhbXBsZS5maWxlcyA8LSBsaXN0LmZpbGVzKHBhdGggPSAifi9Eb2N1bWVudHMvRGF5MTM1L0RheTEzNUN1dG9mZi8iLCBwYXR0ZXJuID0gIiouYmVkZ3JhcGgiKQogCiBwcmludChzYW1wbGUuZmlsZXMpCgpgYGAKCgpteSBETVIgZmlsZSBsb29rcyBnb29kLCBhbmQgSSBoYXZlIHNhbXBsZSBmaWxlIG5hbWVzIHRvIGl0ZXJhdGUgb3ZlcgoKClN0YXJ0IHRoZSBmaXJzdCBwb3N0IGZvciBteSBmZW5jZS4gSSBoYXZlIHRvIHNwZWNpZnkgdGhhdCB0aGUgY29sdW1uIHR5cGUgZm9yIHRoZSA0dGggY29sdW1uLCB3aGljaCBjb250YWlucyBwcm9wb3J0aW9uIG9mIG1ldGh5bGF0aW9uIGRhdGEgaXMgYSBkb3VibGUsIGFzIFIgYXNzdW1lcyBpdCB0byBiZSBhbiBpbnRlZ2VyIHZhbHVlZCB2ZWN0b3IsIHdoaWNoIHJlc3VsdHMgaW4gb25seSAxcyBhbmQgMHMsIHdoaWNoIHdvdWxkbid0IGJlIGluZm9ybWF0aXZlLiAKCmBgYHtyfQoKIEVQSV8xMDNfcGVyY21ldGhfYmVkZ3JhcGggPC0gcmVhZF9kZWxpbSgifi9Eb2N1bWVudHMvRGF5MTM1L0RheTEzNUN1dG9mZi9FUEktMTUxLXBlcmNtZXRoLmJlZGdyYXBoIiwgCiAgICAgIlx0IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCBjb2xfbmFtZXMgPSBGQUxTRSwgCiAgICAgY29sX3R5cGVzID0gY29scyhYNCA9IGNvbF9kb3VibGUoKSksIAogICAgIHRyaW1fd3MgPSBUUlVFKQogCiBFUElfMTAzX3BlcmNtZXRoX2JlZGdyYXBoIDwtIGFzLmRhdGEudGFibGUoRVBJXzEwM19wZXJjbWV0aF9iZWRncmFwaCkKIAogaGVhZChFUElfMTAzX3BlcmNtZXRoX2JlZGdyYXBoKQogCiBwcmludChFUElfMTAzX3BlcmNtZXRoX2JlZGdyYXBoWzcsXSkKCmBgYAoKSSB0b3NzZWQgYW4gZXh0cmEgcHJpbnQgc3RhdGVtZW50IGluLCBqdXN0IHRvIHZlcmlmeSB0aGF0IHNvbWV0aGluZyB0aGF0J3MgZG91YmxlIHZhbHVlZCByZWFsbHkgaXMuIAoKTmV4dCBJIGV4dHJhY3QgaW5mb3JtYXRpb24gb25seSBvbiB0aGUgNDEgRE1Scywgc2luY2UgdGhhdCdzIGFsbCB0aGF0cyBvZiBpbnRlcmVzdAoKYGBge3J9CgpFUElfMTAzX0RNUnMgPC0gRVBJXzEwM19wZXJjbWV0aF9iZWRncmFwaFtFUElfMTAzX3BlcmNtZXRoX2JlZGdyYXBoJFgxICVpbiUgRGlmZk1ldGhSZWdpb25zJFgxLF0KCgpFUElfMTAzX0RNUnMkTG9jIDwtIHBhc3RlMChFUElfMTAzX0RNUnMkWDEsICItIiwgRVBJXzEwM19ETVJzJFgyKQoKCmhlYWQoRVBJXzEwM19ETVJzKQoKRVBJXzEwM19ETVJzIDwtIEVQSV8xMDNfRE1Sc1tFUElfMTAzX0RNUnMkTG9jICVpbiUgRGlmZk1ldGhSZWdpb25zJExvYyxdCgpoZWFkKEVQSV8xMDNfRE1ScykKCkVQSV9ETVJzIDwtIGFzLmRhdGEudGFibGUoY2JpbmQoRVBJXzEwM19ETVJzJExvYywgRVBJXzEwM19ETVJzJFg0KSkKCgoKY29sbmFtZXMoRVBJX0RNUnMpWzFdIDwtICJETVJMb2MiCmNvbG5hbWVzKEVQSV9ETVJzKVsyXSA8LSAiRVBJXzE1MSIKaGVhZChFUElfRE1ScykKCmBgYAoKTm93IEkgZ2V0IHRvIGRvIHRoZSB3aG9sZSBsb29wIHRoaW5nLCBpdGVyYXRpbmcgb3ZlciB0aGUgcmVtYWluaW5nIHNhbXBsZXMgYW5kIHJlYWRpbmcgdGhlbSBpbiwgZXh0cmFjdGluZyB0aGUgRE1ScyBhbmQgc2F2aW5nIHRoZW0gdG8gbXkgRE1SIG1hdHJpeC4KCmBgYHtyfQoKZm9yKGkgaW4gMjpsZW5ndGgoc2FtcGxlLmZpbGVzKSkgICB7CgogIHRlbXAgPC0gcmVhZF9kZWxpbShwYXN0ZTAoIn4vRG9jdW1lbnRzL0RheTEzNS9EYXkxMzVDdXRvZmYvIiwgc2FtcGxlLmZpbGVzW2ldKSwKICAgICJcdCIsIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwgY29sX25hbWVzID0gRkFMU0UsCiAgICBjb2xfdHlwZXMgPSBjb2xzKFg0ID0gY29sX2RvdWJsZSgpKSwKICAgIHRyaW1fd3MgPSBUUlVFKQoKICB0ZW1wIDwtIGFzLmRhdGEudGFibGUodGVtcCkKCiAgdGVtcF9ETVJzIDwtIHRlbXBbdGVtcCRYMSAlaW4lIERpZmZNZXRoUmVnaW9ucyRYMSxdCgoKICB0ZW1wX0RNUnMkTG9jIDwtIHBhc3RlMCh0ZW1wX0RNUnMkWDEsICItIiwgdGVtcF9ETVJzJFgyKQoKCiAgdGVtcF9ETVJzIDwtIHRlbXBfRE1Sc1t0ZW1wX0RNUnMkTG9jICVpbiUgRGlmZk1ldGhSZWdpb25zJExvYyxdCgogIEVQSV9ETVJzJHRlbXAgPC0gdGVtcF9ETVJzJFg0CgogIGNvbG5hbWVzKEVQSV9ETVJzKVtuY29sKEVQSV9ETVJzKV0gPC0gc3Vic3RyKHNhbXBsZS5maWxlc1tpXSwgMSwgNykKCgp9CgpoZWFkKEVQSV9ETVJzKQoKIyMgVGhpcyBpcyBoZXJlIGJlY2F1c2UgZm9yIG9zbWUgcmVhc29uIEVQSV8xMDMgZ2V0cyBicnVnaHQgaW4gYXMgY2hhcmFjdGVycyBhcyBvcHBvc2VkIHRvIGRvdWJsZXMuIE5lZWQgdG8gZmlndXJlIG91dCB3aHksIGJ1dCB0aGlzIGZpeGVzIGl0IGZvciBub3cKRVBJX0RNUnMkRVBJXzE1MSA8LSBhcy5udW1lcmljKEVQSV9ETVJzJEVQSV8xNTEpCgpgYGAKCgpIZXJlIEkgY2FsY3VsYXRlIHRyZWF0bWVudCBtZWFucyBhbmQgc2F2ZSB0aGVtIHRvIGEgdmVjdG9yIG9mIHRyZWF0bWVudCBtZWFucyBieSBsb2NhdGlvbgoKYGBge3J9Cgp0cmVhdG1lbnQubWVhbnMgPC0gYXMuZGF0YS5mcmFtZShFUElfRE1ScyRETVJMb2MpCgp0cmVhdG1lbnQubWVhbnMkQW1iaWVudCA8LSBhcHBseShjYmluZChFUElfRE1ScyRgRVBJLTE1MWAsIEVQSV9ETVJzJGBFUEktMTUyYCwgRVBJX0RNUnMkYEVQSS0xNTNgLCBFUElfRE1ScyRgRVBJLTE1NGApICxNQVJHSU4gPSAxLCBGVU4gPSBtZWFuKQoKdHJlYXRtZW50Lm1lYW5zJExvdyA8LSBhcHBseShjYmluZChFUElfRE1ScyRgRVBJLTE1OWAsIEVQSV9ETVJzJGBFUEktMTYwYCwgRVBJX0RNUnMkYEVQSS0xNjFgLCBFUElfRE1ScyRgRVBJLTE2MmApICxNQVJHSU4gPSAxLCBGVU4gPSBtZWFuKQoKdHJlYXRtZW50Lm1lYW5zJFN1cGVyTG93IDwtIGFwcGx5KGNiaW5kKEVQSV9ETVJzJGBFUEktMTY3YCwgRVBJX0RNUnMkYEVQSS0xNjhgLCBFUElfRE1ScyRgRVBJLTE2OWAsIEVQSV9ETVJzJGBFUEktMTcwYCkgLE1BUkdJTiA9IDEsIEZVTiA9IG1lYW4pCgpoZWFkKHRyZWF0bWVudC5tZWFucykKYGBgCgpUaGlzLi4uIG1ha2VzIGEgcmVhbGx5IHVnbHkgYW5kIGhhcmQgdG8gcmVhZCBncmFwaC4gT24gdGhlIFggYXhpcyBpcyB0aGUgRE1SIGxvY2F0aW9uLCBhbmQgdGhlIFkgYXhpcyBpcyBwcm9wb3J0aW9uIGVtdGh5bGF0ZWQuIEJhcnMgYXJlIGFtYmllbnQsIEdyZWVuIGRvdHMgYXJlIGxvdyB0cmVhdG1lbnRzLCBhbmQgcmVkIGRvdHMgYXJlIFN1cGVyIGxvdyB0cmVhdG1lbnRzLgoKSXQncyBub3QgcmVhbGx5IGluZm9ybWF0aXZlLCBidXQgSSBtYWRlIGl0LCBzbyBJIGZpZ3VyZWQgSSdkIHNob3cgaXQuIApgYGB7cn0KCiBwbG90KHRyZWF0bWVudC5tZWFucyRgRVBJX0RNUnMkRE1STG9jYCwgdHJlYXRtZW50Lm1lYW5zJEFtYmllbnQsIGNvbCA9ICJibHVlIiwgcGNoID0gMTYpCiAKIHBvaW50cyh0cmVhdG1lbnQubWVhbnMkYEVQSV9ETVJzJERNUkxvY2AsIHRyZWF0bWVudC5tZWFucyRMb3csIGNvbCA9ICJncmVlbiIsIHBjaCA9IDE2KQogCiBwb2ludHModHJlYXRtZW50Lm1lYW5zJGBFUElfRE1ScyRETVJMb2NgLCB0cmVhdG1lbnQubWVhbnMkU3VwZXJMb3csIGNvbCA9ICJyZWQiLCBwY2ggPSAxNikKYGBgCgoKSSBsaWtlIHRoaXMgYSBsb3QgYmV0dGVyLCBpdCBtYWtlcyBib3hwbG90cyBmb3IgZWFjaCBETVIgd2l0aCBlYWNoIHRyZWF0bWVudC4gSSBsaWtlIGhvdyB0aGlzIHNob3dzIHRoZSB2YXJpYWlibGl0eSBiZXR3ZWVuIHNhbXBsZXMsIGFzIHdlbGwgYXMgbG9jYXRpb24gaW5mb3JtYXRpb24uIFRoZSBiZWxvdyBjb2RlIG91dHB1dHMgdG8gUi1zdHVkaW8sIGFzIHdlbGwgYXMgYSBQREYgZm9yIGVhc2llciB2aWV3aW5nLgoKYGBge3J9CgoKCiMgIGZvcihpIGluIDE6bnJvdyh0cmVhdG1lbnQubWVhbnMpKSAgIHsKIyAgICAKIyAKIyAgIGJveHBsb3QodChjYmluZChFUElfRE1Sc1tpLDJdLCBFUElfRE1Sc1tpLDNdLCBFUElfRE1Sc1tpLDRdLCBFUElfRE1Sc1tpLDVdKSkseGxpbSA9IGMoMC41LCAzLjUpLCB5bGltID0gYyhtaW4oRVBJX0RNUnNbaSwyOjEzXSksIG1heChFUElfRE1Sc1tpLDI6MTNdKSksIGJveGZpbGwgPSAiYmx1ZSIsIG5hbWVzID0gIkFtYmllbnQiLCBzaG93Lm5hbWVzID0gVFJVRSwgeWxhYiA9ICJQcm9wb3J0aW9uIG9mIHJlYWRzIG1ldGh5bGF0ZWQiKQojIAojIGJveHBsb3QodChjYmluZChFUElfRE1Sc1tpLDZdLCBFUElfRE1Sc1tpLDddLCBFUElfRE1Sc1tpLDhdLCBFUElfRE1Sc1tpLDldKSksIHhheHQgPSAibiIsIGFkZCA9IFRSVUUsIGF0ID0gMiwgYm94ZmlsbCA9ICJncmVlbiIpCiMgCiMgYm94cGxvdCh0KGNiaW5kKEVQSV9ETVJzW2ksMTBdLCBFUElfRE1Sc1tpLDExXSwgRVBJX0RNUnNbaSwxMl0sIEVQSV9ETVJzW2ksMTNdKSksIHhheHQgPSAibiIsIGFkZCA9IFRSVUUsIGF0ID0gMywgYm94ZmlsbCA9ICJyZWQiKQojIAojIGF4aXMoc2lkZSA9IDEsIGF0ID0gMiwgbGFiZWxzID0gIkxvdyIpCiMgYXhpcyhzaWRlID0gMSwgYXQgPSAzLCBsYWJlbHMgPSAiU3VwZXIgTG93IikKIyAKIyB0aXRsZShwYXN0ZTAoIlByb3BvcnRpb24gb2YgTWV0aHlsYXRlZCByZWFkcyBmb3IgRE1SIFxuIGxvY2F0ZWQgYXQgIiwgRVBJX0RNUnNbaSwxXSkpCiMgCiMgCiMgfQoKCnBkZihmaWxlID0gInRocmVleC1ETVItQm94LVBsb3RzLnBkZiIpCgpmb3IoaSBpbiAxOm5yb3codHJlYXRtZW50Lm1lYW5zKSkgICB7CgoKICBib3hwbG90KHQoY2JpbmQoRVBJX0RNUnNbaSw2XSwgRVBJX0RNUnNbaSw3XSwgRVBJX0RNUnNbaSwxMF0sIEVQSV9ETVJzW2ksMTFdKSkseGxpbSA9IGMoMC41LCAzLjUpLCB5bGltID0gYyhtaW4oRVBJX0RNUnNbaSwyOjEzXSksIG1heChFUElfRE1Sc1tpLDI6MTNdKSksIGJveGZpbGwgPSAiYmx1ZSIsIG5hbWVzID0gIkFtYmllbnQiLCBzaG93Lm5hbWVzID0gVFJVRSwgeWxhYiA9ICJQcm9wb3J0aW9uIG9mIHJlYWRzIG1ldGh5bGF0ZWQiKQoKYm94cGxvdCh0KGNiaW5kKEVQSV9ETVJzW2ksMl0sIEVQSV9ETVJzW2ksM10sIEVQSV9ETVJzW2ksOF0sIEVQSV9ETVJzW2ksOV0pKSwgeGF4dCA9ICJuIiwgYWRkID0gVFJVRSwgYXQgPSAyLCBib3hmaWxsID0gImdyZWVuIikKCmJveHBsb3QodChjYmluZChFUElfRE1Sc1tpLDRdLCBFUElfRE1Sc1tpLDVdLCBFUElfRE1Sc1tpLDEyXSwgRVBJX0RNUnNbaSwxM10pKSwgeGF4dCA9ICJuIiwgYWRkID0gVFJVRSwgYXQgPSAzLCBib3hmaWxsID0gInJlZCIpCgpheGlzKHNpZGUgPSAxLCBhdCA9IDIsIGxhYmVscyA9ICJMb3ciKQpheGlzKHNpZGUgPSAxLCBhdCA9IDMsIGxhYmVscyA9ICJTdXBlciBMb3ciKQoKdGl0bGUocGFzdGUwKCJQcm9wb3J0aW9uIG9mIE1ldGh5bGF0ZWQgcmVhZHMgZm9yIERNUiBcbiBsb2NhdGVkIGF0ICIsIEVQSV9ETVJzW2ksMV0pKQoKCn0KCmRldi5vZmYoKQoKYGBgCgpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ3RybCtBbHQrSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4=