This page described the code and the result of C1q data shared by Inge.

Identification of differential acceessibilities

First, the region x sample count matrix was loaded in R and removed non-acceessible regions in most of the samples

inge = read.table("ChIP-seq raw technical reps n4 RPMI C1q.txt")
library(edgeR)
cpms = cpm(inge)
keep = rowSums(cpms > 1) >= 2
inge = inge[keep,]

Because this is a multifactor design and donor variability should be removed by GLM. Therefore, we make a design matrix and donor-variability is removed.

coldata =data.frame(row.names = colnames(inge))
coldata$donor = c(rep("donor1",2),rep("donor2",2),rep("donor3",2),rep("donor4",2))
coldata$condition = rep(c("RPMI","C1q"),4)
design = model.matrix( ~ donor + condition, coldata)
design
       (Intercept) donordonor2 donordonor3 donordonor4 conditionRPMI
RPMIn1           1           0           0           0             1
C1qn1            1           0           0           0             0
RPMIn2           1           1           0           0             1
C1qn2            1           1           0           0             0
RPMIn3           1           0           1           0             1
C1qn3            1           0           1           0             0
RPMIn4           1           0           0           1             1
C1qn4            1           0           0           1             0
attr(,"assign")
[1] 0 1 1 1 2
attr(,"contrasts")
attr(,"contrasts")$donor
[1] "contr.treatment"

attr(,"contrasts")$condition
[1] "contr.treatment"
d = DGEList(counts = inge, group = rep(c("RPMI","C1q"),4),sample = coldata)
d = calcNormFactors(d)
plotMDS(d, labels = rownames(coldata),col = c("darkgreen","blue")[factor(coldata$condition)])

d2 = estimateGLMTrendedDisp(d, design)
d2 = estimateGLMTagwiseDisp(d2, design)
f = glmFit(d2, design)
de = glmLRT(f, coef = 5)
tt = topTags(de, n = nrow(d))
head(tt$table)

Keep in mind that C1q is 0 and RPMI is 1 in this design matrix and this means that logFC > 0 is downregulated (i.e.Ā this program calculats RMPI/C1q, not C1q/RPMI)

A good thing is that C1q and RPMI samples are likely clustered seperately in the MDS plot. But, the result suggests that the most of regions are not FDR<0.05. Now we checked the number of differential accessibilities in various threshold.

library(ggplot2)
das = tt$table
rownames(das) = paste0("chr",rownames(das))

#FDR < 0.05
tmp1 = nrow(subset(das,FDR < 0.05 & logFC < 0))
tmp2 = nrow(subset(das,FDR < 0.05 & logFC > 0))

#Pvalue < 0.01
tmp3 = nrow(subset(das,PValue < 0.01 & logFC < 0))
tmp4 = nrow(subset(das,PValue < 0.01 & logFC > 0))

#Pvalue < 0.05
tmp5 = nrow(subset(das,PValue < 0.05 & logFC < 0))
tmp6 = nrow(subset(das,PValue < 0.05 & logFC > 0))

df = data.frame(threshold=rep(c("FDR0.05","Pval0.01","Pval0.05"),each=2),Up_Down=rep(c("Up","Down"),3),Number=c(tmp1,-tmp2,tmp3,-tmp4,tmp5,-tmp6)) 
df$Up_Down = factor(df$Up_Down,levels = c("Up","Down"))

p = ggplot(df,aes(x= threshold,y=Number,fill=Up_Down)) + geom_bar(stat = "identity")
p + theme_minimal() + coord_flip()

As FDR< 0.05 threshold gives us almost no regions, we set P val <0.01 as a threshold. We may not be able to say ā€œsignificantlyā€ differential accessibilities, but we will see a trend of differential accessibilities induced by C1q.

Peak annotation

Annotation of all peaks

Now we identified differential accessibility between RPMI and C1q samples. Next step is to annotate peaks. To annotate, I use ChIPseeker. The coordinate notion in the original data is without ā€œchrā€ and some software does not accept this format. So, I add ā€œchrā€ in the coordinate before starting annotation. First, we look at all differential accessibilities (Upregulated and downregulated) and then check up- and down-regulated regions indivisually.

Here I show the peaksā€™ genomic context and some enriched ontologies in the text format and dotplot.

library(GenomicRanges)
library(ChIPseeker)
library(TxDb.Hsapiens.UCSC.hg38.knownGene)
library(org.Hs.eg.db)
library(clusterProfiler)
das = subset(tt$table,  PValue  < 0.01)
rownames(das) =paste0("chr",rownames(das))
gr = GRanges(rownames(das))
gr_df = as.data.frame(gr)
peakAnno <- annotatePeak(gr, tssRegion=c(-3000, 3000),TxDb=TxDb.Hsapiens.UCSC.hg38.knownGene, annoDb="org.Hs.eg.db")
>> preparing features information...         2024-01-29 14:11:46 
>> identifying nearest features...       2024-01-29 14:11:46 
>> calculating distance from peak to TSS...  2024-01-29 14:11:47 
>> assigning genomic annotation...       2024-01-29 14:11:47 
>> adding gene annotation...             2024-01-29 14:11:51 
'select()' returned 1:many mapping between keys and columns
>> assigning chromosome lengths          2024-01-29 14:11:51 
>> done...                   2024-01-29 14:11:52 
plotAnnoPie(peakAnno)

gene <- seq2gene(gr, tssRegion = c(-1000, 1000), flankDistance = 3000, TxDb=TxDb.Hsapiens.UCSC.hg38.knownGene)
pathway2 = enrichGO(gene,OrgDb = org.Hs.eg.db,ont="BP",readable = T)
head(pathway2, 5)
dotplot(pathway2)

write.table(as.data.frame(pathway2),"EnrichedOntology_Pval0.01.txt",sep = "\t",quote = F)
#checking peakAnno and das have same order
tmp = paste(as.data.frame(peakAnno)$seqnames,as.data.frame(peakAnno)$start,sep =":")
tmp = paste(tmp,as.data.frame(peakAnno)$end, sep="-")
if( sum(tmp== rownames(das))== nrow(das)){
  das = cbind(das,as.data.frame(peakAnno))
  write.table(das,"DiffAcc_PVal0.01.txt",sep = "\t",quote = F)
}

Annotation of upregulated peaks only

## Upegulated
das = subset(tt$table,  PValue  < 0.01 & logFC <0)
rownames(das) =paste0("chr",rownames(das))
gr = GRanges(rownames(das))
gr_df = as.data.frame(gr)
peakAnno <- annotatePeak(gr, tssRegion=c(-3000, 3000),TxDb=TxDb.Hsapiens.UCSC.hg38.knownGene, annoDb="org.Hs.eg.db")
>> preparing features information...         2024-01-29 14:12:12 
>> identifying nearest features...       2024-01-29 14:12:12 
>> calculating distance from peak to TSS...  2024-01-29 14:12:12 
>> assigning genomic annotation...       2024-01-29 14:12:12 
>> adding gene annotation...             2024-01-29 14:12:17 
'select()' returned 1:many mapping between keys and columns
>> assigning chromosome lengths          2024-01-29 14:12:17 
>> done...                   2024-01-29 14:12:17 
plotAnnoPie(peakAnno)

gene <- seq2gene(gr, tssRegion = c(-1000, 1000), flankDistance = 3000, TxDb=TxDb.Hsapiens.UCSC.hg38.knownGene)
pathway2 = enrichGO(gene,OrgDb = org.Hs.eg.db,ont="BP",readable = T)
head(pathway2, 5)
dotplot(pathway2)

write.table(as.data.frame(pathway2),"EnrichedOntology_Pval0.01_Up.txt",sep = "\t",quote = F)
#checking peakAnno and das have same order
tmp = paste(as.data.frame(peakAnno)$seqnames,as.data.frame(peakAnno)$start,sep =":")
tmp = paste(tmp,as.data.frame(peakAnno)$end, sep="-")
if( sum(tmp== rownames(das))== nrow(das)){
  das = cbind(das,as.data.frame(peakAnno))
  write.table(das,"DiffAcc_PVal0.01_Up.txt",sep = "\t",quote = F)
}

Annotation of downregulated peaks only

## Downregulated
das = subset(tt$table,  PValue  < 0.01 & logFC >0)
rownames(das) =paste0("chr",rownames(das))
gr = GRanges(rownames(das))
gr_df = as.data.frame(gr)
peakAnno <- annotatePeak(gr, tssRegion=c(-3000, 3000),TxDb=TxDb.Hsapiens.UCSC.hg38.knownGene, annoDb="org.Hs.eg.db")
plotAnnoPie(peakAnno)
gene <- seq2gene(gr, tssRegion = c(-1000, 1000), flankDistance = 3000, TxDb=TxDb.Hsapiens.UCSC.hg38.knownGene)
pathway2 = enrichGO(gene,OrgDb = org.Hs.eg.db,ont="BP",readable = T)
head(pathway2, 5)
dotplot(pathway2)
write.table(as.data.frame(pathway2),"EnrichedOntology_Pval0.01_Down.txt",sep = "\t",quote = F)
#checking peakAnno and das have same order
tmp = paste(as.data.frame(peakAnno)$seqnames,as.data.frame(peakAnno)$start,sep =":")
tmp = paste(tmp,as.data.frame(peakAnno)$end, sep="-")
if( sum(tmp== rownames(das))== nrow(das)){
  das = cbind(das,as.data.frame(peakAnno))
  write.table(das,"DiffAcc_PVal0.01_Down.txt",sep = "\t",quote = F)
}
LS0tCnRpdGxlOiAiUmFwaGHDq2wgQzFxIGRhdGEgYW5hbHlzaXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawphdXRob3I6ICJZdXRha2EgTmVnaXNoaSAoeXV0YWthQG1obGFuZ2FsYWIub3JnKSIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgotLS0KCgpUaGlzIHBhZ2UgZGVzY3JpYmVkIHRoZSBjb2RlIGFuZCB0aGUgcmVzdWx0IG9mIFtDMXEgZGF0YV0oaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xUlVVNjZKRkJMNkJxV1AxTXJydWN4S3VRdG51WlFpUUMvdmlldz91c3A9c2hhcmluZykgc2hhcmVkIGJ5IEluZ2UuCiAKIyMgSWRlbnRpZmljYXRpb24gb2YgZGlmZmVyZW50aWFsIGFjY2Vlc3NpYmlsaXRpZXMKCkZpcnN0LCB0aGUgcmVnaW9uIHggc2FtcGxlIGNvdW50IG1hdHJpeCB3YXMgbG9hZGVkIGluIFIgYW5kIHJlbW92ZWQgbm9uLWFjY2Vlc3NpYmxlIHJlZ2lvbnMgaW4gbW9zdCBvZiB0aGUgc2FtcGxlcwoKYGBge3J9CmluZ2UgPSByZWFkLnRhYmxlKCJDaElQLXNlcSByYXcgdGVjaG5pY2FsIHJlcHMgbjQgUlBNSSBDMXEudHh0IikKbGlicmFyeShlZGdlUikKY3BtcyA9IGNwbShpbmdlKQprZWVwID0gcm93U3VtcyhjcG1zID4gMSkgPj0gMgppbmdlID0gaW5nZVtrZWVwLF0KYGBgCgoKQmVjYXVzZSB0aGlzIGlzIGEgbXVsdGlmYWN0b3IgZGVzaWduIGFuZCBkb25vciB2YXJpYWJpbGl0eSBzaG91bGQgYmUgcmVtb3ZlZCBieSBHTE0uIFRoZXJlZm9yZSwgd2UgbWFrZSBhIGRlc2lnbiBtYXRyaXggYW5kIGRvbm9yLXZhcmlhYmlsaXR5IGlzIHJlbW92ZWQuICAKCmBgYHtyfQpjb2xkYXRhID1kYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGNvbG5hbWVzKGluZ2UpKQpjb2xkYXRhJGRvbm9yID0gYyhyZXAoImRvbm9yMSIsMikscmVwKCJkb25vcjIiLDIpLHJlcCgiZG9ub3IzIiwyKSxyZXAoImRvbm9yNCIsMikpCmNvbGRhdGEkY29uZGl0aW9uID0gcmVwKGMoIlJQTUkiLCJDMXEiKSw0KQpkZXNpZ24gPSBtb2RlbC5tYXRyaXgoIH4gZG9ub3IgKyBjb25kaXRpb24sIGNvbGRhdGEpCmRlc2lnbgpkID0gREdFTGlzdChjb3VudHMgPSBpbmdlLCBncm91cCA9IHJlcChjKCJSUE1JIiwiQzFxIiksNCksc2FtcGxlID0gY29sZGF0YSkKZCA9IGNhbGNOb3JtRmFjdG9ycyhkKQpwbG90TURTKGQsIGxhYmVscyA9IHJvd25hbWVzKGNvbGRhdGEpLGNvbCA9IGMoImRhcmtncmVlbiIsImJsdWUiKVtmYWN0b3IoY29sZGF0YSRjb25kaXRpb24pXSkKZDIgPSBlc3RpbWF0ZUdMTVRyZW5kZWREaXNwKGQsIGRlc2lnbikKZDIgPSBlc3RpbWF0ZUdMTVRhZ3dpc2VEaXNwKGQyLCBkZXNpZ24pCmYgPSBnbG1GaXQoZDIsIGRlc2lnbikKZGUgPSBnbG1MUlQoZiwgY29lZiA9IDUpCnR0ID0gdG9wVGFncyhkZSwgbiA9IG5yb3coZCkpCmhlYWQodHQkdGFibGUpCmBgYApLZWVwIGluIG1pbmQgdGhhdCBDMXEgaXMgMCBhbmQgUlBNSSBpcyAxIGluIHRoaXMgZGVzaWduIG1hdHJpeCBhbmQgdGhpcyBtZWFucyB0aGF0IGxvZ0ZDID4gMCBpcyBkb3ducmVndWxhdGVkIChpLmUuIHRoaXMgcHJvZ3JhbSBjYWxjdWxhdHMgUk1QSS9DMXEsIG5vdCBDMXEvUlBNSSkKCkEgZ29vZCB0aGluZyBpcyB0aGF0IEMxcSBhbmQgUlBNSSBzYW1wbGVzIGFyZSBsaWtlbHkgY2x1c3RlcmVkIHNlcGVyYXRlbHkgaW4gdGhlIE1EUyBwbG90LiBCdXQsIHRoZSByZXN1bHQgc3VnZ2VzdHMgdGhhdCB0aGUgbW9zdCBvZiByZWdpb25zIGFyZSBub3QgRkRSPDAuMDUuIE5vdyB3ZSBjaGVja2VkIHRoZSBudW1iZXIgb2YgZGlmZmVyZW50aWFsIGFjY2Vzc2liaWxpdGllcyBpbiB2YXJpb3VzIHRocmVzaG9sZC4KCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpkYXMgPSB0dCR0YWJsZQpyb3duYW1lcyhkYXMpID0gcGFzdGUwKCJjaHIiLHJvd25hbWVzKGRhcykpCgojRkRSIDwgMC4wNQp0bXAxID0gbnJvdyhzdWJzZXQoZGFzLEZEUiA8IDAuMDUgJiBsb2dGQyA8IDApKQp0bXAyID0gbnJvdyhzdWJzZXQoZGFzLEZEUiA8IDAuMDUgJiBsb2dGQyA+IDApKQoKI1B2YWx1ZSA8IDAuMDEKdG1wMyA9IG5yb3coc3Vic2V0KGRhcyxQVmFsdWUgPCAwLjAxICYgbG9nRkMgPCAwKSkKdG1wNCA9IG5yb3coc3Vic2V0KGRhcyxQVmFsdWUgPCAwLjAxICYgbG9nRkMgPiAwKSkKCiNQdmFsdWUgPCAwLjA1CnRtcDUgPSBucm93KHN1YnNldChkYXMsUFZhbHVlIDwgMC4wNSAmIGxvZ0ZDIDwgMCkpCnRtcDYgPSBucm93KHN1YnNldChkYXMsUFZhbHVlIDwgMC4wNSAmIGxvZ0ZDID4gMCkpCgpkZiA9IGRhdGEuZnJhbWUodGhyZXNob2xkPXJlcChjKCJGRFIwLjA1IiwiUHZhbDAuMDEiLCJQdmFsMC4wNSIpLGVhY2g9MiksVXBfRG93bj1yZXAoYygiVXAiLCJEb3duIiksMyksTnVtYmVyPWModG1wMSwtdG1wMix0bXAzLC10bXA0LHRtcDUsLXRtcDYpKSAKZGYkVXBfRG93biA9IGZhY3RvcihkZiRVcF9Eb3duLGxldmVscyA9IGMoIlVwIiwiRG93biIpKQoKcCA9IGdncGxvdChkZixhZXMoeD0gdGhyZXNob2xkLHk9TnVtYmVyLGZpbGw9VXBfRG93bikpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpCnAgKyB0aGVtZV9taW5pbWFsKCkgKyBjb29yZF9mbGlwKCkKYGBgCgpBcyBGRFI8IDAuMDUgdGhyZXNob2xkIGdpdmVzIHVzIGFsbW9zdCBubyByZWdpb25zLCB3ZSBzZXQgUCB2YWwgPDAuMDEgYXMgYSB0aHJlc2hvbGQuIFdlIG1heSBub3QgYmUgYWJsZSB0byBzYXkgInNpZ25pZmljYW50bHkiIGRpZmZlcmVudGlhbCBhY2Nlc3NpYmlsaXRpZXMsIGJ1dCB3ZSB3aWxsIHNlZSBhIHRyZW5kIG9mIGRpZmZlcmVudGlhbCBhY2Nlc3NpYmlsaXRpZXMgaW5kdWNlZCBieSBDMXEuCgojIyBQZWFrIGFubm90YXRpb24KIyMjIEFubm90YXRpb24gb2YgYWxsIHBlYWtzCgpOb3cgd2UgaWRlbnRpZmllZCBkaWZmZXJlbnRpYWwgYWNjZXNzaWJpbGl0eSBiZXR3ZWVuIFJQTUkgYW5kIEMxcSBzYW1wbGVzLiBOZXh0IHN0ZXAgaXMgdG8gYW5ub3RhdGUgcGVha3MuIFRvIGFubm90YXRlLCBJIHVzZSBbQ2hJUHNlZWtlcl0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvQ2hJUHNlZWtlci9pbnN0L2RvYy9DaElQc2Vla2VyLmh0bWwpLgpUaGUgY29vcmRpbmF0ZSBub3Rpb24gaW4gdGhlIG9yaWdpbmFsIGRhdGEgaXMgd2l0aG91dCAiY2hyIiBhbmQgc29tZSBzb2Z0d2FyZSBkb2VzIG5vdCBhY2NlcHQgdGhpcyBmb3JtYXQuIFNvLCBJIGFkZCAiY2hyIiBpbiB0aGUgY29vcmRpbmF0ZSBiZWZvcmUgc3RhcnRpbmcgYW5ub3RhdGlvbi4KRmlyc3QsIHdlIGxvb2sgYXQgYWxsIGRpZmZlcmVudGlhbCBhY2Nlc3NpYmlsaXRpZXMgKFVwcmVndWxhdGVkIGFuZCBkb3ducmVndWxhdGVkKSBhbmQgdGhlbiBjaGVjayB1cC0gYW5kIGRvd24tcmVndWxhdGVkIHJlZ2lvbnMgaW5kaXZpc3VhbGx5LgoKSGVyZSBJIHNob3cgdGhlIHBlYWtzJyBnZW5vbWljIGNvbnRleHQgYW5kIHNvbWUgZW5yaWNoZWQgb250b2xvZ2llcyBpbiB0aGUgdGV4dCBmb3JtYXQgYW5kIGRvdHBsb3QuCgpgYGB7cn0KbGlicmFyeShHZW5vbWljUmFuZ2VzKQpsaWJyYXJ5KENoSVBzZWVrZXIpCmxpYnJhcnkoVHhEYi5Ic2FwaWVucy5VQ1NDLmhnMzgua25vd25HZW5lKQpsaWJyYXJ5KG9yZy5Icy5lZy5kYikKbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCmRhcyA9IHN1YnNldCh0dCR0YWJsZSwgIFBWYWx1ZSAgPCAwLjAxKQpyb3duYW1lcyhkYXMpID1wYXN0ZTAoImNociIscm93bmFtZXMoZGFzKSkKZ3IgPSBHUmFuZ2VzKHJvd25hbWVzKGRhcykpCmdyX2RmID0gYXMuZGF0YS5mcmFtZShncikKcGVha0Fubm8gPC0gYW5ub3RhdGVQZWFrKGdyLCB0c3NSZWdpb249YygtMzAwMCwgMzAwMCksVHhEYj1UeERiLkhzYXBpZW5zLlVDU0MuaGczOC5rbm93bkdlbmUsIGFubm9EYj0ib3JnLkhzLmVnLmRiIikKcGxvdEFubm9QaWUocGVha0Fubm8pCmdlbmUgPC0gc2VxMmdlbmUoZ3IsIHRzc1JlZ2lvbiA9IGMoLTEwMDAsIDEwMDApLCBmbGFua0Rpc3RhbmNlID0gMzAwMCwgVHhEYj1UeERiLkhzYXBpZW5zLlVDU0MuaGczOC5rbm93bkdlbmUpCnBhdGh3YXkyID0gZW5yaWNoR08oZ2VuZSxPcmdEYiA9IG9yZy5Icy5lZy5kYixvbnQ9IkJQIixyZWFkYWJsZSA9IFQpCmhlYWQocGF0aHdheTIsIDUpCmRvdHBsb3QocGF0aHdheTIpCndyaXRlLnRhYmxlKGFzLmRhdGEuZnJhbWUocGF0aHdheTIpLCJFbnJpY2hlZE9udG9sb2d5X1B2YWwwLjAxLnR4dCIsc2VwID0gIlx0IixxdW90ZSA9IEYpCiNjaGVja2luZyBwZWFrQW5ubyBhbmQgZGFzIGhhdmUgc2FtZSBvcmRlcgp0bXAgPSBwYXN0ZShhcy5kYXRhLmZyYW1lKHBlYWtBbm5vKSRzZXFuYW1lcyxhcy5kYXRhLmZyYW1lKHBlYWtBbm5vKSRzdGFydCxzZXAgPSI6IikKdG1wID0gcGFzdGUodG1wLGFzLmRhdGEuZnJhbWUocGVha0Fubm8pJGVuZCwgc2VwPSItIikKaWYoIHN1bSh0bXA9PSByb3duYW1lcyhkYXMpKT09IG5yb3coZGFzKSl7CiAgZGFzID0gY2JpbmQoZGFzLGFzLmRhdGEuZnJhbWUocGVha0Fubm8pKQogIHdyaXRlLnRhYmxlKGRhcywiRGlmZkFjY19QVmFsMC4wMS50eHQiLHNlcCA9ICJcdCIscXVvdGUgPSBGKQp9CmBgYAojIyMgQW5ub3RhdGlvbiBvZiB1cHJlZ3VsYXRlZCBwZWFrcyBvbmx5CgpgYGB7cn0KIyMgVXBlZ3VsYXRlZApkYXMgPSBzdWJzZXQodHQkdGFibGUsICBQVmFsdWUgIDwgMC4wMSAmIGxvZ0ZDIDwwKQpyb3duYW1lcyhkYXMpID1wYXN0ZTAoImNociIscm93bmFtZXMoZGFzKSkKZ3IgPSBHUmFuZ2VzKHJvd25hbWVzKGRhcykpCmdyX2RmID0gYXMuZGF0YS5mcmFtZShncikKcGVha0Fubm8gPC0gYW5ub3RhdGVQZWFrKGdyLCB0c3NSZWdpb249YygtMzAwMCwgMzAwMCksVHhEYj1UeERiLkhzYXBpZW5zLlVDU0MuaGczOC5rbm93bkdlbmUsIGFubm9EYj0ib3JnLkhzLmVnLmRiIikKcGxvdEFubm9QaWUocGVha0Fubm8pCmdlbmUgPC0gc2VxMmdlbmUoZ3IsIHRzc1JlZ2lvbiA9IGMoLTEwMDAsIDEwMDApLCBmbGFua0Rpc3RhbmNlID0gMzAwMCwgVHhEYj1UeERiLkhzYXBpZW5zLlVDU0MuaGczOC5rbm93bkdlbmUpCnBhdGh3YXkyID0gZW5yaWNoR08oZ2VuZSxPcmdEYiA9IG9yZy5Icy5lZy5kYixvbnQ9IkJQIixyZWFkYWJsZSA9IFQpCmhlYWQocGF0aHdheTIsIDUpCmRvdHBsb3QocGF0aHdheTIpCndyaXRlLnRhYmxlKGFzLmRhdGEuZnJhbWUocGF0aHdheTIpLCJFbnJpY2hlZE9udG9sb2d5X1B2YWwwLjAxX1VwLnR4dCIsc2VwID0gIlx0IixxdW90ZSA9IEYpCiNjaGVja2luZyBwZWFrQW5ubyBhbmQgZGFzIGhhdmUgc2FtZSBvcmRlcgp0bXAgPSBwYXN0ZShhcy5kYXRhLmZyYW1lKHBlYWtBbm5vKSRzZXFuYW1lcyxhcy5kYXRhLmZyYW1lKHBlYWtBbm5vKSRzdGFydCxzZXAgPSI6IikKdG1wID0gcGFzdGUodG1wLGFzLmRhdGEuZnJhbWUocGVha0Fubm8pJGVuZCwgc2VwPSItIikKaWYoIHN1bSh0bXA9PSByb3duYW1lcyhkYXMpKT09IG5yb3coZGFzKSl7CiAgZGFzID0gY2JpbmQoZGFzLGFzLmRhdGEuZnJhbWUocGVha0Fubm8pKQogIHdyaXRlLnRhYmxlKGRhcywiRGlmZkFjY19QVmFsMC4wMV9VcC50eHQiLHNlcCA9ICJcdCIscXVvdGUgPSBGKQp9CmBgYAoKIyMjIEFubm90YXRpb24gb2YgZG93bnJlZ3VsYXRlZCBwZWFrcyBvbmx5CgpgYGB7cn0KIyMgRG93bnJlZ3VsYXRlZApkYXMgPSBzdWJzZXQodHQkdGFibGUsICBQVmFsdWUgIDwgMC4wMSAmIGxvZ0ZDID4wKQpyb3duYW1lcyhkYXMpID1wYXN0ZTAoImNociIscm93bmFtZXMoZGFzKSkKZ3IgPSBHUmFuZ2VzKHJvd25hbWVzKGRhcykpCmdyX2RmID0gYXMuZGF0YS5mcmFtZShncikKcGVha0Fubm8gPC0gYW5ub3RhdGVQZWFrKGdyLCB0c3NSZWdpb249YygtMzAwMCwgMzAwMCksVHhEYj1UeERiLkhzYXBpZW5zLlVDU0MuaGczOC5rbm93bkdlbmUsIGFubm9EYj0ib3JnLkhzLmVnLmRiIikKcGxvdEFubm9QaWUocGVha0Fubm8pCmdlbmUgPC0gc2VxMmdlbmUoZ3IsIHRzc1JlZ2lvbiA9IGMoLTEwMDAsIDEwMDApLCBmbGFua0Rpc3RhbmNlID0gMzAwMCwgVHhEYj1UeERiLkhzYXBpZW5zLlVDU0MuaGczOC5rbm93bkdlbmUpCnBhdGh3YXkyID0gZW5yaWNoR08oZ2VuZSxPcmdEYiA9IG9yZy5Icy5lZy5kYixvbnQ9IkJQIixyZWFkYWJsZSA9IFQpCmhlYWQocGF0aHdheTIsIDUpCmRvdHBsb3QocGF0aHdheTIpCndyaXRlLnRhYmxlKGFzLmRhdGEuZnJhbWUocGF0aHdheTIpLCJFbnJpY2hlZE9udG9sb2d5X1B2YWwwLjAxX0Rvd24udHh0IixzZXAgPSAiXHQiLHF1b3RlID0gRikKI2NoZWNraW5nIHBlYWtBbm5vIGFuZCBkYXMgaGF2ZSBzYW1lIG9yZGVyCnRtcCA9IHBhc3RlKGFzLmRhdGEuZnJhbWUocGVha0Fubm8pJHNlcW5hbWVzLGFzLmRhdGEuZnJhbWUocGVha0Fubm8pJHN0YXJ0LHNlcCA9IjoiKQp0bXAgPSBwYXN0ZSh0bXAsYXMuZGF0YS5mcmFtZShwZWFrQW5ubykkZW5kLCBzZXA9Ii0iKQppZiggc3VtKHRtcD09IHJvd25hbWVzKGRhcykpPT0gbnJvdyhkYXMpKXsKICBkYXMgPSBjYmluZChkYXMsYXMuZGF0YS5mcmFtZShwZWFrQW5ubykpCiAgd3JpdGUudGFibGUoZGFzLCJEaWZmQWNjX1BWYWwwLjAxX0Rvd24udHh0IixzZXAgPSAiXHQiLHF1b3RlID0gRikKfQpgYGAKCgojIyMgVGhlIGZpbGVzIHdyb3RlIGluIHRoZSB0ZXh0IGZvcm1hdCBhcmUgYXZhaWxhYmxlIGZyb20gaGVyZQoKMS4gW0Fubm90YXRpb24gb2YgYWxsIHBlYWtzXShodHRwczovL2RyaXZlLmdvb2dsZS5jb20vZmlsZS9kLzFCUF8xZkd5M3R0VWVQMEFZN1QzX3lPWmFRX1JDZnNTTy92aWV3P3VzcD1zaGFyaW5nKQoKMi4gW0VucmljaGVkIEdPcyBvZiBhbGwgcGVha3NdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9maWxlL2QvMXRLSFlFRWEtcmUxSGJSRVhDNDhBYldkcHJwcGh0LWg3L3ZpZXc/dXNwPXNoYXJpbmcpCgozLiBbQW5ub3RhdGlvbiBvZiB1cHJlZ3VsYXRlZCBwZWFrc10oaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xeVRFMm9mWlpDQ3I4UTlaTWZDU1lVTl9PaGlfdjRjWW8vdmlldz91c3A9c2hhcmluZykKCjQuIFtFbnJpY2hlZCBHT3Mgb2YgdXByZWd1bGF0ZWQgcGVha3NdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9maWxlL2QvMWNMRlNINy1CaXdfd1ZHRlpmTXN4TUZXaFRyWnE3Z2dwL3ZpZXc/dXNwPXNoYXJpbmcpCgo1LiBbQW5ub3RhdGlvbiBvZiBkb3dyZWd1bGF0ZWQgcGVha3NdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9maWxlL2QvMWhsQnM5azBTQnZNOUJoN0U2ZmFxdGo1d2NXSjBPd1FKL3ZpZXc/dXNwPXNoYXJpbmcpCgo2LiBbRW5yaWNoZWQgR09zIG9mIGRvd25yZWd1bGF0ZWQgcGVha3NdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9maWxlL2QvMTZTSVMwQjZJb21JeXAtbU96cVczWmprNWNBY2J3N3FyL3ZpZXc/dXNwPXNoYXJpbmcpCg==