For today, we’ll just set a working directory for all our chunks
library(knitr)
dir.create("output")
'output' already exists
setwd("~/Dropbox/me/mcb5472r/output") ## will only set the working directory for this chunk
The working directory was changed to /Users/gogartenlab/Dropbox/me/mcb5472r/output inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
opts_knit$set(root.dir = '~/Dropbox/me/mcb5472r/output') ## will set all chunks (note this doesn't always work and I have no explanation for why)
getwd() ## we'll add this test to make sure our setup script worked
library(dplyr)
library(tidyr)
library(ggplot2)
library(NOISeq)
## Super important note - some packages have functions that will cancel out other functions. Your last loaded function will be the one that's used, for example, if two functions are named the same, e.g. rename() in plyr and in dplyr are run differently, so you have to make sure to load the package you want. You can also load and unload a package within your chunk if you run into this problem
# We'll import a matrix of count data; this is the output from a bowtie2 alignment and salmon counting combined into a matrix
# There are lots of ways to import data
# Because we're in the directory where the file is located, you can just call the file name. You can also call the full path. Often your file might not be in the directory that you're working in, so it's useful to just use the full path (also helps you find your data later when you lose it...)
count_data <- read.table("~/Dropbox/me/mcb5472r/example.mat", header=T, com='', check.names=F)
# "count_data" is now an object in R that we can work with
# You should see it over in your Gllobal Environment window
#
# Let's have a look at our data
# Again, many ways to visualize
names(count_data) # will print out your column headers
head(count_data) # will show you the first few rows
# You can also click the object name in the Global Environment window to open it in a tab
# This will display a reasonable number of rows and you can scroll to see more
# If working with large datasets, this is not convenient
# For some analyses, you can't have fractional data. In some instances, it's ok to round
count_data <- round(count_data, 0) # this will round all your data to the nearest whole number
# We're going to assume for this dataset that if a partcular gene is expressed fewer than 10 times across all replicates, that it is an artefact and get rid of it. This cut off is a personal preference and will change depending on your dataset and your hypothesis (you may want more or less sensitivity)
count_data <- count_data[rowSums(count_data) > 10,]
# This transcriptome data has 4 samples - a00, a08, b00, and b08
# a and b correspond to replicates a and b; 00 and 08 correspond to time points at 0 hours and 8 hours
# We need to tell R what our replicates are and what are time points are
# We'll do this two ways - first by setting up factors and then by making a list
## factors are made by first making a dataframe with the information you want; this example has way more information than we'll need
myfactors = data.frame("rep" = substr(colnames(count_data), start=1, stop=1),
"time" = substr(colnames(count_data), start=2, stop=3),
"samp" = substr(colnames(count_data), start=1, stop=3),
"heading" = substr(colnames(count_data), start=1, stop=9))
rownames(myfactors) <- colnames(count_data) # this will transform the header from your data (sample ids) to the rownames of your factor file
save(myfactors, file = "myfactors_mate.RData") # this will save your object as RData so you can reload it without having to remake every time
# Now we'll look at the factors by clicking on it in Global Environment
# What kind of object is this? This is important to know when using certain functions to analyze your data
class(myfactors)
# lists are also very useful for a billion reasons
# we'll make a bunch of different lists
samps <- c("a00","a08","b00","b08")
time <- c("00","08")
rep1 <- c("a00_quant","a08_quant")
rep2 <- c("b00_quant","b08_quant")
# What kind of objects are your lists?
class(samps)
# Now let's make a basic plot. We want to know how nicely our replicates correspond to one another
plot(count_data) # basic r plot of all our data
plot(count_data$a00_quant,count_data$a08_quant) # r plot of hour 0 replicates
plot(count_data$a00_quant,count_data$a08_quant, xlim=c(0, 1000), ylim=c(0, 1000)) # let's zoom in
# now with ggplot2's quickplot function
qplot(a00_quant,b00_quant,data=count_data) #+
geom_point() #+ #adds points
xlim(c(0,1000)) + ylim(c(0,1000)) #+ #reduces axes lengths to zoom in on majority of points
labs(x = "rep1") + labs(y = "rep2") #+ #renames labels from column headers
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), aspect.ratio=1) #+ #removes grid and makes square
theme_bw() #+ #removes grey background
geom_smooth(method='loess', level=0.95, aes(fill = 'confidence'), alpha = 0.5) #adds regression line and 95% ci
# Principal Component Analysis plot - normally used to identify clustering patterns of biological and technical replicates;
# ran on data without replicates to see if any patterns stood out based on nutrient source or time;
# differences seem to emerge between the two treatments over time
tpmMatrix = cpm(count_data)
rnaseqMatrix = as.matrix(tpmMatrix)
rnaseqMatrix = round(rnaseqMatrix)
exp_study = DGEList(counts=rnaseqMatrix, group=factor(colnames(rnaseqMatrix)))
exp_study = calcNormFactors(exp_study, method = "TMM")
exp_study$samples$eff.lib.size = exp_study$samples$lib.size * exp_study$samples$norm.factors
tmm_table = cpm(exp_study)
mydata2 = readData(tmm_table, myfactors)
myPCA = dat(mydata2, type = "PCA")
explo.plot(myPCA, factor = "rep")
explo.plot(myPCA, factor = "time")
explo.plot(myPCA, factor = "samp")
## correlation test for replicates
dir.create("stats")
setwd("~/Dropbox/me/mcb5472r/output/stats")
pear_corr <- cor(count_data, use="all.obs",method="pearson")
pear_corr
write.table(pear_corr, file = "pear_corr.txt", sep = "\t", quote = FALSE)
spear_corr <- cor(count_data, use="all.obs",method="spearman")
spear_corr
write.table(spear_corr, file = "spear_corr.txt", sep = "\t", quote = FALSE)
# to use noiseq for your differential expression analysis, you must first make an object that noiseq can read
dds = NOISeq::readData(data = count_data, factors = myfactors)
save(dds, file ="mydata_mate.RData")
# i'm going to show you how to do this in a loop because this will be the most useful way to run this
# don't be scared, we'll go through it step by step
for(s1 in time){
for(s2 in time){
if(s1!=s2){
if(s1<s2){
print(c(s1,s2))
tmm = noiseqbio(dds, norm = "tmm", k = 0.5, factor = "time", conditions = c(s1,s2),
r = 50, filter = 1, nclust = 15, a0per= 0.9, random.seed = 12345, plot = TRUE)
tmm_r <- as.data.frame(tmm@results, row.names = NULL)
save(tmm_r, file = paste0("mate_",s1,"vs",s2,"_tmm.RData"))
write.table(tmm@results, paste0("mate_",s1,"vs",s2,"_tmm.txt"), sep = "\t", row.names = TRUE, col.names = NA, quote = FALSE)
tmm_r <- na.omit(tmm_r)
tmm_r$P <- with(tmm_r, 1-prob)
tmm_r$gene <- row.names(tmm_r)
tmm_r$EFFECTSIZE <- tmm_r$M
write.table(tmm_r, paste0("mate_",s1,"vs",s2,"_tmm_filtered.txt"), sep = "\t", row.names = TRUE, col.names = NA, quote = FALSE)
}}}}
# volcano plots are a common way to visualize differential expression data
# you can run this in conjunction with your de analysis
# i like to run it separately so that i can tweak the plot later for papers or do visualize differently
# again, we'll use a loop even though we only have one pair because you will most likely have multiple pairs
for(s1 in time){
for(s2 in time){
if(s1!=s2){
if(s1<s2){
print(c(s1,s2))
tmm_r <- read.delim(paste0("mate_",s1,"vs",s2,"_tmm_filtered.txt"), header=TRUE, row.names = NULL, com='', check.names=F)
plot(tmm_r$log2FC, -log10(1-tmm_r$prob), pch=20, xlim=c(-7,7), ylim=c(0,16), main = paste(s1,"vs",s2),
xlab = "log2FC", ylab = "-log10(p-value)",
col = ifelse(abs(tmm_r$log2FC)>5 & tmm_r$prob>0.999,"red",
ifelse(abs(tmm_r$log2FC)>5,"orange",
ifelse(tmm_r$prob>0.99,"green","black"))))
}}}}
LS0tCnRpdGxlOiAiSW50cm8gdG8gUiIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogQXJ0ZW1pcyBMb3V5YWtpcwpkYXRlOiAyMDE4LjAyLjIxCi0tLQoKIyMgRWFjaCBibG9jayBiZXR3ZWVuIHRoZSB0cmlwbGUgZ3JhdmUgYWNjZW50cyBpcyBhIGNodW5rCiMjIFlvdSBjYW4gdXNlIHRoZSBhcmUgb3V0c2lkZSBvZiB0aGUgY2h1bmtzIHRvIG1ha2Ugbm90ZXMgYWJvdXQgeW91ciBwcm9qZWN0CgpUaGlzIGlzIGEgbm90ZWJvb2sgd2l0aCBzb21lIGJhc2ljIFIgY29tbWFuZHMKCiMjIFRoaXMgaXMgd2hlcmUgeW91IGNhbiBzZXR1cCB5b3VyIG5vdGVib29rIGVudmlyb25tZW50CiMjIEZvciB0b2RheSwgd2UnbGwganVzdCBzZXQgYSB3b3JraW5nIGRpcmVjdG9yeSBmb3IgYWxsIG91ciBjaHVua3MKYGBge3Igc2V0dXB9CmxpYnJhcnkoa25pdHIpCmRpci5jcmVhdGUoIm91dHB1dCIpCnNldHdkKCJ+L0Ryb3Bib3gvbWUvbWNiNTQ3MnIvb3V0cHV0IikgIyMgd2lsbCBvbmx5IHNldCB0aGUgd29ya2luZyBkaXJlY3RvcnkgZm9yIHRoaXMgY2h1bmsKb3B0c19rbml0JHNldChyb290LmRpciA9ICd+L0Ryb3Bib3gvbWUvbWNiNTQ3MnIvb3V0cHV0JykgIyMgd2lsbCBzZXQgYWxsIGNodW5rcyAobm90ZSB0aGlzIGRvZXNuJ3QgYWx3YXlzIHdvcmsgYW5kIEkgaGF2ZSBubyBleHBsYW5hdGlvbiBmb3Igd2h5KQpgYGAKCgpgYGB7ciBsb2FkIGxpYnJhcmllc30KZ2V0d2QoKSAjIyB3ZSdsbCBhZGQgdGhpcyB0ZXN0IHRvIG1ha2Ugc3VyZSBvdXIgc2V0dXAgc2NyaXB0IHdvcmtlZApsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoTk9JU2VxKQoKIyMgU3VwZXIgaW1wb3J0YW50IG5vdGUgLSBzb21lIHBhY2thZ2VzIGhhdmUgZnVuY3Rpb25zIHRoYXQgd2lsbCBjYW5jZWwgb3V0IG90aGVyIGZ1bmN0aW9ucy4gWW91ciBsYXN0IGxvYWRlZCBmdW5jdGlvbiB3aWxsIGJlIHRoZSBvbmUgdGhhdCdzIHVzZWQsIGZvciBleGFtcGxlLCBpZiB0d28gZnVuY3Rpb25zIGFyZSBuYW1lZCB0aGUgc2FtZSwgZS5nLiByZW5hbWUoKSBpbiBwbHlyIGFuZCBpbiBkcGx5ciBhcmUgcnVuIGRpZmZlcmVudGx5LCBzbyB5b3UgaGF2ZSB0byBtYWtlIHN1cmUgdG8gbG9hZCB0aGUgcGFja2FnZSB5b3Ugd2FudC4gWW91IGNhbiBhbHNvIGxvYWQgYW5kIHVubG9hZCBhIHBhY2thZ2Ugd2l0aGluIHlvdXIgY2h1bmsgaWYgeW91IHJ1biBpbnRvIHRoaXMgcHJvYmxlbQpgYGAKCmBgYHtyIGltcG9ydCB5b3VyIGRhdGF9CiMgV2UnbGwgaW1wb3J0IGEgbWF0cml4IG9mIGNvdW50IGRhdGE7IHRoaXMgaXMgdGhlIG91dHB1dCBmcm9tIGEgYm93dGllMiBhbGlnbm1lbnQgYW5kIHNhbG1vbiBjb3VudGluZyBjb21iaW5lZCBpbnRvIGEgbWF0cml4CiMgVGhlcmUgYXJlIGxvdHMgb2Ygd2F5cyB0byBpbXBvcnQgZGF0YSAKIyBCZWNhdXNlIHdlJ3JlIGluIHRoZSBkaXJlY3Rvcnkgd2hlcmUgdGhlIGZpbGUgaXMgbG9jYXRlZCwgeW91IGNhbiBqdXN0IGNhbGwgdGhlIGZpbGUgbmFtZS4gWW91IGNhbiBhbHNvIGNhbGwgdGhlIGZ1bGwgcGF0aC4gT2Z0ZW4geW91ciBmaWxlIG1pZ2h0IG5vdCBiZSBpbiB0aGUgZGlyZWN0b3J5IHRoYXQgeW91J3JlIHdvcmtpbmcgaW4sIHNvIGl0J3MgdXNlZnVsIHRvIGp1c3QgdXNlIHRoZSBmdWxsIHBhdGggKGFsc28gaGVscHMgeW91IGZpbmQgeW91ciBkYXRhIGxhdGVyIHdoZW4geW91IGxvc2UgaXQuLi4pCmNvdW50X2RhdGEgPC0gcmVhZC50YWJsZSgifi9Ecm9wYm94L21lL21jYjU0NzJyL2V4YW1wbGUubWF0IiwgaGVhZGVyPVQsIGNvbT0nJywgY2hlY2submFtZXM9RikKCiMgImNvdW50X2RhdGEiIGlzIG5vdyBhbiBvYmplY3QgaW4gUiB0aGF0IHdlIGNhbiB3b3JrIHdpdGgKIyBZb3Ugc2hvdWxkIHNlZSBpdCBvdmVyIGluIHlvdXIgR2xsb2JhbCBFbnZpcm9ubWVudCB3aW5kb3cKIyAKYGBgCgpgYGB7cn0KIyBMZXQncyBoYXZlIGEgbG9vayBhdCBvdXIgZGF0YQojIEFnYWluLCBtYW55IHdheXMgdG8gdmlzdWFsaXplCm5hbWVzKGNvdW50X2RhdGEpICMgd2lsbCBwcmludCBvdXQgeW91ciBjb2x1bW4gaGVhZGVycwpoZWFkKGNvdW50X2RhdGEpICMgd2lsbCBzaG93IHlvdSB0aGUgZmlyc3QgZmV3IHJvd3MKCiMgWW91IGNhbiBhbHNvIGNsaWNrIHRoZSBvYmplY3QgbmFtZSBpbiB0aGUgR2xvYmFsIEVudmlyb25tZW50IHdpbmRvdyB0byBvcGVuIGl0IGluIGEgdGFiCiMgVGhpcyB3aWxsIGRpc3BsYXkgYSByZWFzb25hYmxlIG51bWJlciBvZiByb3dzIGFuZCB5b3UgY2FuIHNjcm9sbCB0byBzZWUgbW9yZQojIElmIHdvcmtpbmcgd2l0aCBsYXJnZSBkYXRhc2V0cywgdGhpcyBpcyBub3QgY29udmVuaWVudApgYGAKCgpgYGB7ciBtb2RpZnkgeW91ciBkYXRhfQojIEZvciBzb21lIGFuYWx5c2VzLCB5b3UgY2FuJ3QgaGF2ZSBmcmFjdGlvbmFsIGRhdGEuIEluIHNvbWUgaW5zdGFuY2VzLCBpdCdzIG9rIHRvIHJvdW5kCgpjb3VudF9kYXRhIDwtIHJvdW5kKGNvdW50X2RhdGEsIDApICMgdGhpcyB3aWxsIHJvdW5kIGFsbCB5b3VyIGRhdGEgdG8gdGhlIG5lYXJlc3Qgd2hvbGUgbnVtYmVyCgojIFdlJ3JlIGdvaW5nIHRvIGFzc3VtZSBmb3IgdGhpcyBkYXRhc2V0IHRoYXQgaWYgYSBwYXJ0Y3VsYXIgZ2VuZSBpcyBleHByZXNzZWQgZmV3ZXIgdGhhbiAxMCB0aW1lcyBhY3Jvc3MgYWxsIHJlcGxpY2F0ZXMsIHRoYXQgaXQgaXMgYW4gYXJ0ZWZhY3QgYW5kIGdldCByaWQgb2YgaXQuIFRoaXMgY3V0IG9mZiBpcyBhIHBlcnNvbmFsIHByZWZlcmVuY2UgYW5kIHdpbGwgY2hhbmdlIGRlcGVuZGluZyBvbiB5b3VyIGRhdGFzZXQgYW5kIHlvdXIgaHlwb3RoZXNpcyAoeW91IG1heSB3YW50IG1vcmUgb3IgbGVzcyBzZW5zaXRpdml0eSkKY291bnRfZGF0YSA8LSBjb3VudF9kYXRhW3Jvd1N1bXMoY291bnRfZGF0YSkgPiAxMCxdIApgYGAKCmBgYHtyIHRlbGwgUiBhYm91dCB5b3VyIGRhdGF9CiMgVGhpcyB0cmFuc2NyaXB0b21lIGRhdGEgaGFzIDQgc2FtcGxlcyAtIGEwMCwgYTA4LCBiMDAsIGFuZCBiMDgKIyBhIGFuZCBiIGNvcnJlc3BvbmQgdG8gcmVwbGljYXRlcyBhIGFuZCBiOyAwMCBhbmQgMDggY29ycmVzcG9uZCB0byB0aW1lIHBvaW50cyBhdCAwIGhvdXJzIGFuZCA4IGhvdXJzCiMgV2UgbmVlZCB0byB0ZWxsIFIgd2hhdCBvdXIgcmVwbGljYXRlcyBhcmUgYW5kIHdoYXQgYXJlIHRpbWUgcG9pbnRzIGFyZQojIFdlJ2xsIGRvIHRoaXMgdHdvIHdheXMgLSBmaXJzdCBieSBzZXR0aW5nIHVwIGZhY3RvcnMgYW5kIHRoZW4gYnkgbWFraW5nIGEgbGlzdAoKIyMgZmFjdG9ycyBhcmUgbWFkZSBieSBmaXJzdCBtYWtpbmcgYSBkYXRhZnJhbWUgd2l0aCB0aGUgaW5mb3JtYXRpb24geW91IHdhbnQ7IHRoaXMgZXhhbXBsZSBoYXMgd2F5IG1vcmUgaW5mb3JtYXRpb24gdGhhbiB3ZSdsbCBuZWVkCgpteWZhY3RvcnMgPSBkYXRhLmZyYW1lKCJyZXAiID0gc3Vic3RyKGNvbG5hbWVzKGNvdW50X2RhdGEpLCBzdGFydD0xLCBzdG9wPTEpLAogICAgICAgICAgICAgICAgICAgICAgICJ0aW1lIiA9IHN1YnN0cihjb2xuYW1lcyhjb3VudF9kYXRhKSwgc3RhcnQ9Miwgc3RvcD0zKSwKICAgICAgICAgICAgICAgICAgICAgICAic2FtcCIgPSBzdWJzdHIoY29sbmFtZXMoY291bnRfZGF0YSksIHN0YXJ0PTEsIHN0b3A9MyksCiAgICAgICAgICAgICAgICAgICAgICAgImhlYWRpbmciID0gc3Vic3RyKGNvbG5hbWVzKGNvdW50X2RhdGEpLCBzdGFydD0xLCBzdG9wPTkpKQpyb3duYW1lcyhteWZhY3RvcnMpIDwtIGNvbG5hbWVzKGNvdW50X2RhdGEpICMgdGhpcyB3aWxsIHRyYW5zZm9ybSB0aGUgaGVhZGVyIGZyb20geW91ciBkYXRhIChzYW1wbGUgaWRzKSB0byB0aGUgcm93bmFtZXMgb2YgeW91ciBmYWN0b3IgZmlsZQpzYXZlKG15ZmFjdG9ycywgZmlsZSA9ICJteWZhY3RvcnNfbWF0ZS5SRGF0YSIpICMgdGhpcyB3aWxsIHNhdmUgeW91ciBvYmplY3QgYXMgUkRhdGEgc28geW91IGNhbiByZWxvYWQgaXQgd2l0aG91dCBoYXZpbmcgdG8gcmVtYWtlIGV2ZXJ5IHRpbWUKCiMgTm93IHdlJ2xsIGxvb2sgYXQgdGhlIGZhY3RvcnMgYnkgY2xpY2tpbmcgb24gaXQgaW4gR2xvYmFsIEVudmlyb25tZW50CiMgV2hhdCBraW5kIG9mIG9iamVjdCBpcyB0aGlzPyBUaGlzIGlzIGltcG9ydGFudCB0byBrbm93IHdoZW4gdXNpbmcgY2VydGFpbiBmdW5jdGlvbnMgdG8gYW5hbHl6ZSB5b3VyIGRhdGEKY2xhc3MobXlmYWN0b3JzKQoKCiMgbGlzdHMgYXJlIGFsc28gdmVyeSB1c2VmdWwgZm9yIGEgYmlsbGlvbiByZWFzb25zCiMgd2UnbGwgbWFrZSBhIGJ1bmNoIG9mIGRpZmZlcmVudCBsaXN0cwpzYW1wcyA8LSBjKCJhMDAiLCJhMDgiLCJiMDAiLCJiMDgiKQp0aW1lIDwtIGMoIjAwIiwiMDgiKQpyZXAxIDwtIGMoImEwMF9xdWFudCIsImEwOF9xdWFudCIpCnJlcDIgPC0gYygiYjAwX3F1YW50IiwiYjA4X3F1YW50IikKCiMgV2hhdCBraW5kIG9mIG9iamVjdHMgYXJlIHlvdXIgbGlzdHM/CmNsYXNzKHNhbXBzKQpgYGAKCgpgYGB7ciBtYWtlIGEgYmFzaWMgcGxvdH0KIyBOb3cgbGV0J3MgbWFrZSBhIGJhc2ljIHBsb3QuIFdlIHdhbnQgdG8ga25vdyBob3cgbmljZWx5IG91ciByZXBsaWNhdGVzIGNvcnJlc3BvbmQgdG8gb25lIGFub3RoZXIKCnBsb3QoY291bnRfZGF0YSkgIyBiYXNpYyByIHBsb3Qgb2YgYWxsIG91ciBkYXRhCnBsb3QoY291bnRfZGF0YSRhMDBfcXVhbnQsY291bnRfZGF0YSRhMDhfcXVhbnQpICMgciBwbG90IG9mIGhvdXIgMCByZXBsaWNhdGVzCnBsb3QoY291bnRfZGF0YSRhMDBfcXVhbnQsY291bnRfZGF0YSRhMDhfcXVhbnQsIHhsaW09YygwLCAxMDAwKSwgeWxpbT1jKDAsIDEwMDApKSAjIGxldCdzIHpvb20gaW4KCiMgbm93IHdpdGggZ2dwbG90MidzIHF1aWNrcGxvdCBmdW5jdGlvbgoKcXBsb3QoYTAwX3F1YW50LGIwMF9xdWFudCxkYXRhPWNvdW50X2RhdGEpICMrIAogICAgICAgICAgZ2VvbV9wb2ludCgpICMrICNhZGRzIHBvaW50cwogICAgICAgICAgeGxpbShjKDAsMTAwMCkpICsgeWxpbShjKDAsMTAwMCkpICMrICNyZWR1Y2VzIGF4ZXMgbGVuZ3RocyB0byB6b29tIGluIG9uIG1ham9yaXR5IG9mIHBvaW50cwogICAgICAgICAgbGFicyh4ID0gInJlcDEiKSArIGxhYnMoeSA9ICJyZXAyIikgIysgI3JlbmFtZXMgbGFiZWxzIGZyb20gY29sdW1uIGhlYWRlcnMKICAgICAgICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIGFzcGVjdC5yYXRpbz0xKSAjKyAjcmVtb3ZlcyBncmlkIGFuZCBtYWtlcyBzcXVhcmUKICAgICAgICAgIHRoZW1lX2J3KCkgIysgI3JlbW92ZXMgZ3JleSBiYWNrZ3JvdW5kCiAgICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9J2xvZXNzJywgbGV2ZWw9MC45NSwgYWVzKGZpbGwgPSAnY29uZmlkZW5jZScpLCBhbHBoYSA9IDAuNSkgI2FkZHMgcmVncmVzc2lvbiBsaW5lIGFuZCA5NSUgY2kKYGBgCgoKCmBgYHtyIG5vcm1hbGl6aW5nIGRhdGEgYW5kIG1ha2luZyBQQ0EgcGxvdHN9CiMgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyBwbG90IC0gbm9ybWFsbHkgdXNlZCB0byBpZGVudGlmeSBjbHVzdGVyaW5nIHBhdHRlcm5zIG9mIGJpb2xvZ2ljYWwgYW5kIHRlY2huaWNhbCByZXBsaWNhdGVzOyAKIyByYW4gb24gZGF0YSB3aXRob3V0IHJlcGxpY2F0ZXMgdG8gc2VlIGlmIGFueSBwYXR0ZXJucyBzdG9vZCBvdXQgYmFzZWQgb24gbnV0cmllbnQgc291cmNlIG9yIHRpbWU7CiMgZGlmZmVyZW5jZXMgc2VlbSB0byBlbWVyZ2UgYmV0d2VlbiB0aGUgdHdvIHRyZWF0bWVudHMgb3ZlciB0aW1lCnRwbU1hdHJpeCA9IGNwbShjb3VudF9kYXRhKSAKcm5hc2VxTWF0cml4ID0gYXMubWF0cml4KHRwbU1hdHJpeCkKcm5hc2VxTWF0cml4ID0gcm91bmQocm5hc2VxTWF0cml4KQpleHBfc3R1ZHkgPSBER0VMaXN0KGNvdW50cz1ybmFzZXFNYXRyaXgsIGdyb3VwPWZhY3Rvcihjb2xuYW1lcyhybmFzZXFNYXRyaXgpKSkKZXhwX3N0dWR5ID0gY2FsY05vcm1GYWN0b3JzKGV4cF9zdHVkeSwgbWV0aG9kID0gIlRNTSIpCmV4cF9zdHVkeSRzYW1wbGVzJGVmZi5saWIuc2l6ZSA9IGV4cF9zdHVkeSRzYW1wbGVzJGxpYi5zaXplICogZXhwX3N0dWR5JHNhbXBsZXMkbm9ybS5mYWN0b3JzCnRtbV90YWJsZSA9IGNwbShleHBfc3R1ZHkpCm15ZGF0YTIgPSByZWFkRGF0YSh0bW1fdGFibGUsIG15ZmFjdG9ycykKbXlQQ0EgPSBkYXQobXlkYXRhMiwgdHlwZSA9ICJQQ0EiKQpleHBsby5wbG90KG15UENBLCBmYWN0b3IgPSAicmVwIikKZXhwbG8ucGxvdChteVBDQSwgZmFjdG9yID0gInRpbWUiKQpleHBsby5wbG90KG15UENBLCBmYWN0b3IgPSAic2FtcCIpCmBgYAoKCmBgYHtyIGRvIHNvbWUgYmFzaWMgc3RhdHN9CiMjIGNvcnJlbGF0aW9uIHRlc3QgZm9yIHJlcGxpY2F0ZXMKZGlyLmNyZWF0ZSgic3RhdHMiKQpzZXR3ZCgifi9Ecm9wYm94L21lL21jYjU0NzJyL291dHB1dC9zdGF0cyIpCgpwZWFyX2NvcnIgPC0gY29yKGNvdW50X2RhdGEsIHVzZT0iYWxsLm9icyIsbWV0aG9kPSJwZWFyc29uIikKcGVhcl9jb3JyCndyaXRlLnRhYmxlKHBlYXJfY29yciwgZmlsZSA9ICJwZWFyX2NvcnIudHh0Iiwgc2VwID0gIlx0IiwgcXVvdGUgPSBGQUxTRSkKCnNwZWFyX2NvcnIgPC0gY29yKGNvdW50X2RhdGEsIHVzZT0iYWxsLm9icyIsbWV0aG9kPSJzcGVhcm1hbiIpCnNwZWFyX2NvcnIKd3JpdGUudGFibGUoc3BlYXJfY29yciwgZmlsZSA9ICJzcGVhcl9jb3JyLnR4dCIsIHNlcCA9ICJcdCIsIHF1b3RlID0gRkFMU0UpCmBgYAoKYGBge3IgY29tcGxldGUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgb24gYWxsIHBhaXJzfQojIHRvIHVzZSBub2lzZXEgZm9yIHlvdXIgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMsIHlvdSBtdXN0IGZpcnN0IG1ha2UgYW4gb2JqZWN0IHRoYXQgbm9pc2VxIGNhbiByZWFkCmRkcyA9IE5PSVNlcTo6cmVhZERhdGEoZGF0YSA9IGNvdW50X2RhdGEsIGZhY3RvcnMgPSBteWZhY3RvcnMpCnNhdmUoZGRzLCBmaWxlID0ibXlkYXRhX21hdGUuUkRhdGEiKQoKIyBpJ20gZ29pbmcgdG8gc2hvdyB5b3UgaG93IHRvIGRvIHRoaXMgaW4gYSBsb29wIGJlY2F1c2UgdGhpcyB3aWxsIGJlIHRoZSBtb3N0IHVzZWZ1bCB3YXkgdG8gcnVuIHRoaXMKIyBkb24ndCBiZSBzY2FyZWQsIHdlJ2xsIGdvIHRocm91Z2ggaXQgc3RlcCBieSBzdGVwCmZvcihzMSBpbiB0aW1lKXsKICBmb3IoczIgaW4gdGltZSl7CiAgICBpZihzMSE9czIpewogICAgICBpZihzMTxzMil7CiAgICAgICAgcHJpbnQoYyhzMSxzMikpCiAgICAgICAgdG1tID0gbm9pc2VxYmlvKGRkcywgbm9ybSA9ICJ0bW0iLCBrID0gMC41LCBmYWN0b3IgPSAidGltZSIsIGNvbmRpdGlvbnMgPSBjKHMxLHMyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgciA9IDUwLCBmaWx0ZXIgPSAxLCBuY2x1c3QgPSAxNSwgYTBwZXI9IDAuOSwgcmFuZG9tLnNlZWQgPSAxMjM0NSwgcGxvdCA9IFRSVUUpCiAgICAgICAgdG1tX3IgPC0gYXMuZGF0YS5mcmFtZSh0bW1AcmVzdWx0cywgcm93Lm5hbWVzID0gTlVMTCkKICAgICAgICBzYXZlKHRtbV9yLCBmaWxlID0gcGFzdGUwKCJtYXRlXyIsczEsInZzIixzMiwiX3RtbS5SRGF0YSIpKQogICAgICAgIHdyaXRlLnRhYmxlKHRtbUByZXN1bHRzLCBwYXN0ZTAoIm1hdGVfIixzMSwidnMiLHMyLCJfdG1tLnR4dCIpLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBOQSwgcXVvdGUgPSBGQUxTRSkKICAgICAgICB0bW1fciA8LSBuYS5vbWl0KHRtbV9yKQogICAgICAgIHRtbV9yJFAgPC0gd2l0aCh0bW1fciwgMS1wcm9iKQogICAgICAgIHRtbV9yJGdlbmUgPC0gcm93Lm5hbWVzKHRtbV9yKQogICAgICAgIHRtbV9yJEVGRkVDVFNJWkUgPC0gdG1tX3IkTQogICAgICAgIHdyaXRlLnRhYmxlKHRtbV9yLCBwYXN0ZTAoIm1hdGVfIixzMSwidnMiLHMyLCJfdG1tX2ZpbHRlcmVkLnR4dCIpLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBOQSwgcXVvdGUgPSBGQUxTRSkKfX19fQpgYGAKCmBgYHtyIHZvbGNhbm8gcGxvdHN9CiMgdm9sY2FubyBwbG90cyBhcmUgYSBjb21tb24gd2F5IHRvIHZpc3VhbGl6ZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBkYXRhCiMgeW91IGNhbiBydW4gdGhpcyBpbiBjb25qdW5jdGlvbiB3aXRoIHlvdXIgZGUgYW5hbHlzaXMKIyBpIGxpa2UgdG8gcnVuIGl0IHNlcGFyYXRlbHkgc28gdGhhdCBpIGNhbiB0d2VhayB0aGUgcGxvdCBsYXRlciBmb3IgcGFwZXJzIG9yIGRvIHZpc3VhbGl6ZSBkaWZmZXJlbnRseQojIGFnYWluLCB3ZSdsbCB1c2UgYSBsb29wIGV2ZW4gdGhvdWdoIHdlIG9ubHkgaGF2ZSBvbmUgcGFpciBiZWNhdXNlIHlvdSB3aWxsIG1vc3QgbGlrZWx5IGhhdmUgbXVsdGlwbGUgcGFpcnMKCmZvcihzMSBpbiB0aW1lKXsKICBmb3IoczIgaW4gdGltZSl7CiAgICBpZihzMSE9czIpewogICAgICBpZihzMTxzMil7CiAgICAgICAgcHJpbnQoYyhzMSxzMikpCiAgICAgICAgdG1tX3IgPC0gcmVhZC5kZWxpbShwYXN0ZTAoIm1hdGVfIixzMSwidnMiLHMyLCJfdG1tX2ZpbHRlcmVkLnR4dCIpLCBoZWFkZXI9VFJVRSwgcm93Lm5hbWVzID0gTlVMTCwgY29tPScnLCBjaGVjay5uYW1lcz1GKQogICAgICAgIHBsb3QodG1tX3IkbG9nMkZDLCAtbG9nMTAoMS10bW1fciRwcm9iKSwgcGNoPTIwLCB4bGltPWMoLTcsNyksIHlsaW09YygwLDE2KSwgbWFpbiA9IHBhc3RlKHMxLCJ2cyIsczIpLCAKICAgICAgICAgIHhsYWIgPSAibG9nMkZDIiwgeWxhYiA9ICItbG9nMTAocC12YWx1ZSkiLAogICAgICAgICAgICBjb2wgPSBpZmVsc2UoYWJzKHRtbV9yJGxvZzJGQyk+NSAmIHRtbV9yJHByb2I+MC45OTksInJlZCIsCiAgICAgICAgICAgICAgaWZlbHNlKGFicyh0bW1fciRsb2cyRkMpPjUsIm9yYW5nZSIsCiAgICAgICAgICAgICAgICBpZmVsc2UodG1tX3IkcHJvYj4wLjk5LCJncmVlbiIsImJsYWNrIikpKSkKfX19fQpgYGAKCgoKCgoKCgoKCiMjIHRoZSBlbmQgIyM=