Here, I am explaining the processing step of variants for GWAS. Please, ignore the code parts unless interested in details.
Variant loci are generated from the multiple sequence alignments of all EBV genomes we sequenced. Positions and reference allele are in reference to Type 1 reference genome NC_007605.
After calling the variants, we filter out the ones that come from repeatitive regions. We keep all the variants including the synonymous ones as the reviewers suggested. This leaves us 6,495 variant loci to start with.
cd ~/Documents/EBV/ourbatch2/Secondround/ && mkdir SNP-detect_02.27.2020 %% cd SNP-detect_02.27.2020
toolDir='~/Dropbox/codes/ViralGenomeAssembly'
#This will create a vcf file out of the msa using the very first genome (NC_007605) as the reference:
bash $toolDir/scripts/snp_sites_vcf_modifier.sh my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub.with-Ref1.fasta
#Filter the variants in the repeat regions:
bedtools intersect -header -v -wa -a my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub.with-Ref1_modified.vcf -b $toolDir/resources/Annotation/Type1/NC_007605_repeatMask.bed |bedtools intersect -header -v -wa -a - -b $toolDir/resources/Annotation/Type1/NC_007605_miropeat_default_run_repeats.bed|bedtools intersect -header -v -wa -a - -b $toolDir/resources/Annotation/Type1/filter.regions.bed > my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub.with-Ref1_modified_filtered.vcf
#Remove the reference genome entry from the vcf data:
cut -f1-9,11- my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub.with-Ref1_modified_filtered.vcf > my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub_modified_filtered.vcf
Do PCA and check the SNP variation:
Here, I do PCA on variants to use the PC3 as a cofactor in the association test below. PC3 is the principal component that separated the type 2 genomes into Group A and Group B in Figure 2B-lower panel. Also, reviewers wants us to account for the population structure.
summary(pops)
Method EBV_Type Condition Label
Direct Sequencing:33 Inter-typic: 3 eBL :58 eBL_Cell_Line : 3
GenomiPhi-WGA :13 Type1 :60 HealthyControl:40 eBL_Plasma :14
Preamp-sWGA :52 Type2 :35 eBL_Tumor :41
HealthyControl:40
Genome-wide association with GMMAT
This part is the actual GWAS using generalized mixed model with GRM of EBV as the random effect and Age, Gender, EBV type, and PC3 as the fixed effects.
In the test, I mask (not test) the variant loci with less than 5% minor allele frequency and more than 50% missing data. This gives us 2,807 variant loci to be tested.
library(GMMAT)
sampleDemo$id <- rownames(sampleDemo)
GRM.ebv <- as.matrix(read.table("~/Documents/EBV/ourbatch2/Secondround/SNP-detect_02.27.2020/output/GRM.ebv.cXX.txt", check.names = FALSE))
rownames(GRM.ebv) <- sampleDemo$id
colnames(GRM.ebv) <- sampleDemo$id
#pheatmap::pheatmap(GRM.ebv, cluster_rows = F, cluster_cols = F, annotation_col = sampleDemo[,c("Type","Gender","Age","Method")])
geno.file <- strsplit(system.file("extdata", "my.plink.ped.data.bed", package = "GMMAT"), ".bed", fixed = TRUE)[[1]]
model0 <- glmmkin(Phe ~ Type + Age + Gender + PC3, data = sampleDemo, kins = GRM.ebv, id = "id", family = binomial(link = "logit"))
glmm.score(model0,
missing.method = "omit",
infile = geno.file,
MAF.range = c(0.05, 0.5),
miss.cutoff = 0.5,
outfile = "glmm.score.gds.testoutfile.txt")
score.results <- read.delim("glmm.score.gds.testoutfile.txt", header=T)
Determine the genome-wide significance threshold:
Here, I determine the genome-wide significance threshold via phenotype (BL/healthy control) label permutations (1,000 times). This resulted in a suggestive significance threshold of 0.000999952 ~= 10^-3.
P.pool <- data.frame(row.names = rownames(score.results))
for( i in 1:1000){
print(i)
#Permuting the phenotype of interest
sampleDemo.rand <- sampleDemo
sampleDemo.rand$Phe <- sample(sampleDemo$Phe, replace = T)
model.rand <- glmmkin(Phe ~ Type + Age + Gender + PC3, data = sampleDemo.rand, kins = GRM.ebv, id = "id", family = binomial(link = "logit"))
glmm.score(model.rand,
missing.method = "omit",
infile = geno.file,
MAF.range = c(0.05, 0.5),
miss.cutoff = 0.5,
outfile = "glmm.score.Phe-Permutation.txt")
score.results.rand <- read.delim("glmm.score.Phe-Permutation.txt", header=T)
P.pool <- cbind(P.pool, P=score.results.rand$PVAL)
}
plist <- head(sort(apply(P.pool, 1, min)), dim(P.pool)[1]*5/100)
plist[length(plist)]#0.000999952
-log10(plist[length(plist)])
write.csv(P.pool, file = "P.pool.txt")
The Manhattan plot of the results:
The suggestive genome-wide significance threshold of ~3 (in -log10) results in No significant variant in the analysis. Please see the plot below:

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayBmb3IgRUJWIEJMIC0gR1dBUyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQogCkhlcmUsIEkgYW0gZXhwbGFpbmluZyB0aGUgcHJvY2Vzc2luZyBzdGVwIG9mIHZhcmlhbnRzIGZvciBHV0FTLiBQbGVhc2UsIGlnbm9yZSB0aGUgY29kZSBwYXJ0cyB1bmxlc3MgaW50ZXJlc3RlZCBpbiBkZXRhaWxzLiAKClZhcmlhbnQgbG9jaSBhcmUgZ2VuZXJhdGVkIGZyb20gdGhlIG11bHRpcGxlIHNlcXVlbmNlIGFsaWdubWVudHMgb2YgYWxsIEVCViBnZW5vbWVzIHdlIHNlcXVlbmNlZC4gUG9zaXRpb25zIGFuZCByZWZlcmVuY2UgYWxsZWxlIGFyZSBpbiByZWZlcmVuY2UgdG8gVHlwZSAxIHJlZmVyZW5jZSBnZW5vbWUgTkNfMDA3NjA1LgoKQWZ0ZXIgY2FsbGluZyB0aGUgdmFyaWFudHMsIHdlIGZpbHRlciBvdXQgdGhlIG9uZXMgdGhhdCBjb21lIGZyb20gcmVwZWF0aXRpdmUgcmVnaW9ucy4gV2Uga2VlcCBhbGwgdGhlIHZhcmlhbnRzIGluY2x1ZGluZyB0aGUgc3lub255bW91cyBvbmVzIGFzIHRoZSByZXZpZXdlcnMgc3VnZ2VzdGVkLiBUaGlzIGxlYXZlcyB1cyA2LDQ5NSB2YXJpYW50IGxvY2kgdG8gc3RhcnQgd2l0aC4KCmBgYHtiYXNofQpjZCB+L0RvY3VtZW50cy9FQlYvb3VyYmF0Y2gyL1NlY29uZHJvdW5kLyAmJiBta2RpciBTTlAtZGV0ZWN0XzAyLjI3LjIwMjAgJSUgY2QgU05QLWRldGVjdF8wMi4yNy4yMDIwCnRvb2xEaXI9J34vRHJvcGJveC9jb2Rlcy9WaXJhbEdlbm9tZUFzc2VtYmx5JwoKI1RoaXMgd2lsbCBjcmVhdGUgYSB2Y2YgZmlsZSBvdXQgb2YgdGhlIG1zYSB1c2luZyB0aGUgdmVyeSBmaXJzdCBnZW5vbWUgKE5DXzAwNzYwNSkgYXMgdGhlIHJlZmVyZW5jZToKYmFzaCAkdG9vbERpci9zY3JpcHRzL3NucF9zaXRlc192Y2ZfbW9kaWZpZXIuc2ggbXlfSUNlZF9teV9lZGl0ZWRfc2VxdWVuY2UuYWxuLklEcmVwbGFjZWQuT25seUluZGl2aWR1YWxzLU1pbnVzQ2VsbExpbmVzX3N1Yi53aXRoLVJlZjEuZmFzdGEKCiNGaWx0ZXIgdGhlIHZhcmlhbnRzIGluIHRoZSByZXBlYXQgcmVnaW9uczoKYmVkdG9vbHMgaW50ZXJzZWN0IC1oZWFkZXIgLXYgLXdhIC1hIG15X0lDZWRfbXlfZWRpdGVkX3NlcXVlbmNlLmFsbi5JRHJlcGxhY2VkLk9ubHlJbmRpdmlkdWFscy1NaW51c0NlbGxMaW5lc19zdWIud2l0aC1SZWYxX21vZGlmaWVkLnZjZiAtYiAkdG9vbERpci9yZXNvdXJjZXMvQW5ub3RhdGlvbi9UeXBlMS9OQ18wMDc2MDVfcmVwZWF0TWFzay5iZWQgfGJlZHRvb2xzIGludGVyc2VjdCAtaGVhZGVyIC12IC13YSAtYSAtIC1iICR0b29sRGlyL3Jlc291cmNlcy9Bbm5vdGF0aW9uL1R5cGUxL05DXzAwNzYwNV9taXJvcGVhdF9kZWZhdWx0X3J1bl9yZXBlYXRzLmJlZHxiZWR0b29scyBpbnRlcnNlY3QgLWhlYWRlciAtdiAtd2EgLWEgLSAtYiAkdG9vbERpci9yZXNvdXJjZXMvQW5ub3RhdGlvbi9UeXBlMS9maWx0ZXIucmVnaW9ucy5iZWQgPiBteV9JQ2VkX215X2VkaXRlZF9zZXF1ZW5jZS5hbG4uSURyZXBsYWNlZC5Pbmx5SW5kaXZpZHVhbHMtTWludXNDZWxsTGluZXNfc3ViLndpdGgtUmVmMV9tb2RpZmllZF9maWx0ZXJlZC52Y2YKCiNSZW1vdmUgdGhlIHJlZmVyZW5jZSBnZW5vbWUgZW50cnkgZnJvbSB0aGUgdmNmIGRhdGE6IApjdXQgLWYxLTksMTEtIG15X0lDZWRfbXlfZWRpdGVkX3NlcXVlbmNlLmFsbi5JRHJlcGxhY2VkLk9ubHlJbmRpdmlkdWFscy1NaW51c0NlbGxMaW5lc19zdWIud2l0aC1SZWYxX21vZGlmaWVkX2ZpbHRlcmVkLnZjZiA+IG15X0lDZWRfbXlfZWRpdGVkX3NlcXVlbmNlLmFsbi5JRHJlcGxhY2VkLk9ubHlJbmRpdmlkdWFscy1NaW51c0NlbGxMaW5lc19zdWJfbW9kaWZpZWRfZmlsdGVyZWQudmNmCmBgYAoKIyMjIERvIFBDQSBhbmQgY2hlY2sgdGhlIFNOUCB2YXJpYXRpb246CkhlcmUsIEkgZG8gUENBIG9uIHZhcmlhbnRzIHRvIHVzZSB0aGUgUEMzIGFzIGEgY29mYWN0b3IgaW4gdGhlIGFzc29jaWF0aW9uIHRlc3QgYmVsb3cuIFBDMyBpcyB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudCB0aGF0IHNlcGFyYXRlZCB0aGUgdHlwZSAyIGdlbm9tZXMgaW50byBHcm91cCBBIGFuZCBHcm91cCBCIGluIEZpZ3VyZSAyQi1sb3dlciBwYW5lbC4gQWxzbywgcmV2aWV3ZXJzIHdhbnRzIHVzIHRvIGFjY291bnQgZm9yIHRoZSBwb3B1bGF0aW9uIHN0cnVjdHVyZS4KCmBgYHtyfQpsaWJyYXJ5KHZjZlIpCmxpYnJhcnkoZGFydFIpCnZjZi5lYnYgPC0gcmVhZC52Y2ZSKCJ+L0RvY3VtZW50cy9FQlYvb3VyYmF0Y2gyL1NlY29uZHJvdW5kL1NOUC1kZXRlY3RfMDIuMjcuMjAyMC9teV9JQ2VkX215X2VkaXRlZF9zZXF1ZW5jZS5hbG4uSURyZXBsYWNlZC5Pbmx5SW5kaXZpZHVhbHMtTWludXNDZWxsTGluZXNfc3ViX21vZGlmaWVkX2ZpbHRlcmVkLnZjZiIpCmdsIDwtIHZjZlIyZ2VubGlnaHQodmNmLmVidikKCiNkbyBQQ0EKcGMgPC0gZ2wucGNvYShnbCwgbmZhY3RvcnMgPSAzKQoKI0NyZWF0ZSBhIHBoZXR5cGUgZmlsZSBmb3IgR1dBUyBhbmFseXNpczoKcG9wcyA8LSByZWFkLmRlbGltKCJ+L0Ryb3Bib3gvY29kZXMvVmlyYWxHZW5vbWVBc3NlbWJseS93b3Jrc3BhY2UvZGF0YS9wb3BfaW5mby50eHQiLHJvdy5uYW1lcyA9IDEsIGhlYWRlciA9IFQpCnN1bW1hcnkocG9wcykKcG9wIDwtIHJlYWQuZGVsaW0oIn4vRHJvcGJveC9jb2Rlcy9WaXJhbEdlbm9tZUFzc2VtYmx5L3dvcmtzcGFjZS9wb3AucGhlLmRhdGEudHh0IixoZWFkZXI9VFJVRSwgcm93Lm5hbWVzID0gMSkKc2FtcGxlRGVtbyA8LSBjYmluZChwb3AsIHBjJHNjb3Jlc1tyb3duYW1lcyhwb3ApLF0sIGRhdGEuZnJhbWUoTWV0aG9kPWdzdWIoIiAiLHJlcGxhY2VtZW50ID0gIi0iLHBvcHNbcm93bmFtZXMocG9wKSwiTWV0aG9kIl0pKSkKc2FtcGxlRGVtbyRNZXRob2QgPC0gaWZlbHNlKHNhbXBsZURlbW8kTWV0aG9kID09ICJEaXJlY3QtU2VxdWVuY2luZyIsIDEsIGFzLmNoYXJhY3RlcihzYW1wbGVEZW1vJE1ldGhvZCkpCnNhbXBsZURlbW8kTWV0aG9kIDwtIGlmZWxzZShzYW1wbGVEZW1vJE1ldGhvZCA9PSAiUHJlYW1wLXNXR0EiLCAyLCBhcy5jaGFyYWN0ZXIoc2FtcGxlRGVtbyRNZXRob2QpKQpzYW1wbGVEZW1vJE1ldGhvZCA8LSBpZmVsc2Uoc2FtcGxlRGVtbyRNZXRob2QgPT0gIkdlbm9taVBoaS1XR0EiLCAzLCBhcy5jaGFyYWN0ZXIoc2FtcGxlRGVtbyRNZXRob2QpKQpzYW1wbGVEZW1vJFR5cGUgPC0gaWZlbHNlKHNhbXBsZURlbW8kVHlwZSA9PSAzLCAyLCBhcy5mYWN0b3Ioc2FtcGxlRGVtbyRUeXBlKSkKc2FtcGxlRGVtbyRQaGUgPC0gYXMuZmFjdG9yKHNhbXBsZURlbW8kUGhlKQpzYW1wbGVEZW1vJFR5cGUgPC0gYXMuZmFjdG9yKHNhbXBsZURlbW8kVHlwZSkKCndyaXRlLnRhYmxlKHNhbXBsZURlbW8sIGZpbGU9In4vRHJvcGJveC9jb2Rlcy9WaXJhbEdlbm9tZUFzc2VtYmx5L3dvcmtzcGFjZS9wb3AucGhlLmRhdGEud2l0aFBDcy50eHQiLHF1b3RlID0gRixjb2wubmFtZXMgPSBOQSxzZXAgPSAiXHQiICkKYGBgCgoKYGBge2Jhc2ggZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KI0hlYWRlciBmb3IgdGhlIHBvcC5waGUgZmlsZSBvZiBwc2VxOgojRmlyc3QsIGFkZCAjSUQgdG8gdGhlIGZpcnN0IGNvbHVtbiBoZWFkZXIgd2l0aCBWaS4gVGhlbiwgYWRkIHRoZSBoZWFkZXIgYmVsb3cuCmNwIH4vRHJvcGJveC9jb2Rlcy9WaXJhbEdlbm9tZUFzc2VtYmx5L3dvcmtzcGFjZS9wb3AucGhlLmRhdGEud2l0aFBDcy50eHQgLi8KCnZpIHBvcC5waGUuZGF0YS53aXRoUENzLnR4dCAjdG8gYWRkICNJRCB0byB0aGUgZmlyc3QgY29sdW1uIGhlYWRlciBBTkQgbGluZXMgYmVsb3c6CgojI1BoZSxJbnRlZ2VyLDAsIjEvMj1lQkxzL0NvbnRyb2xzIgojI1R5cGUsSW50ZWdlciwwLDEvMi8zPVR5cGUxL1R5cGUyL0ludGVyLXR5cGljIgojI09yaWdpbixJbnRlZ2VyLDAsIjEvMi8zLzQ9ZUJMX0NlbGxfTGluZS9IZWFsdGh5Q29udHJvbC9lQkxfVHVtb3IvZUJMX1BsYXNtYSIKIyNBZ2UsRmxvYXQsLTksIkFnZSBpbiB5ZWFycyIKIyNHZW5kZXIsU3RyaW5nLD8sIk0vRj1NYWxlL0ZlbWFsZSIKIyNBZ2VfaXNMZXNzVGhhbjcsSW50ZWdlciwtOSwiMS8wPWlzQWdlTGVzc1RoYW43IgojI0dlbmRlcl9pc01hbGUsSW50ZWdlciwtOSwiMS8wPU1hbGUvRmVtYWxlIgojI1BDMSxGbG9hdCwiUEMxIgojI1BDMixGbG9hdCwiUEMyIgojI1BDMyxGbG9hdCwiUEMzIgojI01ldGhvZCxJbnRlZ2VyLC05LCIxLzIvMz1EaXJlY3QtU2VxdWVuY2luZy9tbHJQQ1Itc1dHQS9HZW5vbWlQaGktV0dBIgpgYGAKCiMjIyBHZW5lcmF0ZSBhIGdlbmV0aWMgcmVsYXRlZG5lc3MgbWF0cml4IChHUk0pIGZvciBFQlYgR2Vub21lczoKCkkgdXNlZCBHRU1NQSBmb3IgdGhpczoKCmBgYHtiYXNofQojcGxpbmsgZ2V0cyBjb25mdXNlZCB3aGVuIElEcyBjb250YWluIHVuZGVyc2NvcmUsICdfJwpzZWQgJ3MvXy8tL2cnIG15X0lDZWRfbXlfZWRpdGVkX3NlcXVlbmNlLmFsbi5JRHJlcGxhY2VkLk9ubHlJbmRpdmlkdWFscy1NaW51c0NlbGxMaW5lc19zdWJfbW9kaWZpZWRfZmlsdGVyZWQudmNmID4gbXlfSUNlZF9teV9lZGl0ZWRfc2VxdWVuY2UuYWxuLklEcmVwbGFjZWQuT25seUluZGl2aWR1YWxzLU1pbnVzQ2VsbExpbmVzX3N1Yl9tb2RpZmllZF9maWx0ZXJlZC5fLmZpeGVkLnZjZgoKI0ZpcnN0IGNyZWF0ZSBmaWxlIGZvcm1hdHMgdGhhdCBHRU1NQSBjYW4gdGFrZToKI3BsaW5rIC0tdmNmIG15X0lDZWRfbXlfZWRpdGVkX3NlcXVlbmNlLmFsbi5JRHJlcGxhY2VkLk9ubHlJbmRpdmlkdWFscy1NaW51c0NlbGxMaW5lc19zdWJfbW9kaWZpZWRfZmlsdGVyZWQuXy5maXhlZC52Y2YgLS1hbGxvdy1leHRyYS1jaHIgLS1vdXQgbXkucGxpbmsucGVkLmRhdGEgLS1tYWtlLWJlZApwbGluayAtLXZjZiBteV9JQ2VkX215X2VkaXRlZF9zZXF1ZW5jZS5hbG4uSURyZXBsYWNlZC5Pbmx5SW5kaXZpZHVhbHMtTWludXNDZWxsTGluZXNfc3ViX21vZGlmaWVkX2ZpbHRlcmVkLnZjZiAtLWFsbG93LWV4dHJhLWNociAtLW91dCBteS5wbGluay5wZWQuZGF0YSAtLW1ha2UtYmVkCiNUaGlzIGNyZWF0ZXMgZmlsZXMgbXkucGxpbmsucGVkLmRhdGEuYmVkIG15LnBsaW5rLnBlZC5kYXRhLmJpbSBteS5wbGluay5wZWQuZGF0YS5mYW0KCiNDcmVhdGUgYSBjdXN0b20gZmFtIGZpbGUgd2l0aCBwaGVubyBpbmZvOgpncmVwIC12ICIjIyIgcG9wLnBoZS5kYXRhLndpdGhQQ3MudHh0fGN1dCAtZjEsMiw2fGF3ayAne3ByaW50ICQxIlx0IiQxIlx0IjAiXHQiMCJcdCIkMyJcdCIkMn0nfGF3ayAne2lmKCQ1ID09IE0pIHByaW50ICQwIlx0IjE7IGVsc2UgcHJpbnQgJDAiXHQiMn0nfGF3ayAne2lmKCQ2ID09IDIpIHByaW50ICQwIlx0IjA7IGVsc2UgcHJpbnQgJDAiXHQiMX0nfGN1dCAtZjEtNCw3LXxncmVwIC12ICIjInx0ciAnXHQnICcgJyA+IG15LnBsaW5rLnBlZC5kYXRhLmZhbQoKZ2VtbWEgLWJmaWxlIG15LnBsaW5rLnBlZC5kYXRhIC1nayAxIC1vIEdSTS5lYnYKZ2VtbWEgLWJmaWxlIG15LnBsaW5rLnBlZC5kYXRhIC1nayAyIC1vIEdSTS5lYnYKI0dFTU1BIDAuOTguMSAoMjAxOC0xMi0xMCkgYnkgWGlhbmcgWmhvdSBhbmQgdGVhbSAoQykgMjAxMi0yMDE4CiNSZWFkaW5nIEZpbGVzIC4uLgojIyBudW1iZXIgb2YgdG90YWwgaW5kaXZpZHVhbHMgPSA5OAojIyBudW1iZXIgb2YgYW5hbHl6ZWQgaW5kaXZpZHVhbHMgPSA5OAojIyBudW1iZXIgb2YgY292YXJpYXRlcyA9IDEKIyMgbnVtYmVyIG9mIHBoZW5vdHlwZXMgPSAxCiMjIG51bWJlciBvZiB0b3RhbCBTTlBzL3ZhciAgICAgICAgPSAgICAgNjc2NAojIyBudW1iZXIgb2YgYW5hbHl6ZWQgU05QcyAgICAgICAgID0gICAgICA1MTEKI0NhbGN1bGF0aW5nIFJlbGF0ZWRuZXNzIE1hdHJpeCAuLi4KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IDEwMCUKIyoqKiogSU5GTzogRG9uZS4KI1RoaXMgcHJvY2VzcyBjcmVhdGVkIGEgZm9sZGVyICdvdXRwdXQnIHdpdGggZmlsZSAnR1JNLmVidi5jWFgudHh0JyBpbiBpdC4KCiNDb3B5IGZpbGVzIGZvciBnbG1tLnNjb3JlOgpjcCBteS5wbGluay5wZWQuZGF0YS4qIC91c3IvbG9jYWwvbGliL1IvMy41L3NpdGUtbGlicmFyeS9HTU1BVC9leHRkYXRhLwpgYGAKCgojIyMgR2Vub21lLXdpZGUgYXNzb2NpYXRpb24gd2l0aCBHTU1BVApUaGlzIHBhcnQgaXMgdGhlIGFjdHVhbCBHV0FTIHVzaW5nIGdlbmVyYWxpemVkIG1peGVkIG1vZGVsIHdpdGggR1JNIG9mIEVCViBhcyB0aGUgcmFuZG9tIGVmZmVjdCBhbmQgQWdlLCBHZW5kZXIsIEVCViB0eXBlLCBhbmQgUEMzIGFzIHRoZSBmaXhlZCBlZmZlY3RzLgoKSW4gdGhlIHRlc3QsIEkgbWFzayAobm90IHRlc3QpIHRoZSB2YXJpYW50IGxvY2kgd2l0aCBsZXNzIHRoYW4gNSUgbWlub3IgYWxsZWxlIGZyZXF1ZW5jeSBhbmQgbW9yZSB0aGFuIDUwJSBtaXNzaW5nIGRhdGEuIFRoaXMgZ2l2ZXMgdXMgMiw4MDcgdmFyaWFudCBsb2NpIHRvIGJlIHRlc3RlZC4KCmBgYHtyfQpsaWJyYXJ5KEdNTUFUKQpzYW1wbGVEZW1vJGlkIDwtIHJvd25hbWVzKHNhbXBsZURlbW8pCgpHUk0uZWJ2IDwtIGFzLm1hdHJpeChyZWFkLnRhYmxlKCJ+L0RvY3VtZW50cy9FQlYvb3VyYmF0Y2gyL1NlY29uZHJvdW5kL1NOUC1kZXRlY3RfMDIuMjcuMjAyMC9vdXRwdXQvR1JNLmVidi5jWFgudHh0IiwgY2hlY2submFtZXMgPSBGQUxTRSkpCnJvd25hbWVzKEdSTS5lYnYpIDwtIHNhbXBsZURlbW8kaWQKY29sbmFtZXMoR1JNLmVidikgPC0gc2FtcGxlRGVtbyRpZAojcGhlYXRtYXA6OnBoZWF0bWFwKEdSTS5lYnYsIGNsdXN0ZXJfcm93cyA9IEYsIGNsdXN0ZXJfY29scyA9IEYsIGFubm90YXRpb25fY29sID0gc2FtcGxlRGVtb1ssYygiVHlwZSIsIkdlbmRlciIsIkFnZSIsIk1ldGhvZCIpXSkKCmdlbm8uZmlsZSA8LSBzdHJzcGxpdChzeXN0ZW0uZmlsZSgiZXh0ZGF0YSIsICJteS5wbGluay5wZWQuZGF0YS5iZWQiLCBwYWNrYWdlID0gIkdNTUFUIiksICIuYmVkIiwgZml4ZWQgPSBUUlVFKVtbMV1dCgptb2RlbDAgPC0gZ2xtbWtpbihQaGUgfiBUeXBlICsgQWdlICsgR2VuZGVyICsgUEMzLCBkYXRhID0gc2FtcGxlRGVtbywga2lucyA9IEdSTS5lYnYsIGlkID0gImlkIiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpKQoKZ2xtbS5zY29yZShtb2RlbDAsIAogICAgICAgICAgIG1pc3NpbmcubWV0aG9kID0gIm9taXQiLCAKICAgICAgICAgICBpbmZpbGUgPSBnZW5vLmZpbGUsCiAgICAgICAgICAgTUFGLnJhbmdlID0gYygwLjA1LCAwLjUpLAogICAgICAgICAgIG1pc3MuY3V0b2ZmID0gMC41LAogICAgICAgICAgIG91dGZpbGUgPSAiZ2xtbS5zY29yZS5nZHMudGVzdG91dGZpbGUudHh0IikKCnNjb3JlLnJlc3VsdHMgPC0gcmVhZC5kZWxpbSgiZ2xtbS5zY29yZS5nZHMudGVzdG91dGZpbGUudHh0IiwgaGVhZGVyPVQpCgpgYGAKCiMjIyBEZXRlcm1pbmUgdGhlIGdlbm9tZS13aWRlIHNpZ25pZmljYW5jZSB0aHJlc2hvbGQ6CkhlcmUsIEkgZGV0ZXJtaW5lIHRoZSBnZW5vbWUtd2lkZSBzaWduaWZpY2FuY2UgdGhyZXNob2xkIHZpYSBwaGVub3R5cGUgKEJML2hlYWx0aHkgY29udHJvbCkgbGFiZWwgcGVybXV0YXRpb25zICgxLDAwMCB0aW1lcykuIFRoaXMgcmVzdWx0ZWQgaW4gYSBzdWdnZXN0aXZlIHNpZ25pZmljYW5jZSB0aHJlc2hvbGQgb2YgMC4wMDA5OTk5NTIgfj0gMTBeLTMuCgpgYGB7cn0KClAucG9vbCA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IHJvd25hbWVzKHNjb3JlLnJlc3VsdHMpKQpmb3IoIGkgaW4gMToxMDAwKXsKICBwcmludChpKQojUGVybXV0aW5nIHRoZSBwaGVub3R5cGUgb2YgaW50ZXJlc3QKc2FtcGxlRGVtby5yYW5kIDwtIHNhbXBsZURlbW8Kc2FtcGxlRGVtby5yYW5kJFBoZSA8LSBzYW1wbGUoc2FtcGxlRGVtbyRQaGUsIHJlcGxhY2UgPSBUKQptb2RlbC5yYW5kIDwtIGdsbW1raW4oUGhlIH4gVHlwZSArIEFnZSArIEdlbmRlciArIFBDMywgZGF0YSA9IHNhbXBsZURlbW8ucmFuZCwga2lucyA9IEdSTS5lYnYsIGlkID0gImlkIiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpKQoKZ2xtbS5zY29yZShtb2RlbC5yYW5kLCAKICAgICAgICAgICBtaXNzaW5nLm1ldGhvZCA9ICJvbWl0IiwgCiAgICAgICAgICAgaW5maWxlID0gZ2Vuby5maWxlLAogICAgICAgICAgIE1BRi5yYW5nZSA9IGMoMC4wNSwgMC41KSwKICAgICAgICAgICBtaXNzLmN1dG9mZiA9IDAuNSwKICAgICAgICAgICBvdXRmaWxlID0gImdsbW0uc2NvcmUuUGhlLVBlcm11dGF0aW9uLnR4dCIpCgpzY29yZS5yZXN1bHRzLnJhbmQgPC0gcmVhZC5kZWxpbSgiZ2xtbS5zY29yZS5QaGUtUGVybXV0YXRpb24udHh0IiwgaGVhZGVyPVQpCgpQLnBvb2wgPC0gY2JpbmQoUC5wb29sLCBQPXNjb3JlLnJlc3VsdHMucmFuZCRQVkFMKQp9CgpwbGlzdCA8LSBoZWFkKHNvcnQoYXBwbHkoUC5wb29sLCAxLCBtaW4pKSwgZGltKFAucG9vbClbMV0qNS8xMDApCnBsaXN0W2xlbmd0aChwbGlzdCldIzAuMDAwOTk5OTUyCi1sb2cxMChwbGlzdFtsZW5ndGgocGxpc3QpXSkKd3JpdGUuY3N2KFAucG9vbCwgZmlsZSA9ICJQLnBvb2wudHh0IikKYGBgCgojIyMgVGhlIE1hbmhhdHRhbiBwbG90IG9mIHRoZSByZXN1bHRzOgoKVGhlIHN1Z2dlc3RpdmUgZ2Vub21lLXdpZGUgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCBvZiB+MyAoaW4gLWxvZzEwKSByZXN1bHRzIGluIE5vIHNpZ25pZmljYW50IHZhcmlhbnQgaW4gdGhlIGFuYWx5c2lzLiBQbGVhc2Ugc2VlIHRoZSBwbG90IGJlbG93OgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQoKaGVhZChzY29yZS5yZXN1bHRzKQpzY29yZS5yZXN1bHRzJFBWQUwgPC0gaWZlbHNlKGlzLm5hKHNjb3JlLnJlc3VsdHMkUFZBTCksIDEuMCwgYXMubnVtZXJpYyhzY29yZS5yZXN1bHRzJFBWQUwpKQoKZ2Vub21lLndpZGUuc2lnbmlmaW5hbmNlIDwtIHBsaXN0W2xlbmd0aChwbGlzdCldCnNjb3JlLnJlc3VsdHMuc2lnIDwtIHNjb3JlLnJlc3VsdHNbIHdoaWNoKHNjb3JlLnJlc3VsdHMkUFZBTCA8IGdlbm9tZS53aWRlLnNpZ25pZmluYW5jZSksXSRQT1MKCnAxIDwtIGdncGxvdChzY29yZS5yZXN1bHRzLCBhZXMoeD1QT1MvMTAwMCwgeT0tbG9nMTAoUFZBTCkpKSsgZ2VvbV9wb2ludChzaXplPTQsIGNvbG9yPSJncmV5IikrCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0gYXMubnVtZXJpYygtbG9nMTAoZ2Vub21lLndpZGUuc2lnbmlmaW5hbmNlKSkpLGNvbG91ciA9ICJyZWQiLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZSA9IDEpICsgdGhlbWVfYncoKSsKICBnZW9tX3BvaW50KGRhdGE9c2NvcmUucmVzdWx0c1sgLWxvZzEwKHNjb3JlLnJlc3VsdHMkUFZBTCswLjAwMDAwMDEpID4gLWxvZzEwKGdlbm9tZS53aWRlLnNpZ25pZmluYW5jZSksXSxhZXMoeD1QT1MvMTAwMCwgeT0tbG9nMTAoUFZBTCkpLHNpemU9NCwgY29sb3I9InJlZCIpKwogIHlsYWIoIi1sb2cxMCAoUCB2YWx1ZSkiKSsKICB4bGFiKCJHZW5vbWljIFBvc3Rpb24gKGtiKSIpKwogIHlsaW0oMCw1KSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIsZmFjZSA9ICJib2xkIiwgc2l6ZT0xOCksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIixmYWNlID0gImJvbGQiLHNpemU9MTgpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIsZmFjZSA9ICJib2xkIixzaXplPTIwKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siLGZhY2UgPSAiYm9sZCIsc2l6ZT0yMCkpCgpnZ3NhdmUocGxvdD1wMSx3aWR0aCA9IDE4LGhlaWdodCA9IDksIGRwaT0yMDAsIGZpbGVuYW1lPSIvVXNlcnMveWFzaW5rYXltYXovRHJvcGJveC9QYXBlcnMvRUJWX3Byb2plY3Qvd29ya3NwYWNlL0ZpZ3VyZV90ZW1wcy9hc3NvYzgucGRmIiwgdXNlRGluZ2JhdHM9RkFMU0UgKQoKCnJlc3VsdHMub3V0IDwtIHNjb3JlLnJlc3VsdHNbd2hpY2goIWlzLm5hKHNjb3JlLnJlc3VsdHMkUFZBTCkpLCFjb2xuYW1lcyhzY29yZS5yZXN1bHRzKSAlaW4lIGMoIlNOUCIsICJjTSIsICJWQVIiKV0KcmVzdWx0cy5vdXQgPC0gcmVzdWx0cy5vdXRbYygiQ0hSIiwgIlBPUyIsICJBMiIsICJBMSIsICJOIiwgIkFGIiwgIlNDT1JFIiwgIlBWQUwiKV0KCmNvbG5hbWVzKHJlc3VsdHMub3V0KVtjb2xuYW1lcyhyZXN1bHRzLm91dCkgPT0gJ0EyJ10gPC0gJ1JFRicKY29sbmFtZXMocmVzdWx0cy5vdXQpW2NvbG5hbWVzKHJlc3VsdHMub3V0KSA9PSAnQTEnXSA8LSAnQUxUJwoKd3JpdGUudGFibGUocmVzdWx0cy5vdXRbb3JkZXIocmVzdWx0cy5vdXQkUFZBTCksXSwgZmlsZT0ifi9Ecm9wYm94L1BhcGVycy9FQlZfcHJvamVjdC93b3Jrc3BhY2UvZGF0YS9HV0FTX0dMTU1fcmVzdWx0cy5BbGwudHh0IixzZXA9Ilx0IixxdW90ZSA9IEZBTFNFLHJvdy5uYW1lcyA9IEZBTFNFKQoKCiBnZ3Bsb3Qoc2NvcmUucmVzdWx0cywgYWVzKHg9UE9TLzEwMDAsIHk9LWxvZzEwKFBWQUwpKSkrIGdlb21fcG9pbnQoc2l6ZT0yLCBjb2xvcj0iZ3JleSIpKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9IGFzLm51bWVyaWMoLWxvZzEwKGdlbm9tZS53aWRlLnNpZ25pZmluYW5jZSkpKSxjb2xvdXIgPSAicmVkIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemUgPSAxKSArIHRoZW1lX2J3KCkrCiAgZ2VvbV9wb2ludChkYXRhPXNjb3JlLnJlc3VsdHNbIC1sb2cxMChzY29yZS5yZXN1bHRzJFBWQUwrMC4wMDAwMDAxKSA+IC1sb2cxMChnZW5vbWUud2lkZS5zaWduaWZpbmFuY2UpLF0sYWVzKHg9UE9TLzEwMDAsIHk9LWxvZzEwKFBWQUwpKSxzaXplPTIsIGNvbG9yPSJyZWQiKSsKICB5bGFiKCItbG9nMTAgKFAgdmFsdWUpIikrCiAgeGxhYigiR2Vub21pYyBQb3N0aW9uIChrYikiKSsKICB5bGltKDAsNSkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siLGZhY2UgPSAiYm9sZCIsIHNpemU9MTgpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIsZmFjZSA9ICJib2xkIixzaXplPTE4KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siLGZhY2UgPSAiYm9sZCIsc2l6ZT0yMCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIixmYWNlID0gImJvbGQiLHNpemU9MjApKQoKYGBgCg==