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  

Generate a genetic relatedness matrix (GRM) for EBV Genomes:

I used GEMMA for this:

#plink gets confused when IDs contain underscore, '_'
sed 's/_/-/g' my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub_modified_filtered.vcf > my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub_modified_filtered._.fixed.vcf

#First create file formats that GEMMA can take:
#plink --vcf my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub_modified_filtered._.fixed.vcf --allow-extra-chr --out my.plink.ped.data --make-bed
plink --vcf my_ICed_my_edited_sequence.aln.IDreplaced.OnlyIndividuals-MinusCellLines_sub_modified_filtered.vcf --allow-extra-chr --out my.plink.ped.data --make-bed
#This creates files my.plink.ped.data.bed my.plink.ped.data.bim my.plink.ped.data.fam

#Create a custom fam file with pheno info:
grep -v "##" pop.phe.data.withPCs.txt|cut -f1,2,6|awk '{print $1"\t"$1"\t"0"\t"0"\t"$3"\t"$2}'|awk '{if($5 == M) print $0"\t"1; else print $0"\t"2}'|awk '{if($6 == 2) print $0"\t"0; else print $0"\t"1}'|cut -f1-4,7-|grep -v "#"|tr '\t' ' ' > my.plink.ped.data.fam

gemma -bfile my.plink.ped.data -gk 1 -o GRM.ebv
gemma -bfile my.plink.ped.data -gk 2 -o GRM.ebv
#GEMMA 0.98.1 (2018-12-10) by Xiang Zhou and team (C) 2012-2018
#Reading Files ...
## number of total individuals = 98
## number of analyzed individuals = 98
## number of covariates = 1
## number of phenotypes = 1
## number of total SNPs/var        =     6764
## number of analyzed SNPs         =      511
#Calculating Relatedness Matrix ...
#================================================== 100%
#**** INFO: Done.
#This process created a folder 'output' with file 'GRM.ebv.cXX.txt' in it.

#Copy files for glmm.score:
cp my.plink.ped.data.* /usr/local/lib/R/3.5/site-library/GMMAT/extdata/

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==