Prepare sequences
transferredRNA = read.csv('simplex.csv')
names(transferredRNA)[1] = "ID"
gff = read.gff("simplex.gff")
gff$ID = str_match(gff$attributes, "ID=[a-z0-9]*")
gff$ID = substr(gff$ID,4,100)
transferredRNA$sstart = gff$start[match(transferredRNA$ID, gff$ID)]
transferredRNA$end = gff$end[match(transferredRNA$ID, gff$ID)]
genomefilename = "GCF_001578185.1_ASM157818v1_genomic.fna"
fasta = read.FASTA(genomefilename)
names(fasta) = c("genome", "plasmid")
# initialize fasta to empty values
transferredRNA$fasta = ""
# Remove genes without known start and end points in the GFF file.
nona_trRNA = transferredRNA[!is.na(transferredRNA$sstart),]
# b. Attach positive gene with matching sequence
for (index in which(nona_trRNA$count >= 0)) {
bases = nona_trRNA$sstart[index]:nona_trRNA$end[index]
nucleotide2 = fasta$genome[bases]
nucleotide3 = lapply(nucleotide2, as.character.DNAbin)
nona_trRNA$fasta[index] = paste0( unlist(nucleotide3), collapse='')
nona_trRNA$geneLength[index] = nchar(nona_trRNA$fasta[index])
}
pos = nona_trRNA$fasta[nona_trRNA$count > 2]
genes = nona_trRNA$fasta
# Change to biostrings object, then RC and finally as.character
genesRC = lapply(lapply(lapply(genes, DNAString),reverseComplement), as.character)
# positives change to biostring object
posRC = lapply(lapply(lapply(pos, DNAString),reverseComplement), as.character)
# remove big unnecessary objects
rm(fasta, gff, nona_trRNA)
Controls
Random sampling of genes
# sampling
samples = 100
genesSample = tibble(x=1:length(posRC))
for(index in seq(samples)) {
# randomSample[index] = unlist(lapply(genes.length, randDNA))
genesSample[index] = unlist(sample(genesRC, length(posRC)))
}
Random sequences with same nucleotide ratios
# random sequences
# array with nucleotides with same ratio as transferred genes
As = sum(stri_count_fixed(posRC,"A"))
Ts = sum(stri_count_fixed(posRC,"T"))
Gs = sum(stri_count_fixed(posRC,"G"))
Cs = sum(stri_count_fixed(posRC,"C"))
pos.nucleotides = c(rep("A", As), rep("G", Gs), rep("C", Cs), rep("T", Ts))
genes.length = unlist(lapply(lapply(posRC, DNAString), length))
randomSample = matrix(nrow = length(posRC), ncol = samples)
for (resample in seq(samples)){
for (gene.index in seq(genes.length)) {
sequence = sample(pos.nucleotides, as.integer(genes.length[gene.index]))
randomSample[gene.index, resample] = paste0(sequence, collapse = "")
}
}
randomSample = unlist(randomSample)
Looking for the motive
Motive specifications
# numeric Input
maxRepetitions = 27
# motiveUnit = "([atgc][tc][atgc])"
# tc ac ag at gc tg
motiveUnit = toupper("([atgc][tc][atgc])")
# motive results array
motivesHits = data.frame( repetitions = integer(maxRepetitions))
Look the motive in transferred genes
repetitions = 0
for (index in seq(maxRepetitions)) {
repetitions = index + 5
pattern = paste0(motiveUnit,"{",repetitions, ",}")
motivesHits$repetitions[index] = repetitions
motivesHits$positiveRC[index] = sum(stri_count_regex(unlist(posRC), pattern))
}
Look the motive in random sequences
randomSD = matrix(nrow = maxRepetitions)
repetitions=0
for (index in seq(maxRepetitions)){
repetitions = index + 5
pattern = paste0(motiveUnit,"{",repetitions, ",}")
hits.per.gene = stri_count_regex(randomSample, pattern)
motivesHits$random[index] = sum(hits.per.gene) / samples
# randomSD[index] = sd(hits)
}
rm(randomSample)
Look the motive in genes samples
sampleHits = matrix(nrow = maxRepetitions, ncol = samples)
repetitions = 0
for (index in seq(maxRepetitions)) {
repetitions = index + 5
pattern = paste0(motiveUnit,"{",repetitions, ",}")
sampleHits[index,] = stri_count_regex(genesSample, pattern)
}
sampleHits = data.frame(sampleHits)
motivesHits$samples = apply(sampleHits , 1, mean)
sampleHits$repetitions = 6 : (maxRepetitions + 5)
rm(genesSample)
Arrange the data
melted.table = melt(motivesHits, id = "repetitions")
melted.table$value = round(melted.table$value)
meltSamp = melt(sampleHits, id = "repetitions")
Calculate P-value, the percentage of random sets at each length that had a fraction of genes with the motif that was higher than in the real set.
pval = (apply(sampleHits[,1:samples] > motivesHits$positiveRC, 1, sum) + 1) /
(samples + 1)
pval
[1] 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099
[10] 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.02970297
[19] 0.01980198 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099 0.00990099
Motive repetitions in B. simplex
# load("results/molten_##.rdata")
title = bquote(.(motiveUnit) ['n']~ "motive repetitions in " ~ italic("B. simplex"))
Xs = paste0(rep("X", samples), 1:samples)
leg.colors = c("#E69F00", "#56B4E9",rep("#999999", samples))
leg.breaks = c("positiveRC", "random", Xs)
leg = c(values = leg.colors, breaks = leg.breaks)
p = ggplot(melted.table, aes(repetitions, value, variable)) +
geom_point(aes(repetitions, value)
, data = meltSamp
, color = "grey"
, alpha = 0.3
, position = position_jitter(w = 0.5, h = 0)) +
geom_line(aes(repetitions, value, color = variable), size = 2) +
scale_color_manual(values = c("#619CFF","#F8766D","grey")
,labels = c( "Transferred genes"
, "Random sequences"
, "Random genes samples")) +
scale_y_log10(breaks = c(1,10,100,1000,10000)) +
scale_x_continuous(expand = c(0, -0.3)) +
labs(y = "Motive occurrences (#)", x = "Motive repetitions (length)"
, color = "", group = "genes") +
theme_classic() +
theme( text = element_text(size=28)
,title = element_text(size=22)
,legend.position = c(0.75,0.9)
,panel.background = element_blank()
,plot.title = element_text(hjust = 0.5)
) +
ggtitle(title)
p

Save the graph
motivename = substr(motiveUnit, 9, 10)
file.png = paste0("results/greyRandom_",motivename , ".png")
file.svg = paste0("results/greyRandom_", motivename, ".svg")
ggsave(filename = file.png, p, width = 10)
ggsave(filename = file.svg, p, width = 10)
Another graph same values
line = list(width = 3)
p2 = plot_ly(
type = "scatter"
, mode = "markers+lines"
)
p2 = add_trace( p2
, data = melted.table[melted.table$variable =="positiveRC",]
, x = ~repetitions
, y = ~value
, color = ~variable
, line = list(width = 6)
# , name = c("Transferred genes", "Random sequences")
)
p2 = add_markers( p2
, data = melted.table
, x = jitter(melted.table$repetitions)
, y = ~value
, opacity = 0.3
, marker = list(color = "grey", opacity = 0.3)
, name = "genes samples"
)
p2 = add_markers( p2
, data = melted.table[melted.table$variable =="random",]
, x = ~repetitions
, y = ~value
, marker = list(color = "orange")
, name = "Random sequences"
)
p2 = layout( p2
,yaxis = list(type = "log", title = "Hits (#)", zeroline = F, showgrid = F)
,xaxis = list(title = "Motive Repetitions", showgrid = F)
,title = "(NYN)<sub>n</sub> motive in <i>B. simplex</i> genome"
,font = list(size = 12)
,legend = list(x = 0.8, y = 0.9)
,paper_bgcolor = 'rgba(0,0,0,0)'
,plot_bgcolor = 'rgba(0,0,0,0)'
)
p2 # %>% add_annotations(text = "<b> RC = <br>Reverse <br>Complement</b>", x = 23, y = 2.2, showarrow = F)
Source code here
LS0tDQp0aXRsZTogIm1vdGl2ZSBhbmFseXppbmcgZm9yIGVhY2ggc2FtcGxlIg0KYXV0aG9yOiAiUm90ZW0gSGFkYXIiDQpkYXRlOiAiRGVjZW1iZXIgOSwgMjAxOCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCnRvYzogeWVzDQotLS0NCiANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoYXBlKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShzdHJpbmdpKQ0KbGlicmFyeShCaW9zdHJpbmdzKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShodG1sVGFibGUpDQpsaWJyYXJ5KFJCaW9pbmYpDQpsaWJyYXJ5KCJjb3dwbG90IikNCmxpYnJhcnkoZmdwdCkNCmxpYnJhcnkoZHBseXIpDQoNCmBgYA0KDQoNCiMjIyAgUHJlcGFyZSBzZXF1ZW5jZXMNCmBgYHtyIHNlcXVlbmNlc30NCnRyYW5zZmVycmVkUk5BID0gcmVhZC5jc3YoJ3NpbXBsZXguY3N2JykNCm5hbWVzKHRyYW5zZmVycmVkUk5BKVsxXSA9ICJJRCINCg0KZ2ZmID0gcmVhZC5nZmYoInNpbXBsZXguZ2ZmIikNCmdmZiRJRCA9IHN0cl9tYXRjaChnZmYkYXR0cmlidXRlcywgIklEPVthLXowLTldKiIpDQpnZmYkSUQgPSBzdWJzdHIoZ2ZmJElELDQsMTAwKQ0KDQp0cmFuc2ZlcnJlZFJOQSRzc3RhcnQgPSBnZmYkc3RhcnRbbWF0Y2godHJhbnNmZXJyZWRSTkEkSUQsIGdmZiRJRCldDQp0cmFuc2ZlcnJlZFJOQSRlbmQgPSBnZmYkZW5kW21hdGNoKHRyYW5zZmVycmVkUk5BJElELCBnZmYkSUQpXQ0KDQpnZW5vbWVmaWxlbmFtZSA9ICJHQ0ZfMDAxNTc4MTg1LjFfQVNNMTU3ODE4djFfZ2Vub21pYy5mbmEiDQpmYXN0YSA9IHJlYWQuRkFTVEEoZ2Vub21lZmlsZW5hbWUpDQpuYW1lcyhmYXN0YSkgPSBjKCJnZW5vbWUiLCAicGxhc21pZCIpDQoNCiMgaW5pdGlhbGl6ZSBmYXN0YSB0byBlbXB0eSB2YWx1ZXMNCnRyYW5zZmVycmVkUk5BJGZhc3RhID0gIiINCiMgUmVtb3ZlIGdlbmVzIHdpdGhvdXQga25vd24gc3RhcnQgYW5kIGVuZCBwb2ludHMgaW4gdGhlIEdGRiBmaWxlLg0Kbm9uYV90clJOQSA9IHRyYW5zZmVycmVkUk5BWyFpcy5uYSh0cmFuc2ZlcnJlZFJOQSRzc3RhcnQpLF0NCiMgYi4gQXR0YWNoIHBvc2l0aXZlIGdlbmUgd2l0aCBtYXRjaGluZyBzZXF1ZW5jZQ0KZm9yIChpbmRleCBpbiB3aGljaChub25hX3RyUk5BJGNvdW50ID49IDApKSB7DQogIGJhc2VzID0gbm9uYV90clJOQSRzc3RhcnRbaW5kZXhdOm5vbmFfdHJSTkEkZW5kW2luZGV4XQ0KICBudWNsZW90aWRlMiA9IGZhc3RhJGdlbm9tZVtiYXNlc10NCiAgbnVjbGVvdGlkZTMgPSBsYXBwbHkobnVjbGVvdGlkZTIsIGFzLmNoYXJhY3Rlci5ETkFiaW4pDQogIG5vbmFfdHJSTkEkZmFzdGFbaW5kZXhdID0gcGFzdGUwKCB1bmxpc3QobnVjbGVvdGlkZTMpLCBjb2xsYXBzZT0nJykNCiAgbm9uYV90clJOQSRnZW5lTGVuZ3RoW2luZGV4XSA9IG5jaGFyKG5vbmFfdHJSTkEkZmFzdGFbaW5kZXhdKQ0KfQ0KDQpwb3MgPSBub25hX3RyUk5BJGZhc3RhW25vbmFfdHJSTkEkY291bnQgPiAyXQ0KZ2VuZXMgPSBub25hX3RyUk5BJGZhc3RhDQogICAgICAjIENoYW5nZSB0byBiaW9zdHJpbmdzIG9iamVjdCwgdGhlbiBSQyBhbmQgZmluYWxseSBhcy5jaGFyYWN0ZXINCiAgZ2VuZXNSQyA9IGxhcHBseShsYXBwbHkobGFwcGx5KGdlbmVzLCBETkFTdHJpbmcpLHJldmVyc2VDb21wbGVtZW50KSwgYXMuY2hhcmFjdGVyKQ0KDQojIHBvc2l0aXZlcyBjaGFuZ2UgdG8gYmlvc3RyaW5nIG9iamVjdA0KICBwb3NSQyA9IGxhcHBseShsYXBwbHkobGFwcGx5KHBvcywgRE5BU3RyaW5nKSxyZXZlcnNlQ29tcGxlbWVudCksIGFzLmNoYXJhY3RlcikNCg0KIyByZW1vdmUgYmlnIHVubmVjZXNzYXJ5IG9iamVjdHMNCnJtKGZhc3RhLCBnZmYsIG5vbmFfdHJSTkEpDQoNCmBgYA0KDQojIyMjIENvbnRyb2xzDQojIyMjIyBSYW5kb20gc2FtcGxpbmcgb2YgZ2VuZXMNCmBgYHtyfQ0KIyAgc2FtcGxpbmcNCnNhbXBsZXMgPSAxMDANCiAgZ2VuZXNTYW1wbGUgPSB0aWJibGUoeD0xOmxlbmd0aChwb3NSQykpDQpmb3IoaW5kZXggaW4gc2VxKHNhbXBsZXMpKSB7DQogICMgcmFuZG9tU2FtcGxlW2luZGV4XSA9IHVubGlzdChsYXBwbHkoZ2VuZXMubGVuZ3RoLCByYW5kRE5BKSkNCiAgICAgIGdlbmVzU2FtcGxlW2luZGV4XSA9IHVubGlzdChzYW1wbGUoZ2VuZXNSQywgbGVuZ3RoKHBvc1JDKSkpDQp9DQpgYGANCg0KIyMjIyMgUmFuZG9tIHNlcXVlbmNlcyB3aXRoIHNhbWUgbnVjbGVvdGlkZSByYXRpb3MNCmBgYHtyfQ0KIyAgcmFuZG9tIHNlcXVlbmNlcyANCiMgIGFycmF5IHdpdGggbnVjbGVvdGlkZXMgd2l0aCBzYW1lIHJhdGlvIGFzIHRyYW5zZmVycmVkIGdlbmVzDQogIEFzID0gc3VtKHN0cmlfY291bnRfZml4ZWQocG9zUkMsIkEiKSkNCiAgVHMgPSBzdW0oc3RyaV9jb3VudF9maXhlZChwb3NSQywiVCIpKQ0KICBHcyA9IHN1bShzdHJpX2NvdW50X2ZpeGVkKHBvc1JDLCJHIikpDQogIENzID0gc3VtKHN0cmlfY291bnRfZml4ZWQocG9zUkMsIkMiKSkgICAgICAgIA0KcG9zLm51Y2xlb3RpZGVzID0gYyhyZXAoIkEiLCBBcyksIHJlcCgiRyIsIEdzKSwgcmVwKCJDIiwgQ3MpLCByZXAoIlQiLCBUcykpDQogIGdlbmVzLmxlbmd0aCA9IHVubGlzdChsYXBwbHkobGFwcGx5KHBvc1JDLCBETkFTdHJpbmcpLCBsZW5ndGgpKQ0KDQogIHJhbmRvbVNhbXBsZSA9IG1hdHJpeChucm93ID0gbGVuZ3RoKHBvc1JDKSwgbmNvbCA9IHNhbXBsZXMpDQpmb3IgKHJlc2FtcGxlIGluIHNlcShzYW1wbGVzKSl7DQogIGZvciAoZ2VuZS5pbmRleCBpbiBzZXEoZ2VuZXMubGVuZ3RoKSkgew0KICAgIHNlcXVlbmNlID0gc2FtcGxlKHBvcy5udWNsZW90aWRlcywgYXMuaW50ZWdlcihnZW5lcy5sZW5ndGhbZ2VuZS5pbmRleF0pKQ0KICAgIHJhbmRvbVNhbXBsZVtnZW5lLmluZGV4LCByZXNhbXBsZV0gPSBwYXN0ZTAoc2VxdWVuY2UsIGNvbGxhcHNlID0gIiIpDQogIH0NCn0NCnJhbmRvbVNhbXBsZSA9IHVubGlzdChyYW5kb21TYW1wbGUpDQpgYGANCg0KIyMjIExvb2tpbmcgZm9yIHRoZSBtb3RpdmUNCiMjIyMgTW90aXZlIHNwZWNpZmljYXRpb25zDQpgYGB7ciBtb3RpdmVEZWNsZXJhdGlvbn0NCiMgbnVtZXJpYyBJbnB1dA0KbWF4UmVwZXRpdGlvbnMgPSAyNw0KIyBtb3RpdmVVbml0ID0gIihbYXRnY11bdGNdW2F0Z2NdKSINCiMgdGMgYWMgYWcgYXQgZ2MgdGcNCm1vdGl2ZVVuaXQgPSB0b3VwcGVyKCIoW2F0Z2NdW3RjXVthdGdjXSkiKQ0KDQojICBtb3RpdmUgcmVzdWx0cyBhcnJheQ0KbW90aXZlc0hpdHMgPSBkYXRhLmZyYW1lKCByZXBldGl0aW9ucyA9IGludGVnZXIobWF4UmVwZXRpdGlvbnMpKQ0KYGBgDQoNCiMjIyMgTG9vayB0aGUgbW90aXZlIGluIHRyYW5zZmVycmVkIGdlbmVzDQpgYGB7ciBMb29rUG9zaXRpdmV9IA0KcmVwZXRpdGlvbnMgPSAwDQpmb3IgKGluZGV4IGluIHNlcShtYXhSZXBldGl0aW9ucykpIHsNCiAgcmVwZXRpdGlvbnMgPSBpbmRleCArIDUNCiAgcGF0dGVybiA9IHBhc3RlMChtb3RpdmVVbml0LCJ7IixyZXBldGl0aW9ucywgIix9IikNCiAgbW90aXZlc0hpdHMkcmVwZXRpdGlvbnNbaW5kZXhdID0gcmVwZXRpdGlvbnMNCiAgICAgIG1vdGl2ZXNIaXRzJHBvc2l0aXZlUkNbaW5kZXhdID0gc3VtKHN0cmlfY291bnRfcmVnZXgodW5saXN0KHBvc1JDKSwgcGF0dGVybikpDQp9DQpgYGANCg0KIyMjIyBMb29rIHRoZSBtb3RpdmUgaW4gcmFuZG9tIHNlcXVlbmNlcw0KYGBge3IgTG9va1JhbmRvbX0NCnJhbmRvbVNEID0gbWF0cml4KG5yb3cgPSBtYXhSZXBldGl0aW9ucykNCg0KcmVwZXRpdGlvbnM9MA0KZm9yIChpbmRleCBpbiBzZXEobWF4UmVwZXRpdGlvbnMpKXsNCiAgcmVwZXRpdGlvbnMgPSBpbmRleCArIDUNCg0KICBwYXR0ZXJuID0gcGFzdGUwKG1vdGl2ZVVuaXQsInsiLHJlcGV0aXRpb25zLCAiLH0iKQ0KICBoaXRzLnBlci5nZW5lID0gc3RyaV9jb3VudF9yZWdleChyYW5kb21TYW1wbGUsIHBhdHRlcm4pDQogIG1vdGl2ZXNIaXRzJHJhbmRvbVtpbmRleF0gPSBzdW0oaGl0cy5wZXIuZ2VuZSkgLyBzYW1wbGVzDQogICMgcmFuZG9tU0RbaW5kZXhdID0gc2QoaGl0cykNCn0NCg0Kcm0ocmFuZG9tU2FtcGxlKQ0KYGBgDQoNCiMjIyMgTG9vayB0aGUgbW90aXZlIGluIGdlbmVzIHNhbXBsZXMNCmBgYHtyIExvb2tTYW1wbGVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc2FtcGxlSGl0cyA9IG1hdHJpeChucm93ID0gbWF4UmVwZXRpdGlvbnMsIG5jb2wgPSBzYW1wbGVzKQ0KDQpyZXBldGl0aW9ucyA9IDANCmZvciAoaW5kZXggaW4gc2VxKG1heFJlcGV0aXRpb25zKSkgew0KICByZXBldGl0aW9ucyA9IGluZGV4ICsgNQ0KICANCiAgcGF0dGVybiA9IHBhc3RlMChtb3RpdmVVbml0LCJ7IixyZXBldGl0aW9ucywgIix9IikNCiAgc2FtcGxlSGl0c1tpbmRleCxdID0gc3RyaV9jb3VudF9yZWdleChnZW5lc1NhbXBsZSwgcGF0dGVybikNCn0NCg0Kc2FtcGxlSGl0cyA9IGRhdGEuZnJhbWUoc2FtcGxlSGl0cykNCg0KbW90aXZlc0hpdHMkc2FtcGxlcyA9IGFwcGx5KHNhbXBsZUhpdHMgLCAxLCBtZWFuKQ0Kc2FtcGxlSGl0cyRyZXBldGl0aW9ucyA9IDYgOiAobWF4UmVwZXRpdGlvbnMgKyA1KQ0KDQpybShnZW5lc1NhbXBsZSkNCmBgYA0KDQojIyMjIyBBcnJhbmdlIHRoZSBkYXRhDQpgYGB7ciBtZWx0RGF0YX0NCm1lbHRlZC50YWJsZSA9IG1lbHQobW90aXZlc0hpdHMsIGlkID0gInJlcGV0aXRpb25zIikNCm1lbHRlZC50YWJsZSR2YWx1ZSA9IHJvdW5kKG1lbHRlZC50YWJsZSR2YWx1ZSkNCm1lbHRTYW1wID0gbWVsdChzYW1wbGVIaXRzLCBpZCA9ICJyZXBldGl0aW9ucyIpDQpgYGANCg0KQ2FsY3VsYXRlIFAtdmFsdWUsIHRoZSBwZXJjZW50YWdlIG9mIHJhbmRvbSBzZXRzIGF0IGVhY2ggbGVuZ3RoIHRoYXQgaGFkIGEgZnJhY3Rpb24gb2YgZ2VuZXMgd2l0aCB0aGUgbW90aWYgdGhhdCB3YXMgaGlnaGVyIHRoYW4gaW4gdGhlIHJlYWwgc2V0Lg0KYGBge3J9DQpwdmFsID0gKGFwcGx5KHNhbXBsZUhpdHNbLDE6c2FtcGxlc10gPiBtb3RpdmVzSGl0cyRwb3NpdGl2ZVJDLCAxLCBzdW0pICsgMSkgLw0KICAoc2FtcGxlcyArIDEpDQpwdmFsDQpgYGANCg0KDQojIE1vdGl2ZSByZXBldGl0aW9ucyBpbiBfQi4gc2ltcGxleF8NCmBgYHtyIGdncGxvdH0NCiMgbG9hZCgicmVzdWx0cy9tb2x0ZW5fIyMucmRhdGEiKQ0KdGl0bGUgPSBicXVvdGUoLihtb3RpdmVVbml0KSBbJ24nXX4gIm1vdGl2ZSByZXBldGl0aW9ucyBpbiAiIH4gaXRhbGljKCJCLiBzaW1wbGV4IikpDQpYcyA9IHBhc3RlMChyZXAoIlgiLCBzYW1wbGVzKSwgMTpzYW1wbGVzKQ0KbGVnLmNvbG9ycyA9IGMoIiNFNjlGMDAiLCAiIzU2QjRFOSIscmVwKCIjOTk5OTk5Iiwgc2FtcGxlcykpDQogIGxlZy5icmVha3MgPSBjKCJwb3NpdGl2ZVJDIiwgInJhbmRvbSIsIFhzKQ0KbGVnID0gYyh2YWx1ZXMgPSBsZWcuY29sb3JzLCBicmVha3MgPSBsZWcuYnJlYWtzKQ0KDQogICBwID0gZ2dwbG90KG1lbHRlZC50YWJsZSwgYWVzKHJlcGV0aXRpb25zLCB2YWx1ZSwgdmFyaWFibGUpKSArDQogICAgIA0KICAgICBnZW9tX3BvaW50KGFlcyhyZXBldGl0aW9ucywgdmFsdWUpDQogICAgICAgICAgICAgICAgLCBkYXRhID0gbWVsdFNhbXANCiAgICAgICAgICAgICAgICAsIGNvbG9yID0gImdyZXkiDQogICAgICAgICAgICAgICAgLCBhbHBoYSA9IDAuMw0KICAgICAgICAgICAgICAgICwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIodyA9IDAuNSwgaCA9IDApKSArDQogICAgIA0KICAgICBnZW9tX2xpbmUoYWVzKHJlcGV0aXRpb25zLCB2YWx1ZSwgY29sb3IgPSB2YXJpYWJsZSksIHNpemUgPSAyKSArDQogICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjNjE5Q0ZGIiwiI0Y4NzY2RCIsImdyZXkiKQ0KICAgICAgICAgICAgICAgICAgICAgICAgLGxhYmVscyA9IGMoICAiVHJhbnNmZXJyZWQgZ2VuZXMiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICJSYW5kb20gc2VxdWVuY2VzIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAiUmFuZG9tIGdlbmVzIHNhbXBsZXMiKSkgKyANCiAgICAgc2NhbGVfeV9sb2cxMChicmVha3MgPSBjKDEsMTAsMTAwLDEwMDAsMTAwMDApKSArDQogICAgIA0KICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAtMC4zKSkgKw0KICAgICBsYWJzKHkgPSAiTW90aXZlIG9jY3VycmVuY2VzICgjKSIsIHggPSAiTW90aXZlIHJlcGV0aXRpb25zIChsZW5ndGgpIg0KICAgICAgICAgICwgY29sb3IgPSAiIiwgZ3JvdXAgPSAiZ2VuZXMiKSArDQogICAgIHRoZW1lX2NsYXNzaWMoKSArIA0KICAgICB0aGVtZSggIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yOCkgDQogICAgICAgICAgICAsdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMikgDQogICAgICAgICAgICAsbGVnZW5kLnBvc2l0aW9uID0gYygwLjc1LDAuOSkgDQogICAgICAgICAgICAscGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSANCiAgICAgICAgICAgICxwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSANCiAgICAgICAgICApICsgDQogICAgIGdndGl0bGUodGl0bGUpIA0KICAgcA0KYGBgDQojIyMjIyBTYXZlIHRoZSBncmFwaA0KYGBge3Igc2F2ZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCm1vdGl2ZW5hbWUgPSBzdWJzdHIobW90aXZlVW5pdCwgOSwgMTApDQpmaWxlLnBuZyA9IHBhc3RlMCgicmVzdWx0cy9ncmV5UmFuZG9tXyIsbW90aXZlbmFtZSAsICIucG5nIikNCmZpbGUuc3ZnID0gcGFzdGUwKCJyZXN1bHRzL2dyZXlSYW5kb21fIiwgbW90aXZlbmFtZSwgIi5zdmciKSANCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGUucG5nLCBwLCB3aWR0aCA9IDEwKQ0KZ2dzYXZlKGZpbGVuYW1lID0gZmlsZS5zdmcsIHAsIHdpZHRoID0gMTApDQojICBzYXZlIHRoZSBkYXRhIGZvciB0aGUgcGxvdA0Kc2F2ZShmaWxlID0gcGFzdGUwKCJyZXN1bHRzL21vbHRlbl8iLCBtb3RpdmVuYW1lLCAiLnJkYXRhIikNCiAgICAgLCBtZWx0ZWQudGFibGUsIG1lbHRTYW1wLCBtb3RpdmVuYW1lLCBwdmFsKQ0KYGBgDQoNCiMjIEFub3RoZXIgZ3JhcGggc2FtZSB2YWx1ZXMNCmBgYHtyIHBsb3RseX0NCmxpbmUgPSBsaXN0KHdpZHRoID0gMykNCiAgICBwMiA9IHBsb3RfbHkoIA0KICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIg0KICAgICAgICAgICAgICAgICwgbW9kZSA9ICJtYXJrZXJzK2xpbmVzIg0KICAgICAgICAgICAgICAgICkNCiAgICBwMiA9IGFkZF90cmFjZSggcDINCiAgICAgICAgICAgICAgICAgICAgICAsIGRhdGEgPSBtZWx0ZWQudGFibGVbbWVsdGVkLnRhYmxlJHZhcmlhYmxlID09InBvc2l0aXZlUkMiLF0NCiAgICAgICAgICAgICAgICAgICAgLCB4ID0gfnJlcGV0aXRpb25zDQogICAgICAgICAgICAgICAgICAgICwgeSA9IH52YWx1ZQ0KICAgICAgICAgICAgICAgICAgICAsIGNvbG9yID0gfnZhcmlhYmxlDQogICAgICAgICAgICAgICAgICAgICwgbGluZSA9IGxpc3Qod2lkdGggPSA2KQ0KICAgICAgICAgICAgICAgICAgICAjICwgbmFtZSA9IGMoIlRyYW5zZmVycmVkIGdlbmVzIiwgIlJhbmRvbSBzZXF1ZW5jZXMiKQ0KICAgICAgICAgICAgICAgICAgICkgICAgDQogICAgcDIgPSBhZGRfbWFya2VycyggIHAyDQogICAgICAgICAgICAgICAgICAgLCBkYXRhID0gbWVsdGVkLnRhYmxlDQogICAgICAgICAgICAgICAgICAgLCB4ID0gaml0dGVyKG1lbHRlZC50YWJsZSRyZXBldGl0aW9ucykNCiAgICAgICAgICAgICAgICAgICAsIHkgPSB+dmFsdWUNCiAgICAgICAgICAgICAgICAgICAsIG9wYWNpdHkgPSAwLjMNCiAgICAgICAgICAgICAgICAgICAsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiZ3JleSIsIG9wYWNpdHkgPSAwLjMpDQogICAgICAgICAgICAgICAgICAgLCBuYW1lID0gImdlbmVzIHNhbXBsZXMiDQogICAgICAgICAgICAgICAgICApDQogICAgcDIgPSBhZGRfbWFya2VycyggcDINCiAgICAgICAgICAgICAgICAgICAgLCBkYXRhID0gbWVsdGVkLnRhYmxlW21lbHRlZC50YWJsZSR2YXJpYWJsZSA9PSJyYW5kb20iLF0NCiAgICAgICAgICAgICAgICAgICAgLCB4ID0gfnJlcGV0aXRpb25zDQogICAgICAgICAgICAgICAgICAgICwgeSA9IH52YWx1ZQ0KICAgICAgICAgICAgICAgICAgICAsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAib3JhbmdlIikNCiAgICAgICAgICAgICAgICAgICAgLCBuYW1lID0gIlJhbmRvbSBzZXF1ZW5jZXMiDQogICAgICAgICAgICAgICAgICAgKSAgICANCiAgICBwMiA9IGxheW91dCggcDINCiAgICAgICAgICAgICAgICAgLHlheGlzID0gbGlzdCh0eXBlID0gImxvZyIsIHRpdGxlID0gIkhpdHMgKCMpIiwgemVyb2xpbmUgPSBGLCBzaG93Z3JpZCA9IEYpDQogICAgICAgICAgICAgICAgICx4YXhpcyA9IGxpc3QodGl0bGUgPSAiTW90aXZlIFJlcGV0aXRpb25zIiwgc2hvd2dyaWQgPSBGKQ0KICAgICAgICAgICAgICAgICAsdGl0bGUgPSAiKE5ZTik8c3ViPm48L3N1Yj4gbW90aXZlIGluIDxpPkIuIHNpbXBsZXg8L2k+IGdlbm9tZSINCiAgICAgICAgICAgICAgICAgLGZvbnQgPSBsaXN0KHNpemUgPSAxMikNCiAgICAgICAgICAgICAgICAgLGxlZ2VuZCA9IGxpc3QoeCA9IDAuOCwgeSA9IDAuOSkNCiAgICAgICAgICAgICAgICAgLHBhcGVyX2JnY29sb3IgPSAncmdiYSgwLDAsMCwwKScNCiAgICAgICAgICAgICAgICAgLHBsb3RfYmdjb2xvciA9ICdyZ2JhKDAsMCwwLDApJw0KICAgICAgICAgICAgICAgICApDQogICAgICBwMiAjICU+JSBhZGRfYW5ub3RhdGlvbnModGV4dCA9ICI8Yj4gUkMgPSA8YnI+UmV2ZXJzZSA8YnI+Q29tcGxlbWVudDwvYj4iLCB4ID0gMjMsIHkgPSAyLjIsIHNob3dhcnJvdyA9IEYpDQpgYGANCg0KU291cmNlIGNvZGUgW2hlcmVdKGh0dHBzOi8vYml0YnVja2V0Lm9yZy9iZW56enovcm5hbW90aXZlL3NyYy9tYXN0ZXIvZWFjaFJhbmRvbU1vdGl2ZS5ybWQp