- Repeat questions 5 and 7 from Part 1 of the term project, except using the command-line version of hmmer.
#First, I changed my directory to make sure I am pulling from and saving to the right folder. Then...
phmmer Human_PUSL1.fasta uniprot_sprot.fasta
/var/folders/pz/rk934mt528g4zlchvtw8tty80000gn/T/Rtmpjzmj9M/chunk-code1186e391cb817.: line 3: phmmer: command not found
For Q5 of the midterm, I used HMMER in R and BLAST to find the best matches to my assigned gene. With R, I got a bacterial match with an E-value of 3.6e-24. With BLAST, my top match was a human one with an E-value of 0. With command-line, my top match is a human one with an E-value of 8.5e-203 and my second match is a mouse one with an E-value of 4.1e-153. Quite the contrast because, with BLAST, my mouse results didn’t even show up in the first 100. Please see accompanying figure 1.
phmmer Mouse_PUSL1.fasta uniprot_sprot.fasta
/var/folders/pz/rk934mt528g4zlchvtw8tty80000gn/T/Rtmpjzmj9M/chunk-code1186e207bb0fa.: line 1: phmmer: command not found
Unfortunately, on the midterm, I did not properly complete the HMMER and BLAST steps for the mouse gene so lost marks as a result. To complete the comparison between command-line and BLAST, I conducted a BLAST search for it for the final. I have found that the top, not only 2, but 5 results are mouse hits with E-values of 0. With command-line, however, the top hit is a mouse one with an E-value of 2.9e-195 and the second hit is a human one with an E-value of 4.4e-153. Please see accompanying figure 2.
For Q7 of the midterm, I used R to build the MSA and profile HMM for the given fly protein. Here, I used command-line. The portions done in clustalw are included as screenshots. Please refer to accompanying figures 3-12.
hmmbuild fly_protein.hmm fly_protein_new
hmmsearch fly_protein.hmm uniprot_sprot.fasta
/var/folders/pz/rk934mt528g4zlchvtw8tty80000gn/T/Rtmpjzmj9M/chunk-code1186e2fcc133a.: line 1: hmmbuild: command not found
/var/folders/pz/rk934mt528g4zlchvtw8tty80000gn/T/Rtmpjzmj9M/chunk-code1186e2fcc133a.: line 2: hmmsearch: command not found
The most significant human hit is ZMAT3_HUMAN (Q9HA38, Zinc finger matrin-type protein 3 O) with an E-value of 4.6e-12. Please see accompanying figure 13.
#Adding all libraries for the R section of the project.
library("HMM")
library(seqinr)
library("ape")
library(Biostrings)
library(phangorn)
library("bio3d")
library("msa")
- The HMM model for 5’ splice site detection we looked at in class was a “toy” HMM model to use for splice site detection that would not be expected to perform well: it only used the information that the first base of an intron is likely to be a G, and the emission probabilities were not empirically derived. It is known that the full motif for U2 (major class) introns in pre-mRNA has the following 5’ splice site consensus sequence MAG|GTRAGT (using an ambiguity code, where | is the exon-intron boundary), and so including additional upstream and downstream base states could also improve the model (). Improve the model given in class to use the information (i.e. add states for) for two upstream and two downstream bases, and use the following empirically derived exon and intron emission probabilities. Exon base frequencies: A=0.20,C=0.30,G=0.30,T=0.20. Intron base frequencies: A=0.15,C=0.35,G=0.35,T=0.15 Motif base 1: A=0.997,C=0.001,G=0.001,T=0.001, Motif base 2: A=0.001,C=0.001,G=0.997,T=0.001, Motif base 3: A=0.001,C=0.001,G=0.997,T=0.001, Motif base 4: A=0.001,C=0.001,G=0.001,T=0.997, Use the hmm() R package to define an improved 5’ exon-intron junction detector using this information. Then use the UCSC genome browser to extract the human hg38 DNA sequence around the final exon-intron splice site for your assigned human gene (50 bp upstream and downstream); and also extract the following genomic region chr2:85,539,313-85,539,468 (on the + strand). Now try to detect the exon-intron boundary using your improved HMM and compare with the previous HMM given in class for both sequences. Compare with the gencode gene annotation in the UCSC browser- was the correct splice site location detected in the two sequences?
#My partner for this question is Zaina Atieh.
#My New Junction Detector
TheUnitedStates = c("Exon", "toA","toG1","toG2", "toT","Intron")
StarsAndStripes = c("A","C","G","T")
transProbs = matrix(c('E_toE'=0.9,'E_toA'=0.1, 'E_toG1'= 0, 'E_toG2'= 0, 'E_toT'= 0,'E_toI'=0, 'A_toE'=0,'A_toA'=0, 'A_toG1'=1.0, 'A_toG2'=0, 'A_toT'=0, 'A_toI'=0, 'G1_toE'=0,'G1_toA'=0,'G1_toG1'=0,'G1_toG2'=1.0,'G1_toT'=0,'G1_toI'=0,'G2_toE'=0,'G2_toA'=0,'G2_toG1'=0,'G2_toG2'=0,'G2_toT'=1.0,'G2_toI'=0,'T_toE'=0,'T_toA'=0,'T_toG1'=0,'T_toG2'=0,'T_toT'=0,'T_toI'=1.0, 'I_toE'=0, 'I_toA'=0,'I_toG1'=0,'I_toG2'=0,'I_toT'=0, 'I_toI'=1.0), c(length(TheUnitedStates), length(TheUnitedStates)), byrow = TRUE)
transProbs
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0.9 0.1 0 0 0 0
[2,] 0.0 0.0 1 0 0 0
[3,] 0.0 0.0 0 1 0 0
[4,] 0.0 0.0 0 0 1 0
[5,] 0.0 0.0 0 0 0 1
[6,] 0.0 0.0 0 0 0 1
emissionProbs = matrix(c('A'=0.20,'C'=0.30,'G'=0.30,'T'=0.20, 'A'=0.997,'C'=0.001,'G'=0.001,'T'=0.001,'A'=0.001,'C'=0.001,'G'=0.997,'T'=0.001,'A'=0.001,'C'=0.001,'G'=0.997,'T'=0.001,'A'=0.001,'C'=0.001,'G'=0.001,'T'=0.997,'A'=0.15,'C'=0.35,'G'=0.35,'T'=0.15), c(length(TheUnitedStates), length(StarsAndStripes)), byrow = TRUE)
emissionProbs
[,1] [,2] [,3] [,4]
[1,] 0.200 0.300 0.300 0.200
[2,] 0.997 0.001 0.001 0.001
[3,] 0.001 0.001 0.997 0.001
[4,] 0.001 0.001 0.997 0.001
[5,] 0.001 0.001 0.001 0.997
[6,] 0.150 0.350 0.350 0.150
hmm <- initHMM(TheUnitedStates, StarsAndStripes, startProbs = c(1,0,0,0,0,0), transProbs = transProbs, emissionProbs = emissionProbs)
#Class Junction Detector
ParkerStates = c("Exon", "5site", "Intron")
ParkerSymbols = c("A","C","G","T")
ParkertransProbs = matrix(c('EE'=0.9,'E5'=0.1,'EI'=0, '5E'=0, '55'=0, '5I'=1.0, 'IE'=0, 'I5'=0, 'II'=1.0), c(length(ParkerStates), length(ParkerStates)), byrow = TRUE)
ParkertransProbs
[,1] [,2] [,3]
[1,] 0.9 0.1 0
[2,] 0.0 0.0 1
[3,] 0.0 0.0 1
ParkeremissionProbs = matrix(c('A'=0.25,'C'=0.25,'G'=0.25,'T'=0.25, 'A'=0.05,'C'=0.0,'G'=0.95,'T'=0.0, 'A'=0.4,'C'=0.1,'G'=0.1,'T'=0.4), c(length(ParkerStates), length(ParkerSymbols)), byrow = TRUE)
ParkeremissionProbs
[,1] [,2] [,3] [,4]
[1,] 0.25 0.25 0.25 0.25
[2,] 0.05 0.00 0.95 0.00
[3,] 0.40 0.10 0.10 0.40
Parkerhmm <- initHMM(ParkerStates, ParkerSymbols, startProbs = c(1,0,0), transProbs = ParkertransProbs, emissionProbs = ParkeremissionProbs)
#PUSL1 Human
BaldEagle <- s2c('AGCCCCAGCCCACGGCTTATTCCTCAAGTCAGTGCTGTACGGGAACCTCGgtaagaaaaacaggcacgagaagctcctgtcatgtgcccagtgactactg')
BaldEagle <- toupper(BaldEagle)
vitBaldEagle <- viterbi(hmm, BaldEagle)
vitBaldEagle
[1] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[13] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[25] "Exon" "toA" "toG1" "toG2" "toT" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[37] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[49] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[61] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[73] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[85] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[97] "Intron" "Intron" "Intron" "Intron"
ParkervitBaldEagle <- viterbi(Parkerhmm, BaldEagle)
ParkervitBaldEagle
[1] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[17] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[33] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[49] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[65] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[81] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[97] "Exon" "Exon" "Exon" "Exon"
#chr2:85,539,313-85,539,468
NorthAmericanBison <- s2c('ACGAGGCGTTCATCGAGGAGGGCACATTCCTTTTCACCTCAGAGTCGGTCGGGGAAGGCCACCCAGGTGAGGGGACGGCCTGAAGCGAAGCGTGGGGCGGGGCAGAAGGCAGCGCCAAGGTCCGGCTGGCTGCGGCCGGCCGGTGGTGGGGCCCGC')
vitNorthAmericanBison <- viterbi(hmm, NorthAmericanBison)
vitNorthAmericanBison
[1] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[13] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[25] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[37] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[49] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[61] "Exon" "Exon" "Exon" "Exon" "toA" "toG1" "toG2" "toT" "Intron" "Intron" "Intron" "Intron"
[73] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[85] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[97] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[109] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[121] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[133] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
[145] "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron" "Intron"
ParkervitNorthAmericanBison <- viterbi(Parkerhmm, NorthAmericanBison)
ParkervitNorthAmericanBison
[1] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[17] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[33] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[49] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[65] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[81] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[97] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[113] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[129] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
[145] "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon" "Exon"
As expected, the improved junction detector did return a splice site while the previous junction detector we used in class did not. This occurred in both the sequence for the PUSL1 Human gene assigned to me as well as the sequence at chr2:85,539,313-85,539,468. In the latter, the improved detector picked up on the exact splice site found in the UCSC genome browser. However, in the former, with my own gene, the detector picked up something about 25 bases upstream of the actual splice site seen in the browser.
- In this question you will examine a simple toy phylogenetic tree, and associated MSA, similar to the one used as a maximum likelihood example in lectures. In the file toy_MSA.fasta is defined a (very simple) multiple sequence alignment (MSA) of a region of DNA of length 1 across four primate species. In the file toy_tree.tre is defined a potential phylogenetic tree in newick format for which we want to determine its fit to the MSA. Read in the tree (using read.tree() in R) and also read in the MSA. Display the unrooted tree. Assume that in this simple (unrealistic) example all tree branches have the same length t, and assume base composition is equal for all bases. Compute the log likelihood of the tree by hand, using the Jukes-Cantor evolutionary model and for parameter values 𝛼t = 0.09, 0.103, and 0.12. Which value of 𝛼t shows the maximum likelihood? Show your working. Then compute the log likelihood of the tree defined in toy_tree.tre using the R phangorn package and compare your results.
ChristmasTree <- read.tree("toy_tree.tre")
SantasToys = readDNAMultipleAlignment("toy_MSA.fasta", format="FASTA")
SantasToys <- as.phyDat(SantasToys)
plot(ChristmasTree, type="unrooted")

fit = pml(ChristmasTree, data=SantasToys, model="Jukes-Cantor")
fit
loglikelihood: -4.778555
unconstrained loglikelihood: 0
Rate matrix:
a c g t
a 0 1 1 1
c 1 0 1 1
g 1 1 0 1
t 1 1 1 0
Base frequencies:
0.25 0.25 0.25 0.25
logLik(fit)
'log Lik.' -4.778555 (df=5)
Reindeer<- function(a){
Rudolph<-(1+3*exp(-4*a))/4
Vixen<-(1-exp(-4*a))/4
Prancer<-(7*Vixen^5+2*Rudolph^3*Vixen^2+Rudolph^4*Vixen+4*Rudolph^2*Vixen^3+2*Rudolph*Vixen^4)/4
Blitzen<-log(Prancer)
return(Blitzen)
}
Reindeer(0.09)
[1] -4.78537
Reindeer(0.103)
[1] -4.778555
Reindeer(0.12)
[1] -4.787469
Of the three values, 0.103 shows the maximum likelihood which is -4.778555. The log likelihood is also computed using phangorn above the manual calculations. The result of this is also -4.778555.
- Using PFAM, extract the multiple sequence seed alignment for the most significant protein domain from your assigned human gene (if no known domain was found in your gene, use the piwi domain). Using phanghorn, compute the gene tree from this MSA using both neighbour- joining and maximum parsimony and maximum likelihood. Show the parsimony score and log likelihood of your maximum parsimony and maximum likelihood trees, respectively. Show your R code.
#Extract the multiple sequence seed alignment for the most significant protein domain from PFAM.
seedalign <- pfam("PseudoU_synth_1", alignment = "seed")
PseudoU <- as.phyDat(seedalign$ali, type="AA")
#phangorn part
#neighbor-joining
dm <- dist.ml(PseudoU)
treeNJ <- NJ(dm)
plot(treeNJ, "unrooted", main="NJ")

#maximum parsimony
treePars <- optim.parsimony(treeNJ, PseudoU,method = "sankoff")
Final p-score 11170 after 89 nni operations
plot(treePars, "unrooted", main="parsimony")

parsimony(treeNJ, PseudoU,method = "sankoff")
[1] 11337
The parsimony score is 11337.
#maximum likelihood
fitpars <- pml(treeNJ, data=PseudoU)
negative edges length changed to 0!
fitpars
loglikelihood: -59152.72
unconstrained loglikelihood: -1249.257
Rate matrix:
logLik(fitpars)
'log Lik.' -59152.72 (df=619)
The log likelihood is -59152.72.
plot(fitpars$tree)

- The SARS epidemic of 2003 was a viral respiratory disease caused by a mutation in a coronavirus. Various samples of the virus were sequenced as the virus mutated and spread throughout the world. It is also known that the SARS coronavirus is distantly related to the Himalayan Palm Civet coronavirus and so this can be used as an outgroup in our phylogenetic analysis. The sequences of a key protein in each of these samples are provided in the fasta file “sars.fasta”. Perform a phylogenetic analysis of the spread of the disease from these samples to determine the likely site of origin of the disease. Show a NJ phylogenetic tree as your evidence and give your arguments for (i) the site of origin, (ii) the next major site SARS spread to. You should use the phangorn package in R. Note that the root function can be used to set the root of the tree e.g. root(treeNJ, outgroup = “Himalayan palm civet sars cov, complete genome”) .
SARS <- read.phyDat("sars.fasta", type="DNA", format = "fasta")
SARSdm <- dist.ml(SARS)
treeNJ <- NJ(SARSdm)
treeNJroot <- root(treeNJ, outgroup = "Himalayan palm civet sars cov, complete genome", resolve.root=TRUE)
plot(treeNJroot, type="phylogram")

Based on this, we can deduce that the city of origin is Guangzhou in Guangdong. Depending on the definition of the next major site, Zhongshan is the next major city but still in Guangdong and Hong Kong is the next major region after Guangdong as a whole.
LS0tCnRpdGxlOiAiQmlvaW5mb3JtYXRpY3MgRmluYWwgUHJvamVjdCIKc3VidGl0bGU6ICJOdXB1ciBKb3NoaSAobmtqMjE5KSAtIEZhbGwgMjAxOSIgIApvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCjEuIFJlcGVhdCBxdWVzdGlvbnMgNSBhbmQgNyBmcm9tIFBhcnQgMSBvZiB0aGUgdGVybSBwcm9qZWN0LCBleGNlcHQgdXNpbmcgdGhlIGNvbW1hbmQtbGluZSB2ZXJzaW9uIG9mIGhtbWVyLgpgYGB7YmFzaH0KI0ZpcnN0LCBJIGNoYW5nZWQgbXkgZGlyZWN0b3J5IHRvIG1ha2Ugc3VyZSBJIGFtIHB1bGxpbmcgZnJvbSBhbmQgc2F2aW5nIHRvIHRoZSByaWdodCBmb2xkZXIuIFRoZW4uLi4KCnBobW1lciBIdW1hbl9QVVNMMS5mYXN0YSB1bmlwcm90X3Nwcm90LmZhc3RhCmBgYApGb3IgUTUgb2YgdGhlIG1pZHRlcm0sIEkgdXNlZCBITU1FUiBpbiBSIGFuZCBCTEFTVCB0byBmaW5kIHRoZSBiZXN0IG1hdGNoZXMgdG8gbXkgYXNzaWduZWQgZ2VuZS4gCldpdGggUiwgSSBnb3QgYSBiYWN0ZXJpYWwgbWF0Y2ggd2l0aCBhbiBFLXZhbHVlIG9mIDMuNmUtMjQuIFdpdGggQkxBU1QsIG15IHRvcCBtYXRjaCB3YXMgYSBodW1hbiBvbmUgd2l0aCBhbiBFLXZhbHVlIG9mIDAuCldpdGggY29tbWFuZC1saW5lLCBteSB0b3AgbWF0Y2ggaXMgYSBodW1hbiBvbmUgd2l0aCBhbiBFLXZhbHVlIG9mIDguNWUtMjAzIGFuZCBteSBzZWNvbmQgbWF0Y2ggaXMgYSBtb3VzZSBvbmUgd2l0aCBhbiBFLXZhbHVlIG9mIDQuMWUtMTUzLgpRdWl0ZSB0aGUgY29udHJhc3QgYmVjYXVzZSwgd2l0aCBCTEFTVCwgbXkgbW91c2UgcmVzdWx0cyBkaWRuJ3QgZXZlbiBzaG93IHVwIGluIHRoZSBmaXJzdCAxMDAuClBsZWFzZSBzZWUgYWNjb21wYW55aW5nIGZpZ3VyZSAxLgpgYGB7YmFzaH0KcGhtbWVyIE1vdXNlX1BVU0wxLmZhc3RhIHVuaXByb3Rfc3Byb3QuZmFzdGEKYGBgClVuZm9ydHVuYXRlbHksIG9uIHRoZSBtaWR0ZXJtLCBJIGRpZCBub3QgcHJvcGVybHkgY29tcGxldGUgdGhlIEhNTUVSIGFuZCBCTEFTVCBzdGVwcyBmb3IgdGhlIG1vdXNlIGdlbmUgc28gbG9zdCBtYXJrcyBhcyBhIHJlc3VsdC4KVG8gY29tcGxldGUgdGhlIGNvbXBhcmlzb24gYmV0d2VlbiBjb21tYW5kLWxpbmUgYW5kIEJMQVNULCBJIGNvbmR1Y3RlZCBhIEJMQVNUIHNlYXJjaCBmb3IgaXQgZm9yIHRoZSBmaW5hbC4gCkkgaGF2ZSBmb3VuZCB0aGF0IHRoZSB0b3AsIG5vdCBvbmx5IDIsIGJ1dCA1IHJlc3VsdHMgYXJlIG1vdXNlIGhpdHMgd2l0aCBFLXZhbHVlcyBvZiAwLiAKV2l0aCBjb21tYW5kLWxpbmUsIGhvd2V2ZXIsIHRoZSB0b3AgaGl0IGlzIGEgbW91c2Ugb25lIHdpdGggYW4gRS12YWx1ZSBvZiAyLjllLTE5NSBhbmQgdGhlIHNlY29uZCBoaXQgaXMgYSBodW1hbiBvbmUgd2l0aCBhbiBFLXZhbHVlIG9mIDQuNGUtMTUzLgpQbGVhc2Ugc2VlIGFjY29tcGFueWluZyBmaWd1cmUgMi4KCkZvciBRNyBvZiB0aGUgbWlkdGVybSwgSSB1c2VkIFIgdG8gYnVpbGQgdGhlIE1TQSBhbmQgcHJvZmlsZSBITU0gZm9yIHRoZSBnaXZlbiBmbHkgcHJvdGVpbi4gSGVyZSwgSSB1c2VkIGNvbW1hbmQtbGluZS4KVGhlIHBvcnRpb25zIGRvbmUgaW4gY2x1c3RhbHcgYXJlIGluY2x1ZGVkIGFzIHNjcmVlbnNob3RzLiBQbGVhc2UgcmVmZXIgdG8gYWNjb21wYW55aW5nIGZpZ3VyZXMgMy0xMi4KCmBgYHtiYXNofQpobW1idWlsZCBmbHlfcHJvdGVpbi5obW0gZmx5X3Byb3RlaW5fbmV3CmhtbXNlYXJjaCBmbHlfcHJvdGVpbi5obW0gdW5pcHJvdF9zcHJvdC5mYXN0YQpgYGAKClRoZSBtb3N0IHNpZ25pZmljYW50IGh1bWFuIGhpdCBpcyBaTUFUM19IVU1BTiAoUTlIQTM4LCBaaW5jIGZpbmdlciBtYXRyaW4tdHlwZSBwcm90ZWluIDMgTykgd2l0aCBhbiBFLXZhbHVlIG9mIDQuNmUtMTIuClBsZWFzZSBzZWUgYWNjb21wYW55aW5nIGZpZ3VyZSAxMy4KCmBgYHtyfQojQWRkaW5nIGFsbCBsaWJyYXJpZXMgZm9yIHRoZSBSIHNlY3Rpb24gb2YgdGhlIHByb2plY3QuCmxpYnJhcnkoIkhNTSIpCmxpYnJhcnkoc2VxaW5yKQpsaWJyYXJ5KCJhcGUiKQpsaWJyYXJ5KEJpb3N0cmluZ3MpCmxpYnJhcnkocGhhbmdvcm4pCmxpYnJhcnkoImJpbzNkIikKbGlicmFyeSgibXNhIikKYGBgCgoyLiBUaGUgSE1NIG1vZGVsIGZvciA14oCZIHNwbGljZSBzaXRlIGRldGVjdGlvbiB3ZSBsb29rZWQgYXQgaW4gY2xhc3Mgd2FzIGEg4oCcdG954oCdIEhNTSBtb2RlbCB0byB1c2UgZm9yIHNwbGljZSBzaXRlIGRldGVjdGlvbiB0aGF0IHdvdWxkIG5vdCBiZSBleHBlY3RlZCB0byBwZXJmb3JtIHdlbGw6IGl0IG9ubHkgdXNlZCB0aGUgaW5mb3JtYXRpb24gdGhhdCB0aGUgZmlyc3QgYmFzZSBvZiBhbiBpbnRyb24gaXMgbGlrZWx5IHRvIGJlIGEgRywgYW5kIHRoZSBlbWlzc2lvbiBwcm9iYWJpbGl0aWVzIHdlcmUgbm90IGVtcGlyaWNhbGx5IGRlcml2ZWQuCkl0IGlzIGtub3duIHRoYXQgdGhlIGZ1bGwgbW90aWYgZm9yIFUyIChtYWpvciBjbGFzcykgaW50cm9ucyBpbiBwcmUtbVJOQSBoYXMgdGhlIGZvbGxvd2luZyA1JyBzcGxpY2Ugc2l0ZSBjb25zZW5zdXMgc2VxdWVuY2UgTUFHfEdUUkFHVCAodXNpbmcgYW4gYW1iaWd1aXR5IGNvZGUsIHdoZXJlIHwgaXMgdGhlIGV4b24taW50cm9uIGJvdW5kYXJ5KSwgYW5kIHNvIGluY2x1ZGluZyBhZGRpdGlvbmFsIHVwc3RyZWFtIGFuZCBkb3duc3RyZWFtIGJhc2Ugc3RhdGVzIGNvdWxkIGFsc28gaW1wcm92ZSB0aGUgbW9kZWwgKCkuCkltcHJvdmUgdGhlIG1vZGVsIGdpdmVuIGluIGNsYXNzIHRvIHVzZSB0aGUgaW5mb3JtYXRpb24gKGkuZS4gYWRkIHN0YXRlcyBmb3IpIGZvciB0d28gdXBzdHJlYW0gYW5kIHR3byBkb3duc3RyZWFtIGJhc2VzLCBhbmQgdXNlIHRoZSBmb2xsb3dpbmcgZW1waXJpY2FsbHkgZGVyaXZlZCBleG9uIGFuZCBpbnRyb24gZW1pc3Npb24gcHJvYmFiaWxpdGllcy4KRXhvbiBiYXNlIGZyZXF1ZW5jaWVzOiBBPTAuMjAsQz0wLjMwLEc9MC4zMCxUPTAuMjAuIEludHJvbiBiYXNlIGZyZXF1ZW5jaWVzOiBBPTAuMTUsQz0wLjM1LEc9MC4zNSxUPTAuMTUKTW90aWYgYmFzZSAxOiBBPTAuOTk3LEM9MC4wMDEsRz0wLjAwMSxUPTAuMDAxLCBNb3RpZiBiYXNlIDI6IEE9MC4wMDEsQz0wLjAwMSxHPTAuOTk3LFQ9MC4wMDEsIE1vdGlmIGJhc2UgMzogQT0wLjAwMSxDPTAuMDAxLEc9MC45OTcsVD0wLjAwMSwgTW90aWYgYmFzZSA0OiBBPTAuMDAxLEM9MC4wMDEsRz0wLjAwMSxUPTAuOTk3LApVc2UgdGhlIGhtbSgpIFIgcGFja2FnZSB0byBkZWZpbmUgYW4gaW1wcm92ZWQgNScgZXhvbi1pbnRyb24ganVuY3Rpb24gZGV0ZWN0b3IgdXNpbmcgdGhpcyBpbmZvcm1hdGlvbi4KVGhlbiB1c2UgdGhlIFVDU0MgZ2Vub21lIGJyb3dzZXIgdG8gZXh0cmFjdCB0aGUgaHVtYW4gaGczOCBETkEgc2VxdWVuY2UgYXJvdW5kIHRoZSBmaW5hbCBleG9uLWludHJvbiBzcGxpY2Ugc2l0ZSBmb3IgeW91ciBhc3NpZ25lZCBodW1hbiBnZW5lICg1MCBicCB1cHN0cmVhbSBhbmQgZG93bnN0cmVhbSk7IGFuZCBhbHNvIGV4dHJhY3QgdGhlIGZvbGxvd2luZyBnZW5vbWljIHJlZ2lvbiBjaHIyOjg1LDUzOSwzMTMtODUsNTM5LDQ2OCAob24gdGhlICsgc3RyYW5kKS4gTm93IHRyeSB0byBkZXRlY3QgdGhlIGV4b24taW50cm9uIGJvdW5kYXJ5IHVzaW5nIHlvdXIgaW1wcm92ZWQgSE1NIGFuZCBjb21wYXJlIHdpdGggdGhlIHByZXZpb3VzIEhNTSBnaXZlbiBpbiBjbGFzcyBmb3IgYm90aCBzZXF1ZW5jZXMuIENvbXBhcmUgd2l0aCB0aGUgZ2VuY29kZSBnZW5lIGFubm90YXRpb24gaW4gdGhlIFVDU0MgYnJvd3Nlci0gd2FzIHRoZSBjb3JyZWN0IHNwbGljZSBzaXRlIGxvY2F0aW9uIGRldGVjdGVkIGluIHRoZSB0d28gc2VxdWVuY2VzPwoKYGBge3J9CiNNeSBwYXJ0bmVyIGZvciB0aGlzIHF1ZXN0aW9uIGlzIFphaW5hIEF0aWVoLgoKI015IE5ldyBKdW5jdGlvbiBEZXRlY3RvcgpUaGVVbml0ZWRTdGF0ZXMgPSBjKCJFeG9uIiwgInRvQSIsInRvRzEiLCJ0b0cyIiwgInRvVCIsIkludHJvbiIpCgpTdGFyc0FuZFN0cmlwZXMgPSBjKCJBIiwiQyIsIkciLCJUIikKCnRyYW5zUHJvYnMgPSBtYXRyaXgoYygnRV90b0UnPTAuOSwnRV90b0EnPTAuMSwgJ0VfdG9HMSc9IDAsICdFX3RvRzInPSAwLCAnRV90b1QnPSAwLCdFX3RvSSc9MCwgJ0FfdG9FJz0wLCdBX3RvQSc9MCwgJ0FfdG9HMSc9MS4wLCAnQV90b0cyJz0wLCAnQV90b1QnPTAsICdBX3RvSSc9MCwgJ0cxX3RvRSc9MCwnRzFfdG9BJz0wLCdHMV90b0cxJz0wLCdHMV90b0cyJz0xLjAsJ0cxX3RvVCc9MCwnRzFfdG9JJz0wLCdHMl90b0UnPTAsJ0cyX3RvQSc9MCwnRzJfdG9HMSc9MCwnRzJfdG9HMic9MCwnRzJfdG9UJz0xLjAsJ0cyX3RvSSc9MCwnVF90b0UnPTAsJ1RfdG9BJz0wLCdUX3RvRzEnPTAsJ1RfdG9HMic9MCwnVF90b1QnPTAsJ1RfdG9JJz0xLjAsICdJX3RvRSc9MCwgJ0lfdG9BJz0wLCdJX3RvRzEnPTAsJ0lfdG9HMic9MCwnSV90b1QnPTAsICdJX3RvSSc9MS4wKSwgYyhsZW5ndGgoVGhlVW5pdGVkU3RhdGVzKSwgbGVuZ3RoKFRoZVVuaXRlZFN0YXRlcykpLCBieXJvdyA9IFRSVUUpCnRyYW5zUHJvYnMKZW1pc3Npb25Qcm9icyA9IG1hdHJpeChjKCdBJz0wLjIwLCdDJz0wLjMwLCdHJz0wLjMwLCdUJz0wLjIwLCAnQSc9MC45OTcsJ0MnPTAuMDAxLCdHJz0wLjAwMSwnVCc9MC4wMDEsJ0EnPTAuMDAxLCdDJz0wLjAwMSwnRyc9MC45OTcsJ1QnPTAuMDAxLCdBJz0wLjAwMSwnQyc9MC4wMDEsJ0cnPTAuOTk3LCdUJz0wLjAwMSwnQSc9MC4wMDEsJ0MnPTAuMDAxLCdHJz0wLjAwMSwnVCc9MC45OTcsJ0EnPTAuMTUsJ0MnPTAuMzUsJ0cnPTAuMzUsJ1QnPTAuMTUpLCBjKGxlbmd0aChUaGVVbml0ZWRTdGF0ZXMpLCBsZW5ndGgoU3RhcnNBbmRTdHJpcGVzKSksIGJ5cm93ID0gVFJVRSkKZW1pc3Npb25Qcm9icwoKaG1tIDwtIGluaXRITU0oVGhlVW5pdGVkU3RhdGVzLCBTdGFyc0FuZFN0cmlwZXMsIHN0YXJ0UHJvYnMgPSBjKDEsMCwwLDAsMCwwKSwgdHJhbnNQcm9icyA9IHRyYW5zUHJvYnMsIGVtaXNzaW9uUHJvYnMgPSBlbWlzc2lvblByb2JzKQoKI0NsYXNzIEp1bmN0aW9uIERldGVjdG9yClBhcmtlclN0YXRlcyA9IGMoIkV4b24iLCAiNXNpdGUiLCAiSW50cm9uIikKClBhcmtlclN5bWJvbHMgPSBjKCJBIiwiQyIsIkciLCJUIikKClBhcmtlcnRyYW5zUHJvYnMgPSBtYXRyaXgoYygnRUUnPTAuOSwnRTUnPTAuMSwnRUknPTAsICc1RSc9MCwgJzU1Jz0wLCAnNUknPTEuMCwgJ0lFJz0wLCAnSTUnPTAsICdJSSc9MS4wKSwgYyhsZW5ndGgoUGFya2VyU3RhdGVzKSwgbGVuZ3RoKFBhcmtlclN0YXRlcykpLCBieXJvdyA9IFRSVUUpClBhcmtlcnRyYW5zUHJvYnMKUGFya2VyZW1pc3Npb25Qcm9icyA9IG1hdHJpeChjKCdBJz0wLjI1LCdDJz0wLjI1LCdHJz0wLjI1LCdUJz0wLjI1LCAnQSc9MC4wNSwnQyc9MC4wLCdHJz0wLjk1LCdUJz0wLjAsICdBJz0wLjQsJ0MnPTAuMSwnRyc9MC4xLCdUJz0wLjQpLCBjKGxlbmd0aChQYXJrZXJTdGF0ZXMpLCBsZW5ndGgoUGFya2VyU3ltYm9scykpLCBieXJvdyA9IFRSVUUpClBhcmtlcmVtaXNzaW9uUHJvYnMKClBhcmtlcmhtbSA8LSBpbml0SE1NKFBhcmtlclN0YXRlcywgUGFya2VyU3ltYm9scywgc3RhcnRQcm9icyA9IGMoMSwwLDApLCB0cmFuc1Byb2JzID0gUGFya2VydHJhbnNQcm9icywgZW1pc3Npb25Qcm9icyA9IFBhcmtlcmVtaXNzaW9uUHJvYnMpCgojUFVTTDEgSHVtYW4KQmFsZEVhZ2xlIDwtIHMyYygnQUdDQ0NDQUdDQ0NBQ0dHQ1RUQVRUQ0NUQ0FBR1RDQUdUR0NUR1RBQ0dHR0FBQ0NUQ0dndGFhZ2FhYWFhY2FnZ2NhY2dhZ2FhZ2N0Y2N0Z3RjYXRndGdjY2NhZ3RnYWN0YWN0ZycpCkJhbGRFYWdsZSA8LSB0b3VwcGVyKEJhbGRFYWdsZSkKCgp2aXRCYWxkRWFnbGUgPC0gdml0ZXJiaShobW0sIEJhbGRFYWdsZSkKdml0QmFsZEVhZ2xlCgpQYXJrZXJ2aXRCYWxkRWFnbGUgPC0gdml0ZXJiaShQYXJrZXJobW0sIEJhbGRFYWdsZSkKUGFya2Vydml0QmFsZEVhZ2xlCgoKI2NocjI6ODUsNTM5LDMxMy04NSw1MzksNDY4Ck5vcnRoQW1lcmljYW5CaXNvbiA8LSBzMmMoJ0FDR0FHR0NHVFRDQVRDR0FHR0FHR0dDQUNBVFRDQ1RUVFRDQUNDVENBR0FHVENHR1RDR0dHR0FBR0dDQ0FDQ0NBR0dUR0FHR0dHQUNHR0NDVEdBQUdDR0FBR0NHVEdHR0dDR0dHR0NBR0FBR0dDQUdDR0NDQUFHR1RDQ0dHQ1RHR0NUR0NHR0NDR0dDQ0dHVEdHVEdHR0dDQ0NHQycpCgp2aXROb3J0aEFtZXJpY2FuQmlzb24gPC0gdml0ZXJiaShobW0sIE5vcnRoQW1lcmljYW5CaXNvbikKdml0Tm9ydGhBbWVyaWNhbkJpc29uCgpQYXJrZXJ2aXROb3J0aEFtZXJpY2FuQmlzb24gPC0gdml0ZXJiaShQYXJrZXJobW0sIE5vcnRoQW1lcmljYW5CaXNvbikKUGFya2Vydml0Tm9ydGhBbWVyaWNhbkJpc29uCmBgYApBcyBleHBlY3RlZCwgdGhlIGltcHJvdmVkIGp1bmN0aW9uIGRldGVjdG9yIGRpZCByZXR1cm4gYSBzcGxpY2Ugc2l0ZSB3aGlsZSB0aGUgcHJldmlvdXMganVuY3Rpb24gZGV0ZWN0b3Igd2UgdXNlZCBpbiBjbGFzcyBkaWQgbm90LiAKVGhpcyBvY2N1cnJlZCBpbiBib3RoIHRoZSBzZXF1ZW5jZSBmb3IgdGhlIFBVU0wxIEh1bWFuIGdlbmUgYXNzaWduZWQgdG8gbWUgYXMgd2VsbCBhcyB0aGUgc2VxdWVuY2UgYXQgY2hyMjo4NSw1MzksMzEzLTg1LDUzOSw0NjguIApJbiB0aGUgbGF0dGVyLCB0aGUgaW1wcm92ZWQgZGV0ZWN0b3IgcGlja2VkIHVwIG9uIHRoZSBleGFjdCBzcGxpY2Ugc2l0ZSBmb3VuZCBpbiB0aGUgVUNTQyBnZW5vbWUgYnJvd3Nlci4gCkhvd2V2ZXIsIGluIHRoZSBmb3JtZXIsIHdpdGggbXkgb3duIGdlbmUsIHRoZSBkZXRlY3RvciBwaWNrZWQgdXAgc29tZXRoaW5nIGFib3V0IDI1IGJhc2VzIHVwc3RyZWFtIG9mIHRoZSBhY3R1YWwgc3BsaWNlIHNpdGUgc2VlbiBpbiB0aGUgYnJvd3Nlci4KCjMuIEluIHRoaXMgcXVlc3Rpb24geW91IHdpbGwgZXhhbWluZSBhIHNpbXBsZSB0b3kgcGh5bG9nZW5ldGljIHRyZWUsIGFuZCBhc3NvY2lhdGVkIE1TQSwgc2ltaWxhciB0byB0aGUgb25lIHVzZWQgYXMgYSBtYXhpbXVtIGxpa2VsaWhvb2QgZXhhbXBsZSBpbiBsZWN0dXJlcy4KSW4gdGhlIGZpbGUgdG95X01TQS5mYXN0YSBpcyBkZWZpbmVkIGEgKHZlcnkgc2ltcGxlKSBtdWx0aXBsZSBzZXF1ZW5jZSBhbGlnbm1lbnQgKE1TQSkgb2YgYSByZWdpb24gb2YgRE5BIG9mIGxlbmd0aCAxIGFjcm9zcyBmb3VyIHByaW1hdGUgc3BlY2llcy4KSW4gdGhlIGZpbGUgdG95X3RyZWUudHJlIGlzIGRlZmluZWQgYSBwb3RlbnRpYWwgcGh5bG9nZW5ldGljIHRyZWUgaW4gbmV3aWNrIGZvcm1hdCBmb3Igd2hpY2ggd2Ugd2FudCB0byBkZXRlcm1pbmUgaXRzIGZpdCB0byB0aGUgTVNBLgpSZWFkIGluIHRoZSB0cmVlICh1c2luZyByZWFkLnRyZWUoKSBpbiBSKSBhbmQgYWxzbyByZWFkIGluIHRoZSBNU0EuIERpc3BsYXkgdGhlIHVucm9vdGVkIHRyZWUuCkFzc3VtZSB0aGF0IGluIHRoaXMgc2ltcGxlICh1bnJlYWxpc3RpYykgZXhhbXBsZSBhbGwgdHJlZSBicmFuY2hlcyBoYXZlIHRoZSBzYW1lIGxlbmd0aCB0LCBhbmQgYXNzdW1lIGJhc2UgY29tcG9zaXRpb24gaXMgZXF1YWwgZm9yIGFsbCBiYXNlcy4KQ29tcHV0ZSB0aGUgbG9nIGxpa2VsaWhvb2Qgb2YgdGhlIHRyZWUgYnkgaGFuZCwgdXNpbmcgdGhlIEp1a2VzLUNhbnRvciBldm9sdXRpb25hcnkgbW9kZWwgYW5kIGZvciBwYXJhbWV0ZXIgdmFsdWVzIPCdm7x0ID0gMC4wOSwgMC4xMDMsIGFuZCAwLjEyLgpXaGljaCB2YWx1ZSBvZiDwnZu8dCBzaG93cyB0aGUgbWF4aW11bSBsaWtlbGlob29kPyBTaG93IHlvdXIgd29ya2luZy4KVGhlbiBjb21wdXRlIHRoZSBsb2cgbGlrZWxpaG9vZCBvZiB0aGUgdHJlZSBkZWZpbmVkIGluIHRveV90cmVlLnRyZSB1c2luZyB0aGUgUiBwaGFuZ29ybiBwYWNrYWdlCmFuZCBjb21wYXJlIHlvdXIgcmVzdWx0cy4KCmBgYHtyfQpDaHJpc3RtYXNUcmVlIDwtIHJlYWQudHJlZSgidG95X3RyZWUudHJlIikKU2FudGFzVG95cyA9IHJlYWRETkFNdWx0aXBsZUFsaWdubWVudCgidG95X01TQS5mYXN0YSIsIGZvcm1hdD0iRkFTVEEiKQpTYW50YXNUb3lzIDwtIGFzLnBoeURhdChTYW50YXNUb3lzKQpwbG90KENocmlzdG1hc1RyZWUsIHR5cGU9InVucm9vdGVkIikKZml0ID0gcG1sKENocmlzdG1hc1RyZWUsIGRhdGE9U2FudGFzVG95cywgbW9kZWw9Ikp1a2VzLUNhbnRvciIpCmZpdApsb2dMaWsoZml0KQoKUmVpbmRlZXI8LSBmdW5jdGlvbihhKXsKICBSdWRvbHBoPC0oMSszKmV4cCgtNCphKSkvNAogIFZpeGVuPC0oMS1leHAoLTQqYSkpLzQKICBQcmFuY2VyPC0oNypWaXhlbl41KzIqUnVkb2xwaF4zKlZpeGVuXjIrUnVkb2xwaF40KlZpeGVuKzQqUnVkb2xwaF4yKlZpeGVuXjMrMipSdWRvbHBoKlZpeGVuXjQpLzQKICBCbGl0emVuPC1sb2coUHJhbmNlcikKICByZXR1cm4oQmxpdHplbikKfQoKUmVpbmRlZXIoMC4wOSkKUmVpbmRlZXIoMC4xMDMpClJlaW5kZWVyKDAuMTIpCgpgYGAKCk9mIHRoZSB0aHJlZSB2YWx1ZXMsIDAuMTAzIHNob3dzIHRoZSBtYXhpbXVtIGxpa2VsaWhvb2Qgd2hpY2ggaXMgLTQuNzc4NTU1LgpUaGUgbG9nIGxpa2VsaWhvb2QgaXMgYWxzbyBjb21wdXRlZCB1c2luZyBwaGFuZ29ybiBhYm92ZSB0aGUgbWFudWFsIGNhbGN1bGF0aW9ucy4gVGhlIHJlc3VsdCBvZiB0aGlzIGlzIGFsc28gLTQuNzc4NTU1LgoKNC4gVXNpbmcgUEZBTSwgZXh0cmFjdCB0aGUgbXVsdGlwbGUgc2VxdWVuY2Ugc2VlZCBhbGlnbm1lbnQgZm9yIHRoZSBtb3N0IHNpZ25pZmljYW50IHByb3RlaW4gZG9tYWluIGZyb20geW91ciBhc3NpZ25lZCBodW1hbiBnZW5lIChpZiBubyBrbm93biBkb21haW4gd2FzIGZvdW5kIGluIHlvdXIgZ2VuZSwgdXNlIHRoZSBwaXdpIGRvbWFpbikuIFVzaW5nIHBoYW5naG9ybiwgY29tcHV0ZSB0aGUgZ2VuZSB0cmVlIGZyb20gdGhpcyBNU0EgdXNpbmcgYm90aCBuZWlnaGJvdXItIGpvaW5pbmcgYW5kIG1heGltdW0gcGFyc2ltb255IGFuZCBtYXhpbXVtIGxpa2VsaWhvb2QuIFNob3cgdGhlIHBhcnNpbW9ueSBzY29yZSBhbmQgbG9nIGxpa2VsaWhvb2Qgb2YgeW91ciBtYXhpbXVtIHBhcnNpbW9ueSBhbmQgbWF4aW11bSBsaWtlbGlob29kIHRyZWVzLCByZXNwZWN0aXZlbHkuIFNob3cgeW91ciBSIGNvZGUuCgpgYGB7cn0KI0V4dHJhY3QgdGhlIG11bHRpcGxlIHNlcXVlbmNlIHNlZWQgYWxpZ25tZW50IGZvciB0aGUgbW9zdCBzaWduaWZpY2FudCBwcm90ZWluIGRvbWFpbiBmcm9tIFBGQU0uCnNlZWRhbGlnbiA8LSBwZmFtKCJQc2V1ZG9VX3N5bnRoXzEiLCBhbGlnbm1lbnQgPSAic2VlZCIpIApQc2V1ZG9VIDwtIGFzLnBoeURhdChzZWVkYWxpZ24kYWxpLCB0eXBlPSJBQSIpCgoKI3BoYW5nb3JuIHBhcnQKI25laWdoYm9yLWpvaW5pbmcKZG0gPC0gZGlzdC5tbChQc2V1ZG9VKQp0cmVlTkogPC0gTkooZG0pCnBsb3QodHJlZU5KLCAidW5yb290ZWQiLCBtYWluPSJOSiIpCgoKI21heGltdW0gcGFyc2ltb255CnRyZWVQYXJzIDwtIG9wdGltLnBhcnNpbW9ueSh0cmVlTkosIFBzZXVkb1UsbWV0aG9kID0gInNhbmtvZmYiKQpwbG90KHRyZWVQYXJzLCAidW5yb290ZWQiLCBtYWluPSJwYXJzaW1vbnkiKQoKcGFyc2ltb255KHRyZWVOSiwgUHNldWRvVSxtZXRob2QgPSAic2Fua29mZiIpCmBgYAoKVGhlIHBhcnNpbW9ueSBzY29yZSBpcyAxMTMzNy4KCmBgYHtyfQojbWF4aW11bSBsaWtlbGlob29kCmZpdHBhcnMgPC0gcG1sKHRyZWVOSiwgZGF0YT1Qc2V1ZG9VKQpmaXRwYXJzCmxvZ0xpayhmaXRwYXJzKQpgYGAKClRoZSBsb2cgbGlrZWxpaG9vZCBpcyAtNTkxNTIuNzIuCgpgYGB7cn0KcGxvdChmaXRwYXJzJHRyZWUpCmBgYAoKNS4gVGhlIFNBUlMgZXBpZGVtaWMgb2YgMjAwMyB3YXMgYSB2aXJhbCByZXNwaXJhdG9yeSBkaXNlYXNlIGNhdXNlZCBieSBhIG11dGF0aW9uIGluIGEgY29yb25hdmlydXMuIFZhcmlvdXMgc2FtcGxlcyBvZiB0aGUgdmlydXMgd2VyZSBzZXF1ZW5jZWQgYXMgdGhlIHZpcnVzIG11dGF0ZWQgYW5kIHNwcmVhZCB0aHJvdWdob3V0IHRoZSB3b3JsZC4KSXQgaXMgYWxzbyBrbm93biB0aGF0IHRoZSBTQVJTIGNvcm9uYXZpcnVzIGlzIGRpc3RhbnRseSByZWxhdGVkIHRvIHRoZSBIaW1hbGF5YW4gUGFsbSBDaXZldCBjb3JvbmF2aXJ1cyBhbmQgc28gdGhpcyBjYW4gYmUgdXNlZCBhcyBhbiBvdXRncm91cCBpbiBvdXIgcGh5bG9nZW5ldGljIGFuYWx5c2lzLgpUaGUgc2VxdWVuY2VzIG9mIGEga2V5IHByb3RlaW4gaW4gZWFjaCBvZiB0aGVzZSBzYW1wbGVzIGFyZSBwcm92aWRlZCBpbiB0aGUgZmFzdGEgZmlsZSAic2Fycy5mYXN0YSIuClBlcmZvcm0gYSBwaHlsb2dlbmV0aWMgYW5hbHlzaXMgb2YgdGhlIHNwcmVhZCBvZiB0aGUgZGlzZWFzZSBmcm9tIHRoZXNlIHNhbXBsZXMgdG8gZGV0ZXJtaW5lIHRoZSBsaWtlbHkgc2l0ZSBvZiBvcmlnaW4gb2YgdGhlIGRpc2Vhc2UuClNob3cgYSBOSiBwaHlsb2dlbmV0aWMgdHJlZSBhcyB5b3VyIGV2aWRlbmNlIGFuZCBnaXZlIHlvdXIgYXJndW1lbnRzIGZvciAoaSkgdGhlIHNpdGUgb2Ygb3JpZ2luLCAoaWkpIHRoZSBuZXh0IG1ham9yIHNpdGUgU0FSUyBzcHJlYWQgdG8uCllvdSBzaG91bGQgdXNlIHRoZSBwaGFuZ29ybiBwYWNrYWdlIGluIFIuIE5vdGUgdGhhdCB0aGUgcm9vdCBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBzZXQgdGhlIHJvb3Qgb2YgdGhlIHRyZWUgZS5nLiByb290KHRyZWVOSiwgb3V0Z3JvdXAgPSAiSGltYWxheWFuIHBhbG0gY2l2ZXQgc2FycyBjb3YsIGNvbXBsZXRlIGdlbm9tZSIpIC4KCmBgYHtyfQpTQVJTIDwtIHJlYWQucGh5RGF0KCJzYXJzLmZhc3RhIiwgdHlwZT0iRE5BIiwgZm9ybWF0ID0gImZhc3RhIikKClNBUlNkbSA8LSBkaXN0Lm1sKFNBUlMpCnRyZWVOSiA8LSBOSihTQVJTZG0pCnRyZWVOSnJvb3QgPC0gcm9vdCh0cmVlTkosIG91dGdyb3VwID0gIkhpbWFsYXlhbiBwYWxtIGNpdmV0IHNhcnMgY292LCBjb21wbGV0ZSBnZW5vbWUiLCByZXNvbHZlLnJvb3Q9VFJVRSkKcGxvdCh0cmVlTkpyb290LCB0eXBlPSJwaHlsb2dyYW0iKQpgYGAKCkJhc2VkIG9uIHRoaXMsIHdlIGNhbiBkZWR1Y2UgdGhhdCB0aGUgY2l0eSBvZiBvcmlnaW4gaXMgR3Vhbmd6aG91IGluIEd1YW5nZG9uZy4KRGVwZW5kaW5nIG9uIHRoZSBkZWZpbml0aW9uIG9mIHRoZSBuZXh0IG1ham9yIHNpdGUsIFpob25nc2hhbiBpcyB0aGUgbmV4dCBtYWpvciBjaXR5IGJ1dCBzdGlsbCBpbiBHdWFuZ2RvbmcgYW5kIEhvbmcgS29uZyBpcyB0aGUgbmV4dCBtYWpvciByZWdpb24gYWZ0ZXIgR3Vhbmdkb25nIGFzIGEgd2hvbGUuCg==