08_Init test


suppressMessages(library(GenomicRanges))
suppressMessages(library(tidyverse))
suppressMessages(library(rtracklayer))
`%+%`<-paste0
seqinfSY <- readRDS("Data/seqinfSY.rds")
rDNA_SY <- GRanges("CP029160.1",IRanges(3879940,3934000),strand="*",seqinfo=seqinfSY)
maskedTy_SY <- readRDS("Data/maskedTy_SY.rds")
masked_ura3d0 <- GRanges("CP029160.1",IRanges(1051200,1051500),strand="*",seqinfo=seqinfSY,type="ura3d0")
masked_SY <- c(maskedTy_SY,masked_ura3d0) 
source("Helper_function.r")

Importing Ori

ars2keep <- import("Data/ars2keep_lim10k_cl1500_2_dtac1500.bed") %>% sort
ars2keep$score <- NULL

Importing Initiation events

Init overlapping with Ty_chrIII, Ty_chrXVI, ura3d0 and rDNA are removed.

initerSY <- readRDS("Data/initer_SYSY.rds")
initerBY <- readRDS("Data/initer_BYBYSY.rds")

initSY.gr <- with(initerSY %>% filter(type=="Init"),GRanges(seqnames=chrom,ranges=IRanges(start=pmin(x0,x1),end=pmax(x0,x1)),strand="*",seqinfo=seqinfSY,exp=exp))
initSY.gr <- initSY.gr[!overlapsAny(initSY.gr,c(masked_SY,rDNA_SY))]

initBY.gr <- with(initerBY %>% filter(type=="Init"),GRanges(seqnames=chromSY,ranges=IRanges(start=pmin(x0nSY,x1nSY),end=pmax(x0nSY,x1nSY)),strand="*",seqinfo=seqinfSY,exp=exp))
initBY.gr <- initBY.gr[!overlapsAny(initBY.gr,c(masked_SY,rDNA_SY))]

Computing coverages

### normalise by the sum with respect to the genome length

ICgn_SY <- coverage(initSY.gr)/sum(coverage(initSY.gr))*seqlengths(seqinfSY)
ICgn_BY <- coverage(initBY.gr)/sum(coverage(initBY.gr))*seqlengths(seqinfSY)
export(ICgn_SY,con="BigWig/ICgn_SY.bw")
export(ICgn_BY,con="BigWig/ICgn_BY.bw")

initSY1.gr <- initSY.gr[initSY.gr$exp=="SY_rep1"]
initSY2.gr <- initSY.gr[initSY.gr$exp=="SY_rep2"]
initSY3.gr <- initSY.gr[initSY.gr$exp=="SY_rep3"]
initBY1.gr <- initBY.gr[initBY.gr$exp=="BY_rep1"]
initBY2.gr <- initBY.gr[initBY.gr$exp=="BY_rep2"]
initBY3.gr <- initBY.gr[initBY.gr$exp=="BY_rep3"]

ICgn_SY1 <- coverage(initSY1.gr)/sum(coverage(initSY1.gr))*seqlengths(seqinfSY)
ICgn_BY1 <- coverage(initBY1.gr)/sum(coverage(initBY1.gr))*seqlengths(seqinfSY)
export(ICgn_SY1,con="BigWig/ICgn_SY1.bw")
export(ICgn_BY1,con="BigWig/ICgn_BY1.bw")
ICgn_SY2 <- coverage(initSY2.gr)/sum(coverage(initSY2.gr))*seqlengths(seqinfSY)
ICgn_BY2 <- coverage(initBY2.gr)/sum(coverage(initBY2.gr))*seqlengths(seqinfSY)
export(ICgn_SY2,con="BigWig/ICgn_SY2.bw")
export(ICgn_BY2,con="BigWig/ICgn_BY2.bw")
ICgn_SY3 <- coverage(initSY3.gr)/sum(coverage(initSY3.gr))*seqlengths(seqinfSY)
ICgn_BY3 <- coverage(initBY3.gr)/sum(coverage(initBY3.gr))*seqlengths(seqinfSY)
export(ICgn_SY3,con="BigWig/ICgn_SY3.bw")
export(ICgn_BY3,con="BigWig/ICgn_BY3.bw")

To use the number of init overlapping Ori, we choose to keep only the initiation events overlapping only one of the active ori we selected

initSY1.gr1 <- initSY1.gr[countOverlaps(initSY1.gr,ars2keep)==1]
initSY2.gr1 <- initSY2.gr[countOverlaps(initSY2.gr,ars2keep)==1]
initSY3.gr1 <- initSY3.gr[countOverlaps(initSY3.gr,ars2keep)==1]

initBY1.gr1 <- initBY1.gr[countOverlaps(initBY1.gr,ars2keep)==1]
initBY2.gr1 <- initBY2.gr[countOverlaps(initBY2.gr,ars2keep)==1]
initBY3.gr1 <- initBY3.gr[countOverlaps(initBY3.gr,ars2keep)==1]

### generate the coverages
ICgn1_SY1 <- coverage(initSY1.gr1)/sum(coverage(initSY1.gr1))*seqlengths(seqinfSY)
ICgn1_BY1 <- coverage(initBY1.gr1)/sum(coverage(initBY1.gr1))*seqlengths(seqinfSY)
export(ICgn1_SY1,con="BigWig/ICgn1_SY1.bw")
export(ICgn1_BY1,con="BigWig/ICgn1_BY1.bw")
ICgn1_SY2 <- coverage(initSY2.gr1)/sum(coverage(initSY2.gr1))*seqlengths(seqinfSY)
ICgn1_BY2 <- coverage(initBY2.gr1)/sum(coverage(initBY2.gr1))*seqlengths(seqinfSY)
export(ICgn1_SY2,con="BigWig/ICgn1_SY2.bw")
export(ICgn1_BY2,con="BigWig/ICgn1_BY2.bw")
ICgn1_SY3 <- coverage(initSY3.gr1)/sum(coverage(initSY3.gr1))*seqlengths(seqinfSY)
ICgn1_BY3 <- coverage(initBY3.gr1)/sum(coverage(initBY3.gr1))*seqlengths(seqinfSY)
export(ICgn1_SY3,con="BigWig/ICgn1_SY3.bw")
export(ICgn1_BY3,con="BigWig/ICgn1_BY3.bw")

### use these init cov at Ori to do MAnorm2
ars2 <- ars2keep
ars2$initBY1 <- sapply(seq_along(ars2),function(x) countOverlaps(ars2[x],initBY1.gr1))
ars2$initBY2 <- sapply(seq_along(ars2),function(x) countOverlaps(ars2[x],initBY2.gr1))
ars2$initBY3 <- sapply(seq_along(ars2),function(x) countOverlaps(ars2[x],initBY3.gr1))
ars2$initSY1 <- sapply(seq_along(ars2),function(x) countOverlaps(ars2[x],initSY1.gr1))
ars2$initSY2 <- sapply(seq_along(ars2),function(x) countOverlaps(ars2[x],initSY2.gr1))
ars2$initSY3 <- sapply(seq_along(ars2),function(x) countOverlaps(ars2[x],initSY3.gr1))

We then decided to use these counts of initiations at Ori in the MAnorm2 framework

require(MAnorm2)
#packageVersion("MAnorm2")
# [1] ‘1.2.2’
count2test <- mcols(ars2)
x <- as.matrix(count2test[,2:7])
eff.mat <- x
occ.mat <- eff.mat>0
test.mat <- cbind(eff.mat,occ.mat)
norm <- normalize(test.mat,count=c(1:3),occupancy=c(7:9))
norm <- normalize(norm,count=c(4:6),occupancy=c(10:12))

conds <- list(  BY= bioCond(norm[c(1:3)],norm[c(7:9)],name="BY"),
                SY=bioCond(norm[c(4:6)],norm[c(10:12)],name="SY"))
conds <- normBioCond(conds)
conds <- fitMeanVarCurve(conds, method = "parametric", occupy.only = TRUE,init.coef = c(0.1, 10))
During the parametric fit procedure:
After iteration 1: coef = (0.012839, 1.2317); 0 (0.00%) outlier(s) detected
Converged.
res <- diffTest(conds[[1]], conds[[2]])
ars.res <- bind_cols(as_tibble(mcols(ars2)),res)
min(ars.res$padj)
[1] 2.83347e-08
# 2.83347e-08
ars.res %>% filter(padj<=0.01) %>% nrow
[1] 20
# 20 
ars2export <- ars2[ars2$name %in% (ars.res %>% filter(padj<=1e-2) %>% pull(name))]
export(ars2export,con="Data/ARSinitMAnorm2_1e-2.bed")
saveRDS(ars.res,file="Data/ARSinitMAnorm2.rds")

Please note that the test is based on the raw counting of the number of init without . We choose to delegate any normalisation procedure to MAnorm2. As a results, the ICgn might sometimes not reflect what the MAnorm2 describe as significant.

We also generated Termination coverage the same way.

terSY.gr <- with(initerSY %>% filter(type=="Ter"),GRanges(seqnames=chrom,ranges=IRanges(start=pmin(x0,x1),end=pmax(x0,x1)),strand="*",seqinfo=seqinfSY,exp=exp))
terSY.gr <- terSY.gr[!overlapsAny(terSY.gr,c(maskedTy_SY,rDNA_SY))]

terBY.gr <- with(initerBY %>% filter(type=="Ter"),GRanges(seqnames=chromSY,ranges=IRanges(start=pmin(x0nSY,x1nSY),end=pmax(x0nSY,x1nSY)),strand="*",seqinfo=seqinfSY,exp=exp))
terBY.gr <- terBY.gr[!overlapsAny(terBY.gr,c(maskedTy_SY,rDNA_SY))]

TCgn_SY <- coverage(terSY.gr)/sum(coverage(terSY.gr))*seqlengths(seqinfSY)
TCgn_BY <- coverage(terBY.gr)/sum(coverage(terBY.gr))*seqlengths(seqinfSY)
export(TCgn_SY,con="BigWig/TCgn_SY.bw")
export(TCgn_BY,con="BigWig/TCgn_BY.bw")
### looks OK
### idem but separating the replicate
terSY1.gr <- terSY.gr[terSY.gr$exp=="SY_rep1"]
terSY2.gr <- terSY.gr[terSY.gr$exp=="SY_rep2"]
terSY3.gr <- terSY.gr[terSY.gr$exp=="SY_rep3"]
terBY1.gr <- terBY.gr[terBY.gr$exp=="BY_rep1"]
terBY2.gr <- terBY.gr[terBY.gr$exp=="BY_rep2"]
terBY3.gr <- terBY.gr[terBY.gr$exp=="BY_rep3"]

TCgn_SY1 <- coverage(terSY1.gr)/sum(coverage(terSY1.gr))*seqlengths(seqinfSY)
TCgn_BY1 <- coverage(terBY1.gr)/sum(coverage(terBY1.gr))*seqlengths(seqinfSY)
export(TCgn_SY1,con="BigWig/TCgn_SY1.bw")
export(TCgn_BY1,con="BigWig/TCgn_BY1.bw")
TCgn_SY2 <- coverage(terSY2.gr)/sum(coverage(terSY2.gr))*seqlengths(seqinfSY)
TCgn_BY2 <- coverage(terBY2.gr)/sum(coverage(terBY2.gr))*seqlengths(seqinfSY)
export(TCgn_SY2,con="BigWig/TCgn_SY2.bw")
export(TCgn_BY2,con="BigWig/TCgn_BY2.bw")
TCgn_SY3 <- coverage(terSY3.gr)/sum(coverage(terSY3.gr))*seqlengths(seqinfSY)
TCgn_BY3 <- coverage(terBY3.gr)/sum(coverage(terBY3.gr))*seqlengths(seqinfSY)
export(TCgn_SY3,con="BigWig/TCgn_SY3.bw")
export(TCgn_BY3,con="BigWig/TCgn_BY3.bw")
LS0tCnRpdGxlOiAiQllTWSBwcm9qZWN0IE5vdGVib29rIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tICAKIyAwOF9Jbml0IHRlc3QgIAoKKioqICAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShHZW5vbWljUmFuZ2VzKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHRpZHl2ZXJzZSkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShydHJhY2tsYXllcikpCmAlKyVgPC1wYXN0ZTAKc2VxaW5mU1kgPC0gcmVhZFJEUygiRGF0YS9zZXFpbmZTWS5yZHMiKQpyRE5BX1NZIDwtIEdSYW5nZXMoIkNQMDI5MTYwLjEiLElSYW5nZXMoMzg3OTk0MCwzOTM0MDAwKSxzdHJhbmQ9IioiLHNlcWluZm89c2VxaW5mU1kpCm1hc2tlZFR5X1NZIDwtIHJlYWRSRFMoIkRhdGEvbWFza2VkVHlfU1kucmRzIikKbWFza2VkX3VyYTNkMCA8LSBHUmFuZ2VzKCJDUDAyOTE2MC4xIixJUmFuZ2VzKDEwNTEyMDAsMTA1MTUwMCksc3RyYW5kPSIqIixzZXFpbmZvPXNlcWluZlNZLHR5cGU9InVyYTNkMCIpCm1hc2tlZF9TWSA8LSBjKG1hc2tlZFR5X1NZLG1hc2tlZF91cmEzZDApIApzb3VyY2UoIkhlbHBlcl9mdW5jdGlvbi5yIikKYGBgCgojIyMgSW1wb3J0aW5nIE9yaQoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYXJzMmtlZXAgPC0gaW1wb3J0KCJEYXRhL2FyczJrZWVwX2xpbTEwa19jbDE1MDBfMl9kdGFjMTUwMC5iZWQiKSAlPiUgc29ydAphcnMya2VlcCRzY29yZSA8LSBOVUxMCmBgYAoKIyMjIEltcG9ydGluZyBJbml0aWF0aW9uIGV2ZW50cwoKSW5pdCBvdmVybGFwcGluZyB3aXRoIFR5X2NocklJSSwgVHlfY2hyWFZJLCB1cmEzZDAgYW5kIHJETkEgYXJlIHJlbW92ZWQuICAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmluaXRlclNZIDwtIHJlYWRSRFMoIkRhdGEvaW5pdGVyX1NZU1kucmRzIikKaW5pdGVyQlkgPC0gcmVhZFJEUygiRGF0YS9pbml0ZXJfQllCWVNZLnJkcyIpCgppbml0U1kuZ3IgPC0gd2l0aChpbml0ZXJTWSAlPiUgZmlsdGVyKHR5cGU9PSJJbml0IiksR1JhbmdlcyhzZXFuYW1lcz1jaHJvbSxyYW5nZXM9SVJhbmdlcyhzdGFydD1wbWluKHgwLHgxKSxlbmQ9cG1heCh4MCx4MSkpLHN0cmFuZD0iKiIsc2VxaW5mbz1zZXFpbmZTWSxleHA9ZXhwKSkKaW5pdFNZLmdyIDwtIGluaXRTWS5nclshb3ZlcmxhcHNBbnkoaW5pdFNZLmdyLGMobWFza2VkX1NZLHJETkFfU1kpKV0KCmluaXRCWS5nciA8LSB3aXRoKGluaXRlckJZICU+JSBmaWx0ZXIodHlwZT09IkluaXQiKSxHUmFuZ2VzKHNlcW5hbWVzPWNocm9tU1kscmFuZ2VzPUlSYW5nZXMoc3RhcnQ9cG1pbih4MG5TWSx4MW5TWSksZW5kPXBtYXgoeDBuU1kseDFuU1kpKSxzdHJhbmQ9IioiLHNlcWluZm89c2VxaW5mU1ksZXhwPWV4cCkpCmluaXRCWS5nciA8LSBpbml0QlkuZ3JbIW92ZXJsYXBzQW55KGluaXRCWS5ncixjKG1hc2tlZF9TWSxyRE5BX1NZKSldCmBgYAoKQ29tcHV0aW5nIGNvdmVyYWdlcwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyMgbm9ybWFsaXNlIGJ5IHRoZSBzdW0gd2l0aCByZXNwZWN0IHRvIHRoZSBnZW5vbWUgbGVuZ3RoCgpJQ2duX1NZIDwtIGNvdmVyYWdlKGluaXRTWS5ncikvc3VtKGNvdmVyYWdlKGluaXRTWS5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCklDZ25fQlkgPC0gY292ZXJhZ2UoaW5pdEJZLmdyKS9zdW0oY292ZXJhZ2UoaW5pdEJZLmdyKSkqc2VxbGVuZ3RocyhzZXFpbmZTWSkKZXhwb3J0KElDZ25fU1ksY29uPSJCaWdXaWcvSUNnbl9TWS5idyIpCmV4cG9ydChJQ2duX0JZLGNvbj0iQmlnV2lnL0lDZ25fQlkuYnciKQoKaW5pdFNZMS5nciA8LSBpbml0U1kuZ3JbaW5pdFNZLmdyJGV4cD09IlNZX3JlcDEiXQppbml0U1kyLmdyIDwtIGluaXRTWS5ncltpbml0U1kuZ3IkZXhwPT0iU1lfcmVwMiJdCmluaXRTWTMuZ3IgPC0gaW5pdFNZLmdyW2luaXRTWS5nciRleHA9PSJTWV9yZXAzIl0KaW5pdEJZMS5nciA8LSBpbml0QlkuZ3JbaW5pdEJZLmdyJGV4cD09IkJZX3JlcDEiXQppbml0QlkyLmdyIDwtIGluaXRCWS5ncltpbml0QlkuZ3IkZXhwPT0iQllfcmVwMiJdCmluaXRCWTMuZ3IgPC0gaW5pdEJZLmdyW2luaXRCWS5nciRleHA9PSJCWV9yZXAzIl0KCklDZ25fU1kxIDwtIGNvdmVyYWdlKGluaXRTWTEuZ3IpL3N1bShjb3ZlcmFnZShpbml0U1kxLmdyKSkqc2VxbGVuZ3RocyhzZXFpbmZTWSkKSUNnbl9CWTEgPC0gY292ZXJhZ2UoaW5pdEJZMS5ncikvc3VtKGNvdmVyYWdlKGluaXRCWTEuZ3IpKSpzZXFsZW5ndGhzKHNlcWluZlNZKQpleHBvcnQoSUNnbl9TWTEsY29uPSJCaWdXaWcvSUNnbl9TWTEuYnciKQpleHBvcnQoSUNnbl9CWTEsY29uPSJCaWdXaWcvSUNnbl9CWTEuYnciKQpJQ2duX1NZMiA8LSBjb3ZlcmFnZShpbml0U1kyLmdyKS9zdW0oY292ZXJhZ2UoaW5pdFNZMi5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCklDZ25fQlkyIDwtIGNvdmVyYWdlKGluaXRCWTIuZ3IpL3N1bShjb3ZlcmFnZShpbml0QlkyLmdyKSkqc2VxbGVuZ3RocyhzZXFpbmZTWSkKZXhwb3J0KElDZ25fU1kyLGNvbj0iQmlnV2lnL0lDZ25fU1kyLmJ3IikKZXhwb3J0KElDZ25fQlkyLGNvbj0iQmlnV2lnL0lDZ25fQlkyLmJ3IikKSUNnbl9TWTMgPC0gY292ZXJhZ2UoaW5pdFNZMy5ncikvc3VtKGNvdmVyYWdlKGluaXRTWTMuZ3IpKSpzZXFsZW5ndGhzKHNlcWluZlNZKQpJQ2duX0JZMyA8LSBjb3ZlcmFnZShpbml0QlkzLmdyKS9zdW0oY292ZXJhZ2UoaW5pdEJZMy5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCmV4cG9ydChJQ2duX1NZMyxjb249IkJpZ1dpZy9JQ2duX1NZMy5idyIpCmV4cG9ydChJQ2duX0JZMyxjb249IkJpZ1dpZy9JQ2duX0JZMy5idyIpCmBgYAoKVG8gdXNlIHRoZSBudW1iZXIgb2YgaW5pdCBvdmVybGFwcGluZyBPcmksIHdlIGNob29zZSB0byBrZWVwIG9ubHkgdGhlIGluaXRpYXRpb24gZXZlbnRzIG92ZXJsYXBwaW5nIG9ubHkgb25lIG9mIHRoZSBhY3RpdmUgb3JpIHdlIHNlbGVjdGVkCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQppbml0U1kxLmdyMSA8LSBpbml0U1kxLmdyW2NvdW50T3ZlcmxhcHMoaW5pdFNZMS5ncixhcnMya2VlcCk9PTFdCmluaXRTWTIuZ3IxIDwtIGluaXRTWTIuZ3JbY291bnRPdmVybGFwcyhpbml0U1kyLmdyLGFyczJrZWVwKT09MV0KaW5pdFNZMy5ncjEgPC0gaW5pdFNZMy5ncltjb3VudE92ZXJsYXBzKGluaXRTWTMuZ3IsYXJzMmtlZXApPT0xXQoKaW5pdEJZMS5ncjEgPC0gaW5pdEJZMS5ncltjb3VudE92ZXJsYXBzKGluaXRCWTEuZ3IsYXJzMmtlZXApPT0xXQppbml0QlkyLmdyMSA8LSBpbml0QlkyLmdyW2NvdW50T3ZlcmxhcHMoaW5pdEJZMi5ncixhcnMya2VlcCk9PTFdCmluaXRCWTMuZ3IxIDwtIGluaXRCWTMuZ3JbY291bnRPdmVybGFwcyhpbml0QlkzLmdyLGFyczJrZWVwKT09MV0KCiMjIyBnZW5lcmF0ZSB0aGUgY292ZXJhZ2VzCklDZ24xX1NZMSA8LSBjb3ZlcmFnZShpbml0U1kxLmdyMSkvc3VtKGNvdmVyYWdlKGluaXRTWTEuZ3IxKSkqc2VxbGVuZ3RocyhzZXFpbmZTWSkKSUNnbjFfQlkxIDwtIGNvdmVyYWdlKGluaXRCWTEuZ3IxKS9zdW0oY292ZXJhZ2UoaW5pdEJZMS5ncjEpKSpzZXFsZW5ndGhzKHNlcWluZlNZKQpleHBvcnQoSUNnbjFfU1kxLGNvbj0iQmlnV2lnL0lDZ24xX1NZMS5idyIpCmV4cG9ydChJQ2duMV9CWTEsY29uPSJCaWdXaWcvSUNnbjFfQlkxLmJ3IikKSUNnbjFfU1kyIDwtIGNvdmVyYWdlKGluaXRTWTIuZ3IxKS9zdW0oY292ZXJhZ2UoaW5pdFNZMi5ncjEpKSpzZXFsZW5ndGhzKHNlcWluZlNZKQpJQ2duMV9CWTIgPC0gY292ZXJhZ2UoaW5pdEJZMi5ncjEpL3N1bShjb3ZlcmFnZShpbml0QlkyLmdyMSkpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCmV4cG9ydChJQ2duMV9TWTIsY29uPSJCaWdXaWcvSUNnbjFfU1kyLmJ3IikKZXhwb3J0KElDZ24xX0JZMixjb249IkJpZ1dpZy9JQ2duMV9CWTIuYnciKQpJQ2duMV9TWTMgPC0gY292ZXJhZ2UoaW5pdFNZMy5ncjEpL3N1bShjb3ZlcmFnZShpbml0U1kzLmdyMSkpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCklDZ24xX0JZMyA8LSBjb3ZlcmFnZShpbml0QlkzLmdyMSkvc3VtKGNvdmVyYWdlKGluaXRCWTMuZ3IxKSkqc2VxbGVuZ3RocyhzZXFpbmZTWSkKZXhwb3J0KElDZ24xX1NZMyxjb249IkJpZ1dpZy9JQ2duMV9TWTMuYnciKQpleHBvcnQoSUNnbjFfQlkzLGNvbj0iQmlnV2lnL0lDZ24xX0JZMy5idyIpCgojIyMgdXNlIHRoZXNlIGluaXQgY292IGF0IE9yaSB0byBkbyBNQW5vcm0yCmFyczIgPC0gYXJzMmtlZXAKYXJzMiRpbml0QlkxIDwtIHNhcHBseShzZXFfYWxvbmcoYXJzMiksZnVuY3Rpb24oeCkgY291bnRPdmVybGFwcyhhcnMyW3hdLGluaXRCWTEuZ3IxKSkKYXJzMiRpbml0QlkyIDwtIHNhcHBseShzZXFfYWxvbmcoYXJzMiksZnVuY3Rpb24oeCkgY291bnRPdmVybGFwcyhhcnMyW3hdLGluaXRCWTIuZ3IxKSkKYXJzMiRpbml0QlkzIDwtIHNhcHBseShzZXFfYWxvbmcoYXJzMiksZnVuY3Rpb24oeCkgY291bnRPdmVybGFwcyhhcnMyW3hdLGluaXRCWTMuZ3IxKSkKYXJzMiRpbml0U1kxIDwtIHNhcHBseShzZXFfYWxvbmcoYXJzMiksZnVuY3Rpb24oeCkgY291bnRPdmVybGFwcyhhcnMyW3hdLGluaXRTWTEuZ3IxKSkKYXJzMiRpbml0U1kyIDwtIHNhcHBseShzZXFfYWxvbmcoYXJzMiksZnVuY3Rpb24oeCkgY291bnRPdmVybGFwcyhhcnMyW3hdLGluaXRTWTIuZ3IxKSkKYXJzMiRpbml0U1kzIDwtIHNhcHBseShzZXFfYWxvbmcoYXJzMiksZnVuY3Rpb24oeCkgY291bnRPdmVybGFwcyhhcnMyW3hdLGluaXRTWTMuZ3IxKSkKYGBgCgpXZSB0aGVuIGRlY2lkZWQgdG8gdXNlIHRoZXNlIGNvdW50cyBvZiBpbml0aWF0aW9ucyBhdCBPcmkgaW4gdGhlIE1Bbm9ybTIgZnJhbWV3b3JrCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZXF1aXJlKE1Bbm9ybTIpCiNwYWNrYWdlVmVyc2lvbigiTUFub3JtMiIpCiMgWzFdIOKAmDEuMi4y4oCZCmNvdW50MnRlc3QgPC0gbWNvbHMoYXJzMikKeCA8LSBhcy5tYXRyaXgoY291bnQydGVzdFssMjo3XSkKZWZmLm1hdCA8LSB4Cm9jYy5tYXQgPC0gZWZmLm1hdD4wCnRlc3QubWF0IDwtIGNiaW5kKGVmZi5tYXQsb2NjLm1hdCkKbm9ybSA8LSBub3JtYWxpemUodGVzdC5tYXQsY291bnQ9YygxOjMpLG9jY3VwYW5jeT1jKDc6OSkpCm5vcm0gPC0gbm9ybWFsaXplKG5vcm0sY291bnQ9Yyg0OjYpLG9jY3VwYW5jeT1jKDEwOjEyKSkKCmNvbmRzIDwtIGxpc3QoCUJZPSBiaW9Db25kKG5vcm1bYygxOjMpXSxub3JtW2MoNzo5KV0sbmFtZT0iQlkiKSwKCQkJCVNZPWJpb0NvbmQobm9ybVtjKDQ6NildLG5vcm1bYygxMDoxMildLG5hbWU9IlNZIikpCmNvbmRzIDwtIG5vcm1CaW9Db25kKGNvbmRzKQpjb25kcyA8LSBmaXRNZWFuVmFyQ3VydmUoY29uZHMsIG1ldGhvZCA9ICJwYXJhbWV0cmljIiwgb2NjdXB5Lm9ubHkgPSBUUlVFLGluaXQuY29lZiA9IGMoMC4xLCAxMCkpCnJlcyA8LSBkaWZmVGVzdChjb25kc1tbMV1dLCBjb25kc1tbMl1dKQphcnMucmVzIDwtIGJpbmRfY29scyhhc190aWJibGUobWNvbHMoYXJzMikpLHJlcykKbWluKGFycy5yZXMkcGFkaikKIyAyLjgzMzQ3ZS0wOAphcnMucmVzICU+JSBmaWx0ZXIocGFkajw9MC4wMSkgJT4lIG5yb3cKIyAyMCAKYXJzMmV4cG9ydCA8LSBhcnMyW2FyczIkbmFtZSAlaW4lIChhcnMucmVzICU+JSBmaWx0ZXIocGFkajw9MWUtMikgJT4lIHB1bGwobmFtZSkpXQpleHBvcnQoYXJzMmV4cG9ydCxjb249IkRhdGEvQVJTaW5pdE1Bbm9ybTJfMWUtMi5iZWQiKQpzYXZlUkRTKGFycy5yZXMsZmlsZT0iRGF0YS9BUlNpbml0TUFub3JtMi5yZHMiKQpgYGAKUGxlYXNlIG5vdGUgdGhhdCB0aGUgdGVzdCBpcyBiYXNlZCBvbiB0aGUgcmF3IGNvdW50aW5nIG9mIHRoZSBudW1iZXIgb2YgaW5pdCB3aXRob3V0IC4gV2UgY2hvb3NlIHRvIGRlbGVnYXRlIGFueSBub3JtYWxpc2F0aW9uIHByb2NlZHVyZSB0byBNQW5vcm0yLiBBcyBhIHJlc3VsdHMsIHRoZSBJQ2duIG1pZ2h0IHNvbWV0aW1lcyBub3QgcmVmbGVjdCB3aGF0IHRoZSBNQW5vcm0yIGRlc2NyaWJlIGFzIHNpZ25pZmljYW50LiAgCgpXZSBhbHNvIGdlbmVyYXRlZCBUZXJtaW5hdGlvbiBjb3ZlcmFnZSB0aGUgc2FtZSB3YXkuICAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnRlclNZLmdyIDwtIHdpdGgoaW5pdGVyU1kgJT4lIGZpbHRlcih0eXBlPT0iVGVyIiksR1JhbmdlcyhzZXFuYW1lcz1jaHJvbSxyYW5nZXM9SVJhbmdlcyhzdGFydD1wbWluKHgwLHgxKSxlbmQ9cG1heCh4MCx4MSkpLHN0cmFuZD0iKiIsc2VxaW5mbz1zZXFpbmZTWSxleHA9ZXhwKSkKdGVyU1kuZ3IgPC0gdGVyU1kuZ3JbIW92ZXJsYXBzQW55KHRlclNZLmdyLGMobWFza2VkVHlfU1ksckROQV9TWSkpXQoKdGVyQlkuZ3IgPC0gd2l0aChpbml0ZXJCWSAlPiUgZmlsdGVyKHR5cGU9PSJUZXIiKSxHUmFuZ2VzKHNlcW5hbWVzPWNocm9tU1kscmFuZ2VzPUlSYW5nZXMoc3RhcnQ9cG1pbih4MG5TWSx4MW5TWSksZW5kPXBtYXgoeDBuU1kseDFuU1kpKSxzdHJhbmQ9IioiLHNlcWluZm89c2VxaW5mU1ksZXhwPWV4cCkpCnRlckJZLmdyIDwtIHRlckJZLmdyWyFvdmVybGFwc0FueSh0ZXJCWS5ncixjKG1hc2tlZFR5X1NZLHJETkFfU1kpKV0KClRDZ25fU1kgPC0gY292ZXJhZ2UodGVyU1kuZ3IpL3N1bShjb3ZlcmFnZSh0ZXJTWS5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpClRDZ25fQlkgPC0gY292ZXJhZ2UodGVyQlkuZ3IpL3N1bShjb3ZlcmFnZSh0ZXJCWS5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCmV4cG9ydChUQ2duX1NZLGNvbj0iQmlnV2lnL1RDZ25fU1kuYnciKQpleHBvcnQoVENnbl9CWSxjb249IkJpZ1dpZy9UQ2duX0JZLmJ3IikKIyMjIGxvb2tzIE9LCiMjIyBpZGVtIGJ1dCBzZXBhcmF0aW5nIHRoZSByZXBsaWNhdGUKdGVyU1kxLmdyIDwtIHRlclNZLmdyW3RlclNZLmdyJGV4cD09IlNZX3JlcDEiXQp0ZXJTWTIuZ3IgPC0gdGVyU1kuZ3JbdGVyU1kuZ3IkZXhwPT0iU1lfcmVwMiJdCnRlclNZMy5nciA8LSB0ZXJTWS5nclt0ZXJTWS5nciRleHA9PSJTWV9yZXAzIl0KdGVyQlkxLmdyIDwtIHRlckJZLmdyW3RlckJZLmdyJGV4cD09IkJZX3JlcDEiXQp0ZXJCWTIuZ3IgPC0gdGVyQlkuZ3JbdGVyQlkuZ3IkZXhwPT0iQllfcmVwMiJdCnRlckJZMy5nciA8LSB0ZXJCWS5nclt0ZXJCWS5nciRleHA9PSJCWV9yZXAzIl0KClRDZ25fU1kxIDwtIGNvdmVyYWdlKHRlclNZMS5ncikvc3VtKGNvdmVyYWdlKHRlclNZMS5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpClRDZ25fQlkxIDwtIGNvdmVyYWdlKHRlckJZMS5ncikvc3VtKGNvdmVyYWdlKHRlckJZMS5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCmV4cG9ydChUQ2duX1NZMSxjb249IkJpZ1dpZy9UQ2duX1NZMS5idyIpCmV4cG9ydChUQ2duX0JZMSxjb249IkJpZ1dpZy9UQ2duX0JZMS5idyIpClRDZ25fU1kyIDwtIGNvdmVyYWdlKHRlclNZMi5ncikvc3VtKGNvdmVyYWdlKHRlclNZMi5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpClRDZ25fQlkyIDwtIGNvdmVyYWdlKHRlckJZMi5ncikvc3VtKGNvdmVyYWdlKHRlckJZMi5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCmV4cG9ydChUQ2duX1NZMixjb249IkJpZ1dpZy9UQ2duX1NZMi5idyIpCmV4cG9ydChUQ2duX0JZMixjb249IkJpZ1dpZy9UQ2duX0JZMi5idyIpClRDZ25fU1kzIDwtIGNvdmVyYWdlKHRlclNZMy5ncikvc3VtKGNvdmVyYWdlKHRlclNZMy5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpClRDZ25fQlkzIDwtIGNvdmVyYWdlKHRlckJZMy5ncikvc3VtKGNvdmVyYWdlKHRlckJZMy5ncikpKnNlcWxlbmd0aHMoc2VxaW5mU1kpCmV4cG9ydChUQ2duX1NZMyxjb249IkJpZ1dpZy9UQ2duX1NZMy5idyIpCmV4cG9ydChUQ2duX0JZMyxjb249IkJpZ1dpZy9UQ2duX0JZMy5idyIpCmBgYAoK