“Pose ton esprit, Michel”
Catherine Pirenne, my grand-mother

Introduction

The aim of this course is:

  1. To make you think more deeply about some fundamental concepts in statistics, including:
    • the meaning of p-value,
    • the issue of multiple testing,
    • the meaning of the false discovery rate (FDR), and
    • the winners’ curse
  2. To introduce you to basic programming in R, including to compute p-values by simulation and permutation.

I have found this book especially to be an excellent introductions to R:

Other references which may be useful to you include:

You can download this R notebook and other material from: https://www.gigauag.uliege.be/cms/c_4766333/en/gigauag-teaching

I am relatively new to R myself. So be clement please :-).

You will need to install the following R packages and libraries to use this Notebook

# packages and libraries to install
###################################
#install.packages("pryr")
#install.packages("ggplot2")
#install.package("RColorBrewer)
library("pryr")
library("ggplot2")
library("RColorBrewer")
brewer.pal(9,"Blues")
[1] "#F7FBFF" "#DEEBF7" "#C6DBEF" "#9ECAE1" "#6BAED6" "#4292C6" "#2171B5" "#08519C"
[9] "#08306B"

You may also want to check your working directory before starting

# Check / set your working directory
####################################
setwd("/Users/michelgeorges/Documents/Teaching/GIGA_Doctoral_School/Intuitive_statistics/R_INT_STAT")
getwd()
[1] "/Users/michelgeorges/Documents/Teaching/GIGA_Doctoral_School/Intuitive_statistics/R_INT_STAT"

About p-values, null (H0) and alternative (H1) hypotheses

PLAYING WITH COINS

A common modus operandi in science is to challenge a preconceived model (H0) with observations. If the likelihood of the observations is very small under H0, one may put the validity of H0 in question and possibly “reject” it.

To illustrate this, we will play at “heads or tails” (i.e. “pile ou face”) to test whether coins are balanced, i.e. have an equal chance to fall on the head vs tail face when tossed. Each of us will test a 1-€ coin by tossing it, say 50 times and record the number of times it falls on head. If the coin is balanced (=H0) we expect 25 heads and 25 tails. All different values are a “sign of bias”, i.e. an excess of heads (n_H > 25) or an excess of tails (n_T > 25). Yet we are not worried about the balance of a coin if we observe 26 heads and 24 tails (or vice versa), or even 25 heads and 23 tails (or vice versa). But should we be worried about the coin if we observe f.i. 35 heads and 15 tails?

To address this, we need to be able to compute the probability of the observations under H0 (= balanced coin). In this peculiar case, the probability of a given outcome (n_H and n_T) can easily be computed using the binomial distribution:

[(n_H+nT)!/n_H!n_T!] x 0.5^(n_H+n_T)

We will now use R to generate the corresponding probability distribution. For that we will generate a data frame in which the first column (NR) corresponds to the observed number of “heads”, and six other columns are prepared to receive (i) the corresponding probability (which we will call F), (ii) the deviation from expectation (DEV), (iii) the probability to observe an equally or more deviant series (P for p-value), (iv) a column for a logical (T), (v) …, (vi) … We will assume that - to test its balance - we toss the coin 50 times.

nr <- 50
# Generate data frame
toss <- data.frame(NR=0:nr, F=0, DEV=0, P=0, T=0, BIN=0, SIM=0)
toss
# Generate function computing combinations of n objects taken x at a time
comb = function(n, x) {
  factorial(n) / factorial(n-x) / factorial(x)
}
# Compute probabilities "f"
toss[,2] = 0.5^nr * comb(nr,toss[,1])
toss
# Plot probabilities
plot(toss[,1],toss[,2],col= "blue")

We see that this distribution resembles a normal distribution, “balanced” outcomes are more likely than “unbalanced” ones due to the “nCr” term in the equation.

To test whether our coin is tricked or not we actually utilize a different probability which we will refer to as “the p-value” found in all publications. The question we actually want to ask when we throw 35 heads and 15 tail, is “What was the probability to throw an equally unbalanced or even more unbalanced series?” Well, we could have thrown 50/0, 49/1, 48/2, … 35/15, but also 0/50, 1/49, 2/48, … 15/35, which are all outcomes that are equally or more “unbalanced”. Indeed, when we checked for the balance or not of the coin we didn’t decide whether the bias should favor heads or tails. We performed a so-called “two-tailed test”. Had we suspected in advance that the bias would favor the heads, we would only have considered 50/0, 49/1, 48/2, … 35/15 in a so-called “one-tailed” test. When looking at the probability distribution, and assuming it corresponds to a continuous distribution, our intend is to determine the part of the surface under the curve that lies outside of the boundaries between 34/16 and 35/15 and 16/34 and 15/35 in the two-tailed test, or on the left of the 34/16-35/15 boundary in the “one-tailed” test.

We will now use R to compute this probability for the different values of n_H using, first, our self-made little script and then check whether we obtain the same results as a dedicted R function. Note the use of “logical tests, subsetting and element-wise execution”.

# Compute the probability to have an equally or even more biased toss with our own litte script
################################################################################################
# Computing deviation from expectation
toss$DEV = abs(toss[,1]-nr/2)
toss
# Compute p-values
for (i in 0:nr){
  toss$T = toss$DEV >= toss[i+1,3]
  toss[i+1,4] = sum(toss$F*toss$T)
}
toss
# Plot p-values
plot(toss[,1],toss[,4],col="red", xlab = "NR HEADS", ylab = "P/F")
points(toss[,1],toss[,2],col="blue")
# Compare with R function
#########################
for (i in 0:nr){
  bin <- binom.test(x = toss[i+1,1],n = nr, p = 0.5, alternative = "two.sided")
  toss[i+1,6] = bin$p.value
}
toss
# Plot p-values
###############
lines(toss[,1],toss[,6],col="red")

# Plot -log(p)
##############
plot (toss[,1],-log10(toss[,6]),col="red",xlab = "NR HEADS", ylab = "-log(P)")
abline(h = -log10(0.05))

For 35 heads and 15 tails, the p-value is 0.0066. Maybe we have to worry about such a coin!

Assume that you forgot the equation of the binomial distribution, you could still have determined the corresponding p-value quite easily with your computer by “simulation”. Indeed, we can easily simulate series of 50 tosses under H0, i.e. the probability to throw a head is equal to that of a tail. We can then count how often – in the simulations - the number of heads departs as much or more from the expected (=25) than with our actual coin (f.i. 35), i.e. how often |Sim-25|≥|35-25|.
We will use R to generate the corresponding distribution by simulation and compare it with the theoretical one.

# Generate distribution of NR by simulation
###########################################
sample (x=0:1,size=nr, replace=TRUE)
 [1] 1 1 1 1 1 0 1 1 1 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1 1 0 0 1 0 1 1 0 1 0 1 1 1 0 0 0 0
[44] 0 1 1 1 1 0 1
sum(sample (x=0:1,size=nr, replace=TRUE))
[1] 24
replicate(10,sum(sample (x=0:1,size=nr, replace=TRUE)))
 [1] 28 24 18 25 25 25 23 21 29 18
nr_repl = 100000
sim <- replicate(nr_repl,sum(sample (x=0:1,size=nr, replace=TRUE)))
qplot(sim,binwidth=1)

hist(sim,breaks=seq(-0.5,50.5,1), border = "red")

# Compare distribution of simulated and theoretical F values
############################################################
for (i in 0:nr){
  toss[i+1,6] = sum(sim == i)/nr_repl
}
toss
plot(toss[,1], toss[,2],col = "blue")
lines(toss[,1],toss[,6],col = "blue")

The p-value of an observed number of heads (or tails) under the null can very easily be computed as follows:

# Compute p-value using simple simulation
#########################################
test_nr = 35
sum(sim >= test_nr | sim <= nr-test_nr)/nr_repl
[1] 0.00652

GENETIC ASSOCIATION STUDIES

To further our discussions, I will invite you in one of my own research fields: genetic association studies. We are not all equal in the face of disease: some of us are more susceptible to asthma, others to cardiovascular issues, other to cancers, etc. Part of these differences are due to differences in “inherited predisposition”. This means that there are genetic variants in the population that increase (risk variants) or decrease (protective variants) disease risk of those that carry them. Imagine a genetic polymorphism with two variants (say allele A and allele a). Imagine that the allelic frequencies in the population are f_A and f_a = 1-f_A. Imagine that the a allele is a risk variant for Crohn’s disease. This means that if you carry a (i.e. your genotype is Aa or aa) your chance to develop Crohn’s disease is increased when compared to the AA individuals. As a consequence, if you sample a cohort of Crohn’s patients and measure the frequency of the a allele in this cohort of “cases”, it is expected to be higher (say f_a+δ) than the frequency of the a allele in a cohort of healthy “controls” (say ~f_a). It is interesting to identify genetic polymorphisms in our genome that contribute to differences in inherited disease predisposition in the population, as this is a first step towards identifying the genes whose function they perturb and which are potential drug targets. To test whether a polymorphism of interest is influencing disease predisposition, one will typically collect DNA samples from n_D cases, and n_H controls, genotype all individuals for the polymorphism of interest, and check whether the genotypes are associated with the disease, i.e. perform an association study. Stated more plainly, this simply means that one will compare the frequency of the A and a alleles in cases and controls and check whether there is any evidence that they differ significantly. Note that for a biallelic polymorphism, testing A is the same (albeit mirror image) as testing a: if one goes up by an amount δ, the other has to go down by the same amount.

Good … Let us do this. Imagine that we implement that with 100 cases and 100 controls, that the frequency of allele a is 0.10 in cases and 0.15 in controls. Is that interesting? Is the A/a polymorphism significantly associated with Crohn’s disease and a hence a genuine risk variant that may lead us to a real causative gene? In other words, is δ = 0.15-0.10 = 0.05 significantly different from zero?

Can we use an approach similar to the one used with the coins to evaluate this? I guess we can imagine something similar. Under H0, the frequency of a in cases and controls is the same: f_a. Thus, we can predict the probability distribution of n_D,a cases and n_H,a controls using the same equation as above (based on the binomial distribution). Assuming that what happens in cases and controls is independent, the probability of the combination of events is just the product of the individual probabilities. Each of these combinations generates a δ, and thus we have δ’s probability distribution under the null. Great! One problem though: with the coins we knew that under H0 f_H = f_T = 0.5, but what is f_a under the null? We actually don’t know for sure. But assuming that H0 is true, hence that f_a is the same in cases and controls, our best estimate of the true value of f_a is the frequency of a in cases and controls combined (largest sample we can assemble). Thus, we will generate an estimate f̂_a using both cases and controls. There we go … we have everything we need.

# Distribution of n_a in a sample of 100 individuals
####################################################
f_a = 0.125
nr_ind = 100
nr_gam = 2*nr_ind
ass_bin <- data.frame(NR_a = 0:nr_gam, FREQ=0, F_FREQ=0, DELTA = 0, F_DELTA = 0, P_DELTA = 0, P = 0)
ass_bin[,2] = ass_bin[,1]/nr_gam
ass_bin[,3] = dbinom(ass_bin[,1],nr_gam,f_a,log = FALSE)
ass_bin[,4] = ass_bin[,1]/nr_gam
ass_bin
plot(ass_bin[,2],ass_bin[,3],col="red", xlab = "FREQ", ylab = "F")

# Frequency distribution of delta between two samples of 100 individuals (f.i. cases and ctrls) under the null
################################################################################################################
for (i in 1:nr_gam+1){
  for (j in 1:nr_gam+1){
    ass_bin[abs(ass_bin[i,1]-ass_bin[j,1])+1,5] = ass_bin[abs(ass_bin[i,1]-ass_bin[j,1])+1,5] + (ass_bin[i,3] * ass_bin[j,3])
  }
}
ass_bin
plot(ass_bin[,4],ass_bin[,5],col="red", xlab = "DELTA", ylab = "F")

# Probability to have delta larger or equal than "x"
####################################################
for (i in 1:nr_gam){
  ass_bin[nr_gam-i,6] = ass_bin[nr_gam+1-i,6]+ass_bin[nr_gam-i,5]
}
ass_bin
plot(ass_bin[,4],ass_bin[,6],col="blue",xlab = "DELTA", ylab = "F/P", xlim = c(0,0.1))
points(ass_bin[,4],ass_bin[,5],col="red")
abline(h = 0.05)

In this specific case, we could fall back on the binomial distribution. But this will not always be the case or tractable. One of the things statisticians have done during the 20ies century is to imagine a number of “tricks” that will allow you in lots of circumstances to perform a simple manipulation of your data such that the outcome corresponds to a “statistic” with a known probability distribution. You have heard of Z (standard normal distribution with mean 0 and var/SD 1), chi-squared (sum of squared Z’s), t (Z/sqrt(n)) and F (ratio of variances) statistics. These are all “quantities” that have a known probability distribution under the null.

In the case of the association test, one can for instance generate a contingency table, and compute SUM(EXP-OBS)^2/EXP, which is known to have a chi-squared distribution with one degree of freedom.

# Contingency table
###################
SOE = 2*(1+25/175)
SOE 
[1] 2.285714
p_SOE = pchisq(SOE,1,lower.tail = FALSE)
p_SOE
[1] 0.13057
plot(ass_bin[,4],ass_bin[,6],col="blue",xlab = "DELTA", ylab = "P", xlim = c(0,0.1))
abline(h = 0.05)
points(0.05,p_SOE,col="green",pch = 19,cex = 2)

M<-as.table(rbind(c(30,170),c(20,180)))
M
    A   B
A  30 170
B  20 180
Xsq <- chisq.test(M,correct=FALSE)
Xsq$statistic
X-squared 
 2.285714 
Xsq$p.value
[1] 0.13057

An alternative is to generate a likelihood ratio test (LRT) which also has a chi-squared distribution.

# Likelihood Ratio Test
#######################
L0 = 0.125^(20+30) * 0.875^(170+180)
L1 = 0.15^30 * 0.85^170 * 0.10^20 * 0.90^180
log(L0)
[1] -150.7081
log(L1)
[1] -149.5584
lrt = -2*(log(L0)-log(L1))
lrt
[1] 2.299305
p_lrt = pchisq(lrt,1,lower.tail = FALSE)
p_lrt
[1] 0.1294319
plot(ass_bin[,4],ass_bin[,6],col="blue",xlab = "DELTA", ylab = "P", xlim = c(0,0.1))
abline(h = 0.05)
points(0.05,p_lrt,col="black",pch = 19,cex = 2)

A problem with these “standard” statistic tests is that to conform to the expected probability distribution, a number of conditions need to be met which may not always be the case. This can generate both false negatives, but more worrisomely false positives as well. So, don’t get excited too quickly when you obtain a low p-value ;-).

The game with the binomial distribution is not that easy, and you may not remember the standard statistic tricks too well. Fortunately, in the 21st century, computers really may help you out a lot. How about using in silico simulations as above, to evaluate whether δ = 0.05 is interesting or not? Why not generate genotypes for a case cohort of n_D individuals and a control cohort of n_H individuals using our best estimate of f̂_a and measure δ? If we repeat this a large number of times, we will in effect generate the distribution of δ under the null and directly evaluate how commonly values as large or larger the the δ seen with real data occur under the null.

# Using simulations
###################
f_a = 0.125
sample(c(0,1),nr_gam,replace = TRUE,prob = c(1-f_a,f_a))
  [1] 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
 [44] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
 [87] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[130] 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
[173] 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
sum(sample(c(0,1),nr_gam,replace = TRUE,prob = c(1-f_a,f_a)))
[1] 23
sum(sample(c(0,1),nr_gam,replace = TRUE,prob = c(1-f_a,f_a)))/nr_gam
[1] 0.125
sim_f<-replicate(1000,sum(sample(c(0,1),nr_gam,replace = TRUE,prob = c(1-f_a,f_a)))/nr_gam)
mean(sim_f)
[1] 0.12452
sim_d<-replicate(10000,sum(sample(c(0,1),nr_gam,replace = TRUE,prob = c(1-f_a,f_a)))/nr_gam-sum(sample(c(0,1),nr_gam,replace = TRUE,prob = c(1-f_a,f_a)))/nr_gam)
mean(sim_d)
[1] -0.0002835
sum(abs(sim_d)>= 0.05)/10000
[1] 0.1395
plot(ass_bin[,4],ass_bin[,6],col="blue",xlab = "DELTA", ylab = "P", xlim = c(0,0.1))
abline(h = 0.05)
points(0.05,sum(abs(sim_d)>= 0.05)/10000,col="red",pch = 19,cex = 2)

EXERCICES

1 Compute the p-value of 38 euros tosses yielding 12 heads under the null.
2. Compute the p-value of finding the a allele at frequency of 0.20 in 150 cases, and at frequency of 0.24 in 125 cases.

#####################
nr_tosses = 38
nr_heads = 12
nr_repl = 10000
sim<-replicate(nr_repl,sum(sample (x=0:1,size=nr_tosses, replace=TRUE)))
sim
(abs(sim-nr_tosses/2) >= abs(nr_heads-nr_tosses/2))
sum(abs(sim-nr_tosses/2) >= abs(nr_heads-nr_tosses/2))
sum(abs(sim-nr_tosses/2) >= abs(nr_heads-nr_tosses/2))/nr_repl
#######################
nr_cases = 150
nr_ctrls = 125
a_cases = 0.20
a_ctrls = 0.24
nr_repl = 10000
f_a = (a_cases*nr_cases+a_ctrls*nr_ctrls)/(nr_cases+nr_ctrls)
sim_d<-replicate(nr_repl,sum(sample(c(0,1),2*nr_cases,replace = TRUE,prob = c(1-f_a,f_a) ) )/2/nr_cases - sum(sample(c(0,1),2*nr_ctrls,replace = TRUE,prob = c(1-f_a,f_a) ) )/2/nr_ctrls)
mean(sim_d)
sum(abs(sim_d)>= abs(a_cases-a_ctrls))/nr_repl
######################

We actually have an alternative to the simulations that may even be better. The question at hand is whether – in the real data – the genotypes are somehow correlated with disease status (i.e. being case vs control). What if we were to “shuffle” the data, meaning that we would assign the available genotypes randomly to any of the available phenotypes. For sure, any association between genotype and phenotype could only be fortuitous under such scenario. Hence repeating such permutations many times and each time measuring δ (as for the simulations) will yield its distribution under the null. With permutations, the data resemble the real data even better than with the simulations. Specifically, for this example, the genotypes in the permutations match the real data even better than the genotypes in simulations.

We will use real data to illustrate this approach. We will first load a “preprocessed” file with genotypes at ~ 420 SNPs for a case-control cohort for IBD totaling 4,000 individuals.

# Load real dataset
###################
GWAS <- read.csv("~/Documents/Teaching/GIGA_Doctoral_School/Intuitive_statistics/ibd_genotypes_76b541e64057bdfdaf86_/GWAS.data", header=FALSE, sep=";")
#View(GWAS)

The rows in the file correspond to individuals. The columns correspond to “id”, “sex” (1 vs 2), “affection status (1 vs 2), and then genotypes at a series of SNPs (0, 1 or 2 copies of allele a). Let’s us have a look at some of the features of the dataset.

# Have a look at the dataset
############################
nr_var <- ncol(GWAS)-3
nr_var
[1] 420
nr_ind_with_sex <- sum(GWAS$V2 == 1 | GWAS$V2 == 2)
nr_ind_with_sex
[1] 4000
nr_males <- sum(GWAS$V2 == 1)
nr_males
[1] 1893
nr_ind_with_phen <- sum(GWAS$V3 == 1 | GWAS$V3 == 2)
nr_ind_with_phen
[1] 4000
nr_healthy_ind <- sum(GWAS$V3 == 1)
nr_healthy_ind
[1] 2496
nr_ind_with_V4_genotype <- sum(GWAS$V4 == 0 |GWAS$V4 == 1 | GWAS$V4 == 2)
nr_ind_with_V4_genotype
[1] 4000
freq_all_alt_V4 <- sum(GWAS$V4)/(2*sum(GWAS$V4 == 0 | GWAS$V4 == 1 | GWAS$V4 == 2))
freq_all_alt_V4
[1] 0.688625
nr_cases_with_F4_genotype <- sum((GWAS$V4 == 0 | GWAS$V4 == 1 | GWAS$V4 == 2) & GWAS$V3 == 2) 
nr_cases_with_F4_genotype
[1] 1504
freq_cases_alt_V4 <- sum(GWAS$V4[GWAS$V3 == 2])/(2*sum((GWAS$V4 == 0 | GWAS$V4 == 1 | GWAS$V4 == 2) & GWAS$V3 == 2))
freq_cases_alt_V4
[1] 0.6884973
nr_ctrls_with_F4_genotype <- sum((GWAS$V4 == 0 | GWAS$V4 == 1 | GWAS$V4 == 2) & GWAS$V3 == 1) 
nr_ctrls_with_F4_genotype
[1] 2496
freq_ctrls_alt_V4 <- sum(GWAS$V4[GWAS$V3 == 1])/(2*sum((GWAS$V4 == 0 |GWAS$V4 == 1 | GWAS$V4 == 2) & GWAS$V3 == 1))
freq_ctrls_alt_V4
[1] 0.6887019
i=5
sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2))
[1] NA
sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2), na.rm = TRUE)
[1] 3996
sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 1, na.rm = TRUE)
[1] 2492
sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 2, na.rm = TRUE)
[1] 1504
sum(GWAS[,i+3][GWAS[,3] == 1], na.rm = TRUE)/(2*sum((GWAS[,i+3] == 0 |GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 1, na.rm = TRUE))
[1] 0.9390048

For reasons which you will understand later I will save the original “affection status” as a distinct vector.

# Save original version of "affection status" as a vector
#########################################################
AFF_STATUS <- GWAS$V3
#AFF_STATUS

We will first compute the association (with disease) p-values for the 420 SNPs using both the contingency table approach and the LRT.

# Preparing a data frame
########################
RES_GWAS <- data.frame(SNP = 1:nr_var, CHR = 0, POS=0, NR_GEN_CTR=0, ALT_FR_CTR=0, NR_GEN_CAS=0, ALT_FR_CAS=0, ALT_FR_ALL=0, 
                       CHISQ=0, LP_CHISQ_1=0, LP_CHISQ_2=0, LRT=0, LP_LRT=0, LP_PERM=0, LP_MULTEST=0)
RES_GWAS
# Generating a function computing the p-value of a contingency table using a chi squared test
#############################################################################################
mychi <- function(i){
  ct<-matrix(c(2*RES_GWAS[i,4]*RES_GWAS[i,5],2*RES_GWAS[i,4]*(1-RES_GWAS[i,5]),2*RES_GWAS[i,6]*RES_GWAS[i,7],2*RES_GWAS[i,6]*(1-RES_GWAS[i,7])), nrow=2, byrow=TRUE)
  Xsq <- chisq.test(ct,correct=FALSE)
  Xsq$p.value
}
# Generating and storing summary data and p-values in data frame
################################################################
for (i in 1:nr_var){
  RES_GWAS[i,4] = sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 1, na.rm = TRUE)
  RES_GWAS[i,5] = round(sum(GWAS[,i+3][GWAS[,3] == 1], na.rm = TRUE)/(2*RES_GWAS[i,4]),digits=3)
  RES_GWAS[i,6] = sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 2, na.rm = TRUE)
  RES_GWAS[i,7] = round(sum(GWAS[,i+3][GWAS[,3] == 2], na.rm = TRUE)/(2*RES_GWAS[i,6]),digits=3)
  RES_GWAS[i,8] = round((RES_GWAS[i,4]*RES_GWAS[i,5]+RES_GWAS[i,6]*RES_GWAS[i,7])/(RES_GWAS[i,4]+RES_GWAS[i,6]),digits=3)
  RES_GWAS[i,9] = 2*( (2*RES_GWAS[i,4]*RES_GWAS[i,5] - 2*RES_GWAS[i,4]*RES_GWAS[i,8]) ^2) / (2*RES_GWAS[i,4]*RES_GWAS[i,8])
                + ( (2*RES_GWAS[i,4]*(1-RES_GWAS[i,5]) - 2*RES_GWAS[i,4]*(1-RES_GWAS[i,8])) ^2) / (2*RES_GWAS[i,4]*(1-RES_GWAS[i,8]))
  RES_GWAS[i,10] = -log10(pchisq(RES_GWAS[i,9],1,lower.tail = FALSE))
  RES_GWAS[i,11] = -log10(mychi(i))
  LH1 = (2*RES_GWAS[i,4]*RES_GWAS[i,5])*log(RES_GWAS[i,5]) + (2*RES_GWAS[i,4]*(1-RES_GWAS[i,5]))*log(1-RES_GWAS[i,5]) + (2*RES_GWAS[i,6]*RES_GWAS[i,7])*log(RES_GWAS[i,7]) + (2*RES_GWAS[i,6]*(1-RES_GWAS[i,7]))*log(1-RES_GWAS[i,7])
  LH0 = (2*RES_GWAS[i,4]*RES_GWAS[i,5])*log(RES_GWAS[i,8]) + (2*RES_GWAS[i,4]*(1-RES_GWAS[i,5]))*log(1-RES_GWAS[i,8]) + (2*RES_GWAS[i,6]*RES_GWAS[i,7])*log(RES_GWAS[i,8]) + (2*RES_GWAS[i,6]*(1-RES_GWAS[i,7]))*log(1-RES_GWAS[i,8])
  RES_GWAS[i,12] = 2*(LH1-LH0)
  RES_GWAS[i,13] = -log10(pchisq(RES_GWAS[i,12],1,lower.tail = FALSE))
}
RES_GWAS
# Generate mini Manhattan plot
##############################
plot(RES_GWAS[,1],RES_GWAS[,11],col="red", xlab = "ORDERED SNPs", ylab = "-log(p)")
abline(h = -log10(0.05), lty = 4)
points(RES_GWAS[,1],RES_GWAS[,13],col="blue")

# Compare p-values CT vs LRT
############################
plot(RES_GWAS[,11],RES_GWAS[,13],col="red", xlab = "-log(p) CT", ylab = "-log(p) LRT")

As you can see, both approaches yield virtually identical results.

We will now apply the permutation test. Thus, we will re-assign affection status randomly to the 4,000 individuals yet maintaining the same number of cases and controls. By doing this we obviously disconnect the genotypes from the phenotype as discussed above. Any association could now only be fortuitous (although – see below). We will compute a “statistic” that measures the difference in f_a between cases and controls. I choose just to compute delta. We repeat this n_perm times, hence providing us with the distribution of delta under the null. The p-value of the real delta’s under the null then corresponds to the number of permutations yielding delta’s that are larger or equal to the real ones.

The following code may take a long time to run if you have lots of SNPs and/or many individuals. If you prefer not to run it now, you can go to the next “R chunk” to import precomputed results.

# Generating a data frame (with same structure as RES_GAWAS) to store the results of the permutations (SH-uffles)
##################################################################################################################
SH_GWAS <- data.frame(SNP = 1:nr_var, CHR = 0, POS=0, NR_GEN_CTR=0, ALT_FR_CTR=0, NR_GEN_CAS=0, ALT_FR_CAS=0, ALT_FR_ALL=0, 
                       CHISQ=0, LP_CHISQ=0, LP_CHISQ_2=0, LRT=0, LP_LRT=0, LP_PERM=0, LP_MULTEST=0)
# Generate a function that will shuffle the affection status in GWAS,
# generate and store the relevant summary data and p-values
#####################################################################
shuffle <- function(i){
  GWAS[,3] <- sample(AFF_STATUS,size = 4000,replace = FALSE)
  SH_GWAS[i,4] = sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 1, na.rm = TRUE)
  SH_GWAS[i,5] = round(sum(GWAS[,i+3][GWAS[,3] == 1], na.rm = TRUE)/(2*SH_GWAS[i,4]),digits=3)
  SH_GWAS[i,6] = sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 2, na.rm = TRUE)
  SH_GWAS[i,7] = round(sum(GWAS[,i+3][GWAS[,3] == 2], na.rm = TRUE)/(2*SH_GWAS[i,6]),digits=3)
  DELTA = abs(SH_GWAS[i,5]-SH_GWAS[i,7])
  DELTA
}
# Compute distribution of delta under the null and resulting p-value of real delta for each SNP separately
##########################################################################################################
nr_perm=10000
for (i in 1:nr_var) {
  perm <- replicate(nr_perm,shuffle(i))
  nr_pos <- sum(perm >= abs(RES_GWAS[i,5]-RES_GWAS[i,7]))
  if (nr_pos == 0){
    RES_GWAS[i,14] = -log10(1/nr_perm)
  } else {
    RES_GWAS[i,14] = -log10(nr_pos/nr_perm)
  }
}
RES_GWAS
# Compare the p-values obtained with the different approaches
#############################################################
plot(RES_GWAS[,11],RES_GWAS[,14],col="red")
points(RES_GWAS[,13],RES_GWAS[,14],col="green")
points(RES_GWAS[,11],RES_GWAS[,13],col="black")
# Compare the Manhattan plots obtained with the different approaches
####################################################################
plot(RES_GWAS[,1],RES_GWAS[,11],col="red", xlab = "ORDERED SNPs", ylab = "-log(p)")
abline(h = -log10(0.05), lty = 4)
points(RES_GWAS[,1],RES_GWAS[,13],col="green")
points(RES_GWAS[,1],RES_GWAS[,14],col="black")
# Write RES_GWAS to file
########################
write.csv(RES_GWAS,"GWAS_RES",row.names = FALSE)
# Read RES_GWAS
###############
#GWAS_RES <- read.csv("~/Documents/Teaching/GIGA_Doctoral_School/Intuitive_statistics/R_INT_STAT/GWAS_RES")
#View(GWAS_RES)

Run this R chunk to import precomputed results and import them in RES_GWAS

# Read RES_GWAS
###############
GWAS_RES <- read.csv("~/Documents/Teaching/GIGA_Doctoral_School/Intuitive_statistics/R_INT_STAT/GWAS_RES")
#View(GWAS_RES)
RES_GWAS[,14] <- GWAS_RES[,14]
#RES_GWAS
# Compare the p-values obtained with the different approaches
#############################################################
plot(RES_GWAS[,11],RES_GWAS[,14],col="red")
points(RES_GWAS[,13],RES_GWAS[,14],col="green")
points(RES_GWAS[,11],RES_GWAS[,13],col="black")

# Compare the Manhattan plots obtained with the different approaches
####################################################################
plot(RES_GWAS[,1],RES_GWAS[,11],col="red", xlab = "ORDERED SNPs", ylab = "-log(p)")
abline(h = -log10(0.05), lty = 4)
points(RES_GWAS[,1],RES_GWAS[,13],col="green")
points(RES_GWAS[,1],RES_GWAS[,14],col="black")

In this case, the p-values obtained by permutation are very similar to those obtained with the other approaches [at least for p-values > 1/(number of permutations)] . But this is not always the case. Assuming that the permutation tests was properly executed, it is the most trustworthy. As you can see, a disadvantage of the permutation test is that it may be time consuming with large datasets (as is the case for GWAS).

CORRECTING FOR FIXED EFFECTS IN PERMUTATION TESTS

Finding a significant association between a SNP and a disease suggests that the SNP may perturb the function of a nearby gene (i.e. in cis) hence increasing disease risk. Indeed, uncovering such scenarios is the main reason why these experiments are conducted in the first place. However, one has to be cautious in interpreting the results, as more trivial explanation may account for the observed association. One of these is so-called population stratification. As an example, the case-control cohort may combine samples originating from different countries. The frequency of the a allele may differ between countries as a results of random drift. If the proportion of cases vs controls differs between countries, these two factors combined may cause a difference in the frequency of the a allele between “all” cases and “all” controls (i.e. across countries) that is not reflecting a genuine “causal” association with disease, but rather population stratification. There are several ways to correct for stratification. As we are discussing the permutation test here, we will only describe a way to ajust the permutation test to account for possible “confounding” effects. What one can do in the example cited above (i.e. an association study conducted with samples originating from different countries having different case vs control ratios) is to perform the permutations within country (i.e. within “strata”). By doing so, the permutations remain “affected” by the same stratification problem as the real data. Thus the delta’s obtained from the permuted data will tend to be inflated as well (as a result of stratification). The delta seen with real data will therefore not be seen as particularly exceptional in regard to the distribution of delta’s obtained across the permutations. Hence, the corresponding p-value will not be deemed particularly small nor interesting.

EXERCICE

As an exercice, you may want to write an R script that permutes for instance within sex in the GWAS dataset.

Correcting for multiple testing

PLAYING WITH COINS AGAIN

Let us go back to our one Euro coins. We will each toss our Euro coin 50 times, record the number of heads, and compute the corresponding p-value, i.e. assuming that our Euro is balanced. I assume (there should be around 20 students in the room) that we will observe that - for at least one of us - the p-value turns out to be <= 0.05. Are there thus “unbalanced”" euro coins in circulation? Or not?

Let us ask the computer. We will simulate what we just did in the room for 10, 20, 30, … 100 students and see how many coins are - on average - declared “unbalanced” (p <= 0.05) per “class”. Given that we simulated balanced coins in the computer (and assuming we did this correctly) these apparently unbalanced coins should all be false positives.

# Building a function that mimics series of "heads and tail"
############################################################
nr_tosses = 300
series <- sample(0:1,nr_tosses, replace = TRUE)
series
  [1] 1 1 0 1 1 1 1 1 0 1 0 0 1 0 1 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1 0 0 0 0 1 0
 [37] 0 1 0 1 1 0 0 1 1 0 1 0 1 1 1 0 1 1 1 0 0 1 1 1 0 0 0 0 1 0 0 1 1 1 1 1
 [73] 0 1 0 0 1 0 0 1 0 1 0 0 1 1 1 0 0 0 1 1 0 0 1 0 1 0 1 1 0 1 0 0 0 0 1 1
[109] 1 0 1 0 1 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1 0 1 1 1 1 0 0 0 0 1 0 1 0 1 1
[145] 1 0 1 0 0 0 0 0 0 1 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0
[181] 0 0 0 0 1 0 1 1 0 0 0 1 0 0 1 0 1 0 1 0 0 0 1 0 1 0 1 1 0 1 1 1 0 0 1 0
[217] 1 0 1 0 1 0 1 1 0 0 1 1 1 1 0 0 0 1 0 1 1 0 1 1 0 0 1 0 1 1 0 1 1 0 0 1
[253] 1 0 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 1
[289] 1 1 0 0 0 1 1 1 0 0 0 0
nr_heads <- sum(series)
nr_heads
[1] 138
bin_test <- binom.test(x = nr_heads, nr_tosses, p = 0.5, alternative = "two.sided")
bin_test <- binom.test(x = sum(sample(0:1,nr_tosses, replace = TRUE)), nr_tosses, p = 0.5, alternative = "two.sided")
bin_p <- bin_test$p.value
bin_p
[1] 1
coin_test <- function(n){
  bin_test <- binom.test(x = sum(sample(0:1,n, replace = TRUE)),n , p = 0.5, alternative = "two.sided")
  bin_p <- bin_test$p.value
  bin_p
}
coin_test(nr_tosses)
[1] 0.2726299
# Applying the test to classes ranging from 120 to 100 students, with 100 repetitions
######################################################################################
NR_FP<-matrix(1:1000, nrow=100, byrow=TRUE)
#NR_FP <-data.frame(ST10=1:1000,ST20=0,ST30=0,ST40=0,ST50=0,ST60=0,ST70=0,ST80=0,ST90=0,ST100=0)
for (i in 1:100){
  for (j in 1:10){
    stud_ser <- replicate(j*10,coin_test(nr_tosses))
    NR_FP[i,j] <- sum(stud_ser <= 0.05)
  }
}
head(NR_FP,3)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    2    1    2    1    0    4    2    3    3     3
[2,]    0    0    1    1    4    1    0    2    2     7
[3,]    1    0    1    1    4    3    2    4    2     7
boxplot(NR_FP)
for (i in 1:10){
  mean_fp <- mean(NR_FP[,i])  
}
mean_fp
[1] 4.42

Thus, even when all coins are balanced, a certain proportion of students will throw a series of heads and tails with p <= 0.05 under the null. In the example, this proportion is of the order of 0.83 students on average per class of 20, and 4 students on average per class of 100. You will notice that this value is slighltly below 5%.

In fact, and by definition, we expect 5% of the realized tests to be significant at the 5% level, i.e. with p <= 0.05. Using this threshold, we expect to have one false-postive every 20 tests, i.e. the Type I error rate.

The reason why we observed a slightly lower Type I error rate in the example reflects some idiosyncrasies of the binomial distribution. If we increase the size of the series (i.e. the number of tosses), we indeed obtain very close to the expected Type Error rate of I with “nominal” p-value threshold of 0.05.

nr_tosses=15000
sum(sample (x=0:1,size=nr_tosses, replace=TRUE))
[1] 7560
replicate(20,2*pbinom(nr_tosses/2-abs(sum(sample (x=0:1,size=nr_tosses, replace=TRUE))-nr_tosses/2),size=nr_tosses,prob=0.5))
 [1] 0.62999710 0.60697883 0.96743573 0.65338035 0.25640378 0.92843492
 [7] 0.01749831 0.45747560 0.43794384 0.36477163 0.72551946 0.24962436
[13] 0.70116258 0.11506006 0.59561237 0.64164430 0.59561237 0.36477163
[19] 0.12679585 0.49796819
psim2<-replicate(20000,2*pbinom(nr_tosses/2-abs(sum(sample (x=0:1,size=nr_tosses, replace=TRUE))-nr_tosses/2),size=nr_tosses,prob=0.5))
hist(psim2,breaks=seq(-0.1,1.1,0.05), border = "red")

The graph shows that the distribution of p-values under the null is “uniform”, i.e. 5% of the tests have p-value 0 < p < 0.05, 5% have p-value 0.05 < p < 0.10, 5% have p-value 0.10 < p < 0.15, etc … And this is exactly what one would expected given the very way the p-values were defined (think about this …).

A very common way to examine the distribution of p-values for a number of tests is by means of “QQ-plots” (or Quantile-Quantile Plots). The following code generates a QQ plot for the same set of simulations.

# Function generating a QQ plot of p-values "borrowed" from the internat
########################################################################
ggd.qqplot = function(pvector, main=NULL, ...) {
  o = -log10(sort(pvector,decreasing=F))
  e = -log10( 1:length(o)/length(o) )
  plot(e,o,pch=19,cex=1, main=main, ...,
       xlab=expression(Expected~~-log[10](italic(p))),
       ylab=expression(Observed~~-log[10](italic(p))),
       xlim=c(0,max(e)), ylim=c(0,max(o)))
  lines(e,e,col="red")
}
ggd.qqplot(psim2)

Clearly, we have to do something about this if we want to avoid generating false positives. If our experiment entails the realization of multiple tests (f.i. one experiment could be a class of 20 students realizing together 20 tests), we need to adjust the threshold value such that false positives are only expected once every 20 experiments. Such a threshold is referred to as an experiment-wide threshold. A test that yields a p-value < to this threshold is said to be experiment-wide significant. A test that yields a p-value < to the uncorrected (or nominal) significance threshold of 0.05 is said to be nominally significant. People sometimes also use suggestive thresholds. The suggestive threshold is expected to be “exceeded” on average once per experiment (under the null). I will not going in a detailed description of the suggestive threshold.

THE FACT THAT MANY SCIENTISTS DO NOT REALIZE THIS SUFFICIENTLY IS ONE OF THE MAIN CAUSES WHY TOO MANY RESULTS REPORTED IN THE LITERATURE ARE FALSE POSITIVES. JUST REALIZE 20 BOGUS TESTS (EXPRIMENTS) EVERY YEAR, APPLY A 5% SIGNIFICANCE THRESHOLD TO ALL YOUR TESTS, AND YOU ARE BOUND TO REPORT ONE FP IN YOUR YEARLY PAPER. I GUESS YOU MUST START TO SEE/FEEL ONE OF THE DIFFICULTIES: WHERE DO EXPERIMENTS BEGIN AND END? DO WE NEED A LIFE-TIME SIGNIFICANCE THRESHOLD?

How do we properly adjust the significance threshold when performing multiple tests?

Assume that we perform n tests, the adjusted threshold can be derived using Sidak’s correction:

0.05 = 1-(1-p_c)^n

hence corresponding to

p_c = 1 - 10^(log10(0.95)/n)

This threshold is more often approximated using the simpler Bonferroni correction:

p_c = 0.05/n

t = 0.05
SID_BON <- data.frame(n=1:1000,SIDAK=0,BONF=0,LSIDAK=0,LBONF=0)
SID_BON[,2] = round(1-10^(log10(1-t)/SID_BON[,1]),digits=10)
SID_BON[,3] = round(t/SID_BON[,1],digits=10)
SID_BON[,4] = -log10(1-10^(log10(1-t)/SID_BON[,1]))
SID_BON[,5] = -log10(t/SID_BON[,1])
SID_BON
plot(SID_BON[,4],SID_BON[,5],col="red", xlab = "L_SIDAK", ylab = "L_BONF")

plot(SID_BON[,1],SID_BON[,4], col="red", xlab = "N_tests", ylab = "L_BONF threshold")

The graphs show that (i) the Bonferroni correction is an excellent approximation, and (ii) the effect of the number of tests (X axis) on the p-value (in -log units) that needs to be applied to control the experiment-wide type I error at 0.05.

EXERCICE

Try to generate a small script that shows that when you apply Sidak’s or Bonferroni’s correction you only obtain false positives (FP) every 20 experiments conducted. Some experiments will yield 0 FP’s, some 1, some 2, some 3, … The threshold is such that the proportion of experiments with 0 FP corresponds to 95% of the experiments.

RETURNING TO GENETIC ASSOCIATION STUDIES

When performing “Genome-Wide Association Studies” or GWAS, one performs (as in all -omic studies) many, many tests (hundreds of thousands to millions). In this case, every SNP is tested for its association with the disease. Applying a nominal threshold of 0.05 is therefore bound to give a FP every 20 SNPs tested. We therefore have to correct the threshold accordingly to control the rate of FPs.

In the previous example we tested 420 SNPs. A simple way is therefore to correct the 0.05 threshold for the realization of 420 tests using either Sidak’s or Bonferroni’s equation.

plot(RES_GWAS[,1],RES_GWAS[,11],col="red", xlab = "ORDERED SNPs", ylab = "-log(p)")
abline(h = -log10(0.05))
abline(h = -log10(0.05/(nr_var)), lty = 2)

The plain horizontal line corresponds to the nominal (uncorrected) threshold of 0.05, while the dashed horizontal line corresponds the threshold, Bonferroni-corrected for the realization of 420 tests, that should control the experiment-wide false positive rate to no more than 0.05.

This may, however, be overkill. Indeed, our genome is characterized by a phenomenon called “linkage disequilibrium” or LD. This means that the genotypes of closely linked SNPs are “correlated”, i.e. they can be very similar to each other. Individuals that are heterozygous for the first SNP (say with alleles A and a) will tend to be heterozygous for the second SNP (say with alleles B and b). Individuals that are homozygous AA may tend to be more often bb than expected by chance. In other words, the genotypes at the “A” and “B” SNPs are not independent. At the extreme (“perfect LD”) the genotypes of two adjacent SNPs may be perfectly redundant in the studied cohort(s): if you know one, you can perfectly predict the other. Two SNPs in perfect LD clearly do not correspond to two different tests; they are one and the same. If x such pairs existed in our dataset, the actual number of realized tests would by 420-x, hence yielding a less stringent experiment-wide threshold (often referred to as genome-wide in the case of GWAS).

For two SNPs that are not perfectly redundant, yet still in LD, the outcome of the association test will tend to be correlated. They can not be seen as two independent tests either. Together, they account maybe for 1.5 but not for 2 tests. The question thus becomes: to how many independent tests does our little GWAS corresponds? If we knew that we could apply to appropriate Sidak/Bonferroni correction to determine the correct experiment-wide threshold.

There are a number of ways to achieve this. Permutation testing provides a very interesting way to correct for the effective number of tests performed, as we will now see.

We previously (see above) used a permutation test to evaluate the significance of the association between one SNP and the disease. The affection status was shuffled across the individuals hence disconnecting any possible relationship between genotype and phenotype (= disease). We are going to do the same thing here, but rather than testing one SNP only, we are going to test all the SNPs with the same phenotype permutation. Thus we are going to perform the same multiple tests as we did with the real data. We want to ensure that the correlation structure between tests that existed with the real data (due to LD between the SNPs), is faithfully maintained in the permutations. Thus, we shuffle the phenotypes between the individuals, but the “vectors” of individual genotypes remain unaltered. Thus, if the Aa genotype at SNP “A” was preferentially associated with the Bb genotype at SNP “B” in the real data, this will remain so in the permuted data.

We still want to compare the allelic frequencies between cases and controls in the permutations. But this time, we have to pay attention that our measure be comparable across SNPs. It shouldn’t for instance be dependent on f_a, which delta is. A good idea in this case is to find inspiration in classic statistics, i.e. use the transformations similar to those yielding the chi-squared, t and F test, or even the ensuing p-values. This is what I will be doing here, using the “CT” test.

Thus, for each permutation we will keep the best p-value (or -log(p-value)). If we perform n_perm such permutations, we will therefore end up with a list of n_perm best p-values. We can rank or sort these best p-values. The 5% experiment-wide significance threshold then corresponds to the 5% percentile of this list, i.e. a value that was only “matched” or “exceeded” (meaning an equal or lower best p-value found) for 5% of permutations. [We can do the same thing using -log(p) values, and determine the 95% percentile]. Thus, this is an elegant way to determine the experiment-wide significance threshold that appropriately corrects for the number of tests that were performed and their correlations.

We can use the same approach to determine the corrected p-value for each SNP. One just has to determine in what fraction of the permutations an equally “good” or “better” p-value (or -log(p)) value was obtained. It is noteworthy that accurate estimation of small (experiment-wide) p-values by permutations requires running a commensurate number of them.

Let us illustrate this with real data.

# Previous mini Manhattan plot with nominalk and Sidak/Bonferroni corrected significance thresholds
###################################################################################################
plot(RES_GWAS[,1],RES_GWAS[,11],col="red", xlab = "ORDERED SNPs", ylab = "-log(p)")
abline(h = -log10(0.05))
abline(h = -log10(0.05/(ncol(GWAS)-3)), lty = 2)

# Generating a data frame (with same structure as RES_GAWAS) to store the results of the permutations (SH-uffles)
################################################################################################################## 
SH_GWAS <- data.frame(SNP = 1:(ncol(GWAS)-3), CHR = 0, POS=0, NR_GEN_CTR=0, ALT_FR_CTR=0, NR_GEN_CAS=0, ALT_FR_CAS=0, ALT_FR_ALL=0, 
                      CHISQ=0, LP_CHISQ=0, LP_CHISQ_2=0, LRT=0, LP_LRT=0, LP_PERM=0)
SH_GWAS
# Define function to compute p-value based on CT test
#####################################################
mychi_sh <- function(i){
  ct<-matrix(c(2*SH_GWAS[i,4]*SH_GWAS[i,5],2*SH_GWAS[i,4]*(1-SH_GWAS[i,5]),2*SH_GWAS[i,6]*SH_GWAS[i,7],2*SH_GWAS[i,6]*(1-SH_GWAS[i,7])), nrow=2, byrow=TRUE)
  Xsq <- chisq.test(ct,correct=FALSE)
  Xsq$p.value
}
# Compute relevant stats for all SNPs (We will use the CT test in this example)
###############################################################################
for (i in 1:nr_var){
  SH_GWAS[i,4] = sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 1, na.rm = TRUE)
  SH_GWAS[i,5] = round(sum(GWAS[,i+3][GWAS[,3] == 1], na.rm = TRUE)/(2*SH_GWAS[i,4]),digits=3)
  SH_GWAS[i,6] = sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 2, na.rm = TRUE)
  SH_GWAS[i,7] = round(sum(GWAS[,i+3][GWAS[,3] == 2], na.rm = TRUE)/(2*SH_GWAS[i,6]),digits=3)
  SH_GWAS[i,11] = -log10(mychi_sh(i))
}
SH_GWAS
# Define function to generate shuffled data, compute the corresponding stats FOR ALL SNPs (vs previous function), 
#and extract the top -log(p) value acroos all SNPs
#################################################################################################################
shuffle_2 <- function(){
  GWAS[,3] <- sample(AFF_STATUS,size = 4000,replace = FALSE)
  for (i in 1:nr_var){
    SH_GWAS[i,4] = sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 1, na.rm = TRUE)
    SH_GWAS[i,5] = round(sum(GWAS[,i+3][GWAS[,3] == 1], na.rm = TRUE)/(2*SH_GWAS[i,4]),digits=3)
    SH_GWAS[i,6] = sum((GWAS[,i+3] == 0 | GWAS[,i+3] == 1 | GWAS[,i+3] == 2) & GWAS[,3] == 2, na.rm = TRUE)
    SH_GWAS[i,7] = round(sum(GWAS[,i+3][GWAS[,3] == 2], na.rm = TRUE)/(2*SH_GWAS[i,6]),digits=3)
    SH_GWAS[i,11] = -log10(mychi_sh(i))
    assign("SH_GWAS",SH_GWAS,envir = globalenv())
  }
  MAX <- max(SH_GWAS[,11])
  MAX
  #list(ran.in = environment(),parent = parent.env(environment()), objects = ls.str(environment()))
}
# Note that the outcome of the loop needs to be assigned to GWAS in globalenv
# Perform permutations and generate list of best p-values
#########################################################
nr_perm=100
mult_test <- replicate (nr_perm,shuffle_2())
mult_test
  [1] 7.781412 1.789614 2.404158 2.939171 1.856394 2.309214 3.151856 1.973791
  [9] 2.534976 3.410673 2.990641 1.534577 1.906961 2.242938 2.177275 1.593806
 [17] 2.702784 4.238273 1.719955 2.249026 2.430571 4.190491 2.007094 2.539132
 [25] 2.705255 1.960397 3.312652 2.640095 2.742447 2.007550 2.213136 1.851350
 [33] 2.730949 1.991178 2.960982 3.926220 1.905751 3.039103 1.893748 1.840908
 [41] 2.335767 2.573776 2.817796 2.832877 2.204520 2.119171 2.061094 2.122357
 [49] 1.626046 2.750356 1.582762 1.717207 3.577824 2.816531 1.980708 3.279910
 [57] 2.977770 4.502004 2.888258 2.532667 3.150311 2.328889 2.594226 2.721036
 [65] 1.425274 2.172181 2.072350 1.954385 2.453251 3.113615 2.594229 1.665414
 [73] 2.885086 1.954591 2.147106 1.656673 2.601734 1.443936 1.748885 1.819391
 [81] 2.223627 2.334531 1.945039 3.982961 2.442108 2.306314 2.256293 1.817003
 [89] 2.042623 2.055231 3.390739 2.165115 1.680421 1.884140 1.872650 2.257531
 [97] 2.284148 2.188978 2.810305 2.835514
# Extract experiment-wide threshold
###################################
mt_thresh <- quantile(mult_test,0.95)
mt_thresh
     95% 
3.929058 
# Add new threshold to mini Manhattan plot
##########################################
plot(RES_GWAS[,1],RES_GWAS[,11],col="red", xlab = "ORDERED SNPs", ylab = "-log(p)")
abline(h = -log10(0.05))
abline(h = -log10(0.05/nr_var), lty = 2)
abline(h = mt_thresh, lty = 4)
# Determine corrected p-values for indivdiual SNPs
##################################################
x=5.495316e+00
mult_test
  [1] 7.781412 1.789614 2.404158 2.939171 1.856394 2.309214 3.151856 1.973791
  [9] 2.534976 3.410673 2.990641 1.534577 1.906961 2.242938 2.177275 1.593806
 [17] 2.702784 4.238273 1.719955 2.249026 2.430571 4.190491 2.007094 2.539132
 [25] 2.705255 1.960397 3.312652 2.640095 2.742447 2.007550 2.213136 1.851350
 [33] 2.730949 1.991178 2.960982 3.926220 1.905751 3.039103 1.893748 1.840908
 [41] 2.335767 2.573776 2.817796 2.832877 2.204520 2.119171 2.061094 2.122357
 [49] 1.626046 2.750356 1.582762 1.717207 3.577824 2.816531 1.980708 3.279910
 [57] 2.977770 4.502004 2.888258 2.532667 3.150311 2.328889 2.594226 2.721036
 [65] 1.425274 2.172181 2.072350 1.954385 2.453251 3.113615 2.594229 1.665414
 [73] 2.885086 1.954591 2.147106 1.656673 2.601734 1.443936 1.748885 1.819391
 [81] 2.223627 2.334531 1.945039 3.982961 2.442108 2.306314 2.256293 1.817003
 [89] 2.042623 2.055231 3.390739 2.165115 1.680421 1.884140 1.872650 2.257531
 [97] 2.284148 2.188978 2.810305 2.835514
(mult_test >= x)
  [1]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [97] FALSE FALSE FALSE FALSE
sum(mult_test >= x)
[1] 1
sum(mult_test >= x)/nr_perm
[1] 0.01
-log10(sum(mult_test >= x)/nr_perm)
[1] 2
for (i in 1:nr_var){
  if (sum(mult_test >= RES_GWAS[i,11]) == 0){
    RES_GWAS[i,15] = -log10(1/nr_perm)
  } else {
    RES_GWAS[i,15] = -log10(sum(mult_test >= RES_GWAS[i,11])/nr_perm)
  }
}
RES_GWAS
# Add corrected p-values to Manhattan plot
###########################################
points(RES_GWAS[,1],RES_GWAS[,15],col="black")

Exploiting the distribution of observed p-values to estimate the False Discovery Rate or FDR

In the previous sections, we came to realize that multiple testing is an important issue that needs to be addressed by adjusting the significance thresholds accordingly. To do this, we determined the (effective) number of test performed (one way or the other) and then corrected the thresholds (one way or the other).

A quite radically different and interesting approach consists in examining the distribution of nominal p-values, see how it compares with the uniform distribution expected if all performed tests are real H0 test (see above), and learn from it.

Let us go back to our Euro coins, and first re-generate the uniform distribution of p-values expected if all coins are balanced. As above, I will test 20,000 coins by tossing each of them 15,000 times.

# Generating the distribution of p-values for 20,000 balanced coins
###################################################################
nr_dr=15000
sum(sample (x=0:1,size=nr_dr, replace=TRUE))
[1] 7643
replicate(20,2*pbinom(nr_dr/2-abs(sum(sample (x=0:1,size=nr_dr, replace=TRUE))-nr_dr/2),size=nr_dr,prob=0.5))
 [1] 0.85103876 0.33942574 0.48766961 0.29975865 0.61844117 0.76257415
 [7] 0.20566566 0.86385944 0.21157597 0.27750486 0.47748708 0.04041883
[13] 0.75015721 0.26331002 0.33123434 0.19987625 0.96743573 0.05100267
[19] 0.55114826 0.33123434
psim2<-replicate(20000,2*pbinom(nr_dr/2-abs(sum(sample (x=0:1,size=nr_dr, replace=TRUE))-nr_dr/2),size=nr_dr,prob=0.5))
hist(psim2,breaks=seq(-0.1,1.1,0.05), border = "red", xlab = "Binned p-values")

We will now repeat the experiment with 20,000 unbalanced coins. The probability to obtain heads is slighly increased to 0.51 (instead of 0.5 for balanced coins).

# Generating the distribution of p-values for 20,000 unbalanced coins
#####################################################################
nr_dr=15000
sum(sample (x=0:1,size=nr_dr, replace=TRUE, prob = c(0.49,0.51)))
[1] 7555
replicate(20,2*pbinom(nr_dr/2-abs(sum(sample (x=0:1,size=nr_dr, replace=TRUE, prob = c(0.49,0.51)))-nr_dr/2),size=nr_dr,prob=0.5))
 [1] 2.091127e-06 2.371302e-02 1.409665e-03 1.227846e-01 1.122022e-03
 [6] 2.847943e-01 4.326498e-04 2.794332e-04 1.463076e-02 3.884984e-02
[11] 3.747347e-03 2.450887e-03 1.041960e-01 2.176697e-02 2.371302e-02
[16] 2.272190e-02 1.832235e-01 8.200710e-02 3.374962e-03 4.606238e-03
psim3<-replicate(20000,2*pbinom(nr_dr/2-abs(sum(sample (x=0:1,size=nr_dr, replace=TRUE, prob = c(0.49,0.51)))-nr_dr/2),size=nr_dr,prob=0.5))
hist(psim3,breaks=seq(-0.1,1.1,0.05), border = "red", xlab = "Binned p-values")

The distribution is severely shifted towards lower p-values suggesting either that our statistical test has a problem, or (as is the case here) that many of our tests (in this case all) are true H1 hypotheses.

Let us know simulate a situation that resembles what we often face in the real world, i.e. that the tests performed include both true H0 and true H1. The proportion of true H0 is often referred to as “pi0”. In the following example “pi0” is simulated to be approximately 50%.

# Generating the distribution of p-values for a mixture of balanced and unbalanced coins
########################################################################################
mixt <- function(){
  if (runif(1,0,1) > 0.5){
    2*pbinom(nr_dr/2-abs(sum(sample (x=0:1,size=nr_dr, replace=TRUE))-nr_dr/2),size=nr_dr,prob=0.5)
  } else{
    2*pbinom(nr_dr/2-abs(sum(sample (x=0:1,size=nr_dr, replace=TRUE, prob = c(0.49,0.51)))-nr_dr/2),size=nr_dr,prob=0.5)
  }
}
nr_dr=15000
nr_exp=20000
psim4 <- replicate(nr_exp,mixt())
hist(psim4,breaks=seq(-0.1,1.1,0.05), border = "red", xlab = "Binned p-values")

The distribution remains heavily shifted towards low p-values due to the high proportion of H1 hypotheses amongst the tests. We normally expect around 1,000 observations per 5% bin under the null. This is approximately the case for bins with p-values > 0.3 in our example. But bins with p-values < 0.3 tend to be over-represented. The first bin, for instance,contains > 7,000 observations, while only 1,000 are expected under the null. Thus, we can reasonably conclude that in this bin approximately 6 out of 7 tests probably correspond to true H1 hypotheses. Or stated otherwise, if we select the tests in the first bin as potentially interesting (we tend to reject the null hypothesis), given the observed distribution of p-values, the proportion of false positives in this bin will be approximately 1 in 7. The right way to say this is that, in the first bin, the False Discovery Rate (FDR) has to be approximately 1/7.

Let us compute this a bit more accurately:

# Computing the FDR for the group of tests in the 0-0.05 bin
############################################################
sum(psim4 <= 0.05)
[1] 7294
FDR = (nr_exp*0.05)/sum(psim4 <= 0.05)
FDR
[1] 0.137099

Another common way to look at this distributions is by means of the QQ plots that were already discussed before.

# QQ plot for mixture of balanced and unbalanced coins
######################################################
ggd.qqplot = function(pvector, main=NULL, ...) {
  o = -log10(sort(pvector,decreasing=F))
  e = -log10( 1:length(o)/length(o) )
  plot(e,o,pch=19,cex=1, main=main, ...,
       xlab=expression(Expected~~-log[10](italic(p))),
       ylab=expression(Observed~~-log[10](italic(p))),
       xlim=c(0,max(e)), ylim=c(0,max(o)))
  lines(e,e,col="red")
}
ggd.qqplot(psim4)

In the previous example, we computed the FDR for the group of tests falling in the lowest bin. We can also compute the FDR for individual tests. These values correspond to so-called q-values. This is in fact a bit misleading. As you will soon understand, the q-value computed for an individual test is actually the joint FDR for all the test with p-value equal or smaller than the examined one. Let us compute the q-values for the “psim4” (mixed balanced and unbalanced coins) dataset.

# Computing anb examining q-values
###################################
#psim4
rank_sim4<-rank(psim4,na.last = TRUE, ties.method = "random")
#rank_sim4
#sort_sim4<-sort(psim4,decreasing=FALSE)
#sort_sim4
fdr<-(nr_exp*psim4)/rank_sim4
lpsim4<-log10(1/psim4)
lfdr<-log10(1/fdr)
#plot(lpsim4,lfdr)
#bonf<-psim4*nr_exp
#lbonf<-log10(1/bonf)
#plot(lbonf,lpsim4)
sid<-1-(1-psim4)^nr_exp
lsid<-log10(1/sid)
#plot(lsid,lpsim4)
plot(lsid,lfdr)

[+ interpretation]

As a matter of fact we can do better. From the distribution of p-values, we can have an idea of “pi0”, i.e. the proportion of H0 hypotheses amongst the realized tests. We will assume for that, that the “high p-value bins”" primarily encompass H0 hypotheses. Indeed, typically the height of these bins “flattens out”. Thus the average proportion of observations in these bins multiplied by the total number of bins (say 20) gives us an estimate of the proportion of H0 hypotheses in the data. This estimate can then be used to compute improved q-values. The idea behind this approach is described in Storey et al. (2003)[https://www.ncbi.nlm.nih.gov/pubmed/12883005].

Let us implement it to our psim4 data, using Storey’s software, which we will first install.

# Installing Storey's package
#############################
#install.packages("devtools")
library("devtools")
#install_github("jdstorey/qvalue")
library(qvalue)

While playing with this I realized that psim4 contains values > 1. We will first correct these values and set them to 1.

# Eliminating p-values > 1 from psim4
#####################################
max(psim4)
[1] 1.006515
psim4[psim4>1]<-1
max(psim4)
[1] 1

We will then recompute FDR’s using “our” method.

# Computing FDR with "our" method
##################################
rank_sim4<-rank(psim4,na.last = TRUE, ties.method = "random")
#rank_sim4
fdr<-(nr_exp*psim4)/rank_sim4
lfdr<-log10(1/fdr)

Let us now use Storey’s program.

# Computing FDR with Storey's method
#####################################
qobj <- qvalue(p = psim4)
#qobj
lq<-log10(1/qobj$qvalues)
lp<-log10(1/qobj$pvalues)

We can now compare the two sets of values.

plot(lfdr,lq)
lines(lfdr,lfdr,col = "red")

We can also use Storey’s program to estimate pi0 values.

# Generating the distribution of p-values for a mixture of balanced and unbalanced coins
########################################################################################
mixt <- function(pi_zero){
  if (runif(1,0,1) < pi_zero){
    2*pbinom(nr_dr/2-abs(sum(sample (x=0:1,size=nr_dr, replace=TRUE))-nr_dr/2),size=nr_dr,prob=0.5)
  } else{
    2*pbinom(nr_dr/2-abs(sum(sample (x=0:1,size=nr_dr, replace=TRUE, prob = c(0.49,0.51)))-nr_dr/2),size=nr_dr,prob=0.5)
  }
}
nr_dr=15000
nr_exp=10000
psim_series <- data.frame(V0=1:nr_exp,V25=0,V50=0,V75=0,V100=0)
#psim_series
for (i in 1:5){
  psim_series[,i] <- replicate(nr_exp,mixt(pi_zero = 0.10*(i-1)))
}
#psim_series
pi0 = data.frame(V1=0:1,V2=NA,V3=NA,V4=NA,V5=NA)
for (i in 1:5){
  pi0[1,i] = 0.10*(i-1)
  psim_series[,i][psim_series[,i]>1]<-1
  qobj <- qvalue(p = psim_series[,i])
  pi0[2,i]<-qobj$pi0
}
pi0

In these simulations, Storey’s program seem to slightly but systematically overestimate pi0 … :-)

Examples of the design and use of empirical statistical test in genome studies

  1. Rosewick, N. et al. Cis-perturbation of cancer drivers by the HTLV-1/BLV proviruses is an early determinant of leukemogenesis. Nat Commun 8:15264 (2017) [https://www.nature.com/articles/ncomms15264]

This paper makes extensive use of simulations to evaluate the statistical significance of genomic features associated with BLV proviral insertion sights. The BLV and HTLV-I retroviruses cause leukelia in cattle/sheep and human, respectively, and this after a long incubation period. It was previously assumed that the proviral integration site was random, and that tumor development was due to (i) the transformation potential of virus-encoded proteins including Tax in the early phases of the disease, and (ii) somatic mutations accruing in cancer driver genes across the genome in the later stages of the disease. This paper shows that the integration of BLV proviruses in sheep is absolutely not random. Proviruses tend to preferentially “land” in hotspots of integration. Moreover, these hotspots are enriched in known cancer driver genes, strongly suggesting that the integration site contributes to early cell transofmration. Simulation was used in several experiments to evaluate the statistical significance of the observed proviral clustering.

Identifying integration hotspots: “Hotspots were then defined as follows: for each IS we counted the number of IS located in a 50 kb window centred on that IS. We then randomly picked 66,557 IS in the ovine genome, performed the same counting procedure and retained the simulated IS window harbouring the highest number of IS. We performed N=1,000,000 iterations of this procedure to generate a distribution reflecting random integration. We then assigned a P-value to each IS. Hotspots were defined by grouping consecutive IS windows that showed a P-value <= 0.05, the position of the two extreme IS 5 kb determining the boundaries of the hotspot.”

  1. Rossin, E.J. et al. Proteins encoded in genomic regions associated with immune-mediated disease physically interact and suggest underlying biology. PLoS Genetics 7: e1001273 (2011) [https://journals.plos.org/plosgenetics/article?id=10.1371/journal.pgen.1001273]

“Therefore, we apply a permutation method that is robust to non-specific binding and differences in publication density. We perform a within-degree node-label permutation that is carried out as follows: a random network is built that has nearly the exact same structure as the original InWeb network, only the node labels (i.e. the protein names) are randomly re-assigned to nodes of equal binding degree; this method assumes a null distribution of connectivity that is entirely a function of the binding degree of individual proteins. Random networks will have the same size, number of edges and per-protein binding degree as InWeb; we build 50,000 different random networks. With this method, we are able to test the non-randomness of our network conditional on the exact binding degree distribution of our disease proteins.”

The winners’ curse

In the previous section we showed how not properly accounting for multiple testing is a common source of false positive, i.e. non reproducible results. Another possible cause of the apparent non-reproducibility of results is when experiments are “underpowered”. This is well illustrated in GWAS studies. Several groups around the world initially performed “their own” GWAS, i.e. they assempled a case-control cohort of - say - 1,000 cases and 1,000 controls - and ran their own analyses. This would typically yield one or two genome-wide significant signals. All of these discoveries were accompanied by a confirmation in an independent “confirmation” cohort, hence strongly supporting their genuine nature [Note that the significance thresholds used in the confirmation step are “leanier” as much fewer tests are conducted in the confirmation than in the discovery phase]. Yet, the signals that were discovdered in these initial GWAS nearly always differed between studies. Why is that?
The reason is that the SNP effects were smaller than anticipated. As a result, the initial GWAS studies were initially “underpowered” to detect them. Assuming that you only have 10% power to detect the signals of interest given your sample size, you will by definition only find 10% of the existings signal in your study. Your colleague, who is in the same situation, may by chance detect another of the existing signals in hers/his study, etc. What lies behind the “by chance” statement in this context? Well to detect a signal in an underpowered study, the corresponding effect has to be “accidentally” slightly inflated in that study. Otherwise it would not exceed the significance threshold. This is the essence of what is commonly referred to as the winners’ curse. That the effects are indeed inflated in the discovery phase is confirmed when re-estimating the effect in the confirmation cohort: they are nearly always inferior to what they were in the discovery phase. All this made people quickly realize that salvation lays in collaboration. A new layer of effects that would be impossible to detect in individual studies indeed emerged when performing meta-analayses by merging the indiviual datasets. This is indeed what happened for nearly all studied diseases, yielding an amazing “crop” of GWAS hits for nearly all of them [see EBI’s GWAS catalog at https://www.ebi.ac.uk/gwas/].

Let us explore this a bit more quantitatively. We are going to simulate the identification, by association study, of a genetic variant affecting a quantitative trait. For simplicity we are going to assume that we work with a haploid organism. Thus the genotype of individuals is either A (“0” in the simulations) or a (“1” in the simulations). We will set the frequency of the a allele at 0.25 (the script below allows to vary f_a as well as to test a range of values). We will assume that the trait of interest is normally distributed with mean 0 and standard deviation 1 within genotype (i.e. “residual” variance). We will assume that the effect of the a allele is to increase the phenotype by delta. In our simulations, delta will vary from say 0.25 to 1 residual standard deviation. We will vary the sample size from, say 200 to >1,400. We will test the significance of the effect in our simulated data set using a t-test. We will select a significance threshold (f.i. p < 0.000001) to decide whether delta is significant or not. We will examine the impact of the studied parameters on (i) the power to detect the signal at the chosen significance threshold, (ii) the impact of power on the estimate of delta.

The following code may take a long time to run if run large numbers of simulations. If you prefer not to run it now, you can go to the next “R chunk” to import precomputed results.

# Set all_comb at zero prior to starting
########################################
all_comb = NULL
# Select parameter (allele freqiency, size of the effect, sample size) space which you want to explore
######################################################################################################
freq<-c(0.25)
effect<-c(0.20,0.30,0.40,0.50,0.60,0.70,0.80,0.90,1)
ssize<-c(200,400, 600, 800, 1000, 1200, 1400)
# Generate all_comb matrix using "expand" such that all possible paremeter combinations correspond to one row
#############################################################################################################
all_comb<-expand.grid(freq,effect,ssize)
all_comb[,4:9]=0 # I just put some columns in which I will do additions at zero. May not be necessary 
names(all_comb)=c("AF","EFF","SS","AD","SUCC","DS","ADP","SUCCP","DSP")
# Select significance threshold to use
######################################
p_tresh=0.000001
# Generate function to simulate a population with given values to be found in all_comb and perform its analysis
###############################################################################################################
run_sim<-function(j){
  sim=NULL
  # Generate a data.frame in which to store individual information
  sim<-data.frame(GEN=1:all_comb[j,3],RES=NA,PHEN_0=NA,PHEN_1=NA)
  sim$GEN=sample(x=0:1,size=all_comb[j,3],replace=TRUE, prob = c(1-all_comb[j,1],all_comb[j,1]))
  sim$RES=rnorm(all_comb[j,3],0,1)
  sim$PHEN_0 = sim$RES
  sim$PHEN_1 = sim$RES+all_comb[j,2]
  sim$PHEN_0[sim$GEN==1] = NA
  sim$PHEN_1[sim$GEN==0] = NA
  # Calculate realized delta
  delta = mean(sim$PHEN_1,na.rm = TRUE) - mean(sim$PHEN_0,na.rm = TRUE)
  # Store realized data in appropriate place in all_comb
  all_comb[j,4]=all_comb[j,4]+delta
  # test significance of delta using t-test    
  t_res<-t.test(sim$PHEN_0,sim$PHEN_1, alternative = "two.sided")
  # Record whether significant and if it is, store results in appropriate place in all_comb
  if (t_res$p.value < p_tresh){
    all_comb[j,5]=all_comb[j,5]+1
    all_comb[j,6]=all_comb[j,6]+delta
  } 
  # Reset SIM
  sim=NULL
  # Transfer results to globalenv
  assign("all_comb",all_comb,envir = globalenv())
}
# Define numner of simulations to perform and run these one row at a time
#########################################################################
nr_sims = 20000
for (j in 1:nrow(all_comb)){
  replicate(nr_sims,run_sim(j))
}

Run this R chunk to import precomputed results

# Load precomputed all_comb fine
################################
all_comb <- read.csv("~/Documents/Teaching/GIGA_Doctoral_School/Intuitive_statistics/R_INT_STAT/WIN_CURSE")
#View(all_comb)
# Generate plots
################
plot(all_comb[1:9,2],all_comb[1:9,2],type = "l", xlab = "Real effect",ylab = "Estimated effect / Power", col = "red")
lines(all_comb[1:9,2],all_comb[1:9,9], col = "#08306B")
lines(all_comb[10:18,2],all_comb[10:18,9], col = "#08519C")
lines(all_comb[19:27,2],all_comb[19:27,9], col = "#2171B5")
lines(all_comb[28:36,2],all_comb[28:36,9], col = "#4292C6")
lines(all_comb[37:45,2],all_comb[37:45,9], col = "#6BAED6")
lines(all_comb[46:54,2],all_comb[46:54,9], col = "#9ECAE1")
lines(all_comb[55:63,2],all_comb[55:63,9], col = "#C6DBEF")
lines(all_comb[1:9,2],all_comb[1:9,8], col = "#08306B", lty = 2)
lines(all_comb[10:18,2],all_comb[10:18,8], col = "#08519C", lty = 2)
lines(all_comb[19:27,2],all_comb[19:27,8], col = "#2171B5", lty = 2)
lines(all_comb[28:36,2],all_comb[28:36,8], col = "#4292C6", lty = 2)
lines(all_comb[37:45,2],all_comb[37:45,8], col = "#6BAED6", lty = 2)
lines(all_comb[46:54,2],all_comb[46:54,8], col = "#9ECAE1", lty = 2)
lines(all_comb[55:63,2],all_comb[55:63,8], col = "#C6DBEF", lty = 2)

The dashed lines correspond to the power to detect the simulated effects (X axis) with population of increasing size (dark to light blue). The red diagonal corresponds to the expectation assuming that the effects are perfectly estimated. The regular lines correspond to the estimates effects in the populations of increasing size (dark to light blue). What we see is that when the power departs from 100%, the effects tend to be overestimated. Quite interestingly, at suboptimal power the estimated effects appear to be determined by the sample size more than by the actual effect. Thus, under these conditions, the estimates tell us more about our experimental design than about the biology we are trying to study.

How can we address this “curse”? Especially in -omic studies, it is a good idea to distinguish a discovery phase from a confirmation phase. Effects are first discovered in a “discovery” sample, applying stringent significance thresholds that properly account for multiple testing. In a second stage, the “discovered” effects are then confirmed in an independent “confirmation” sample, using a more lenient threshold that only corrects for the number of discoveries. If significant in the confirmation sample, the effect is deemed real, while the conformation cohort provides a less biased estimate of the size of the true effect.

Take home messages

  1. The p-value of a test is the probability to have an equally or more unlikely outcome of a test under the null hypothesis (H0).

  2. p-values can be computed with standard statistic tests or, increasingly, using self-designed empirical tests using in silico simulation and/or permutation.

  3. When performing multiple tests, the threshold p-value to declare significance has to be adjusted in order to control the number of experiment-wide false positives. NOT DOING THIS APPROPRIATELY IS A MAJOR SOURCE OF FALSE POSITIVES IN THE LITTERATURE.

  4. Rather than adjusting the threshold value for the effective number of realized tests, one may exploit the obtained distribution of p-values to compute FDR or q-values. This is especially effective when the proportion of true H1 hypotheses is high amongst the realized tests, hence causing a major shift of the p-value distribution to low values.

  5. When the statistical power to detect a true H1 is limited (for instance because the sample size is too small), the effect will often be missed (false negatives, type II error). THIS IS A VALID CAUSE OF NON-REPRODUCIBILITY OF PUBLISHED RESULTS. To detect the effect one has to be a bit lucky, i.e. the effect needs to be - by chance - overestimated in your data. Thus, when one detects an effect that one had a small chance to detect, it will be overestimated in the “discovery” sample (= Winners’ curse). As matter of fact, under conditions of low statistical power, the estimates of the effects are determined more by the sample size than by the actual effect size.

Acknowledgements

I thank the 2019 students for a very pleasant and interactive three days (21-23/10). I would also like to thank one of the students (2019, Renaud Nivelle) for sharing his excellent R scripts, and helping us all to progress.

LS0tCnRpdGxlOiAiSW50dWl0aXZlIHN0YXRpc3RpY3MiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KICAKKiJQb3NlIHRvbiBlc3ByaXQsIE1pY2hlbCIqICAKQ2F0aGVyaW5lIFBpcmVubmUsIG15IGdyYW5kLW1vdGhlciAgCgojSW50cm9kdWN0aW9uICAKClRoZSBhaW0gb2YgdGhpcyBjb3Vyc2UgaXM6ICAgCiAgCiAgCjEuIFRvIG1ha2UgeW91IHRoaW5rIG1vcmUgZGVlcGx5IGFib3V0IHNvbWUgZnVuZGFtZW50YWwgY29uY2VwdHMgaW4gc3RhdGlzdGljcywgaW5jbHVkaW5nOiAgCiAgICAtIHRoZSBtZWFuaW5nIG9mICoqcC12YWx1ZSoqLCAgCiAgICAtIHRoZSBpc3N1ZSBvZiAqKm11bHRpcGxlIHRlc3RpbmcqKiwgICAKICAgIC0gdGhlIG1lYW5pbmcgb2YgdGhlICoqZmFsc2UgZGlzY292ZXJ5IHJhdGUgKEZEUikqKiwgYW5kICAKICAgIC0gdGhlICoqd2lubmVycycgY3Vyc2UqKiAgCiAgCiAgCjIuIFRvIGludHJvZHVjZSB5b3UgdG8gYmFzaWMgcHJvZ3JhbW1pbmcgaW4gUiwgaW5jbHVkaW5nIHRvIGNvbXB1dGUgcC12YWx1ZXMgYnkgc2ltdWxhdGlvbiBhbmQgcGVybXV0YXRpb24uICAKICAKSSBoYXZlIGZvdW5kIHRoaXMgYm9vayBlc3BlY2lhbGx5IHRvIGJlIGFuIGV4Y2VsbGVudCBpbnRyb2R1Y3Rpb25zIHRvIFI6ICAKICAKLSAiSGFuZHMtb24gcHJvZ3JhbW1pbmcgd2l0aCBSIiBieSBHYXJyZXR0IEdyb2xlbXVuZCAoaHR0cHM6Ly9yc3R1ZGlvLWVkdWNhdGlvbi5naXRodWIuaW8vaG9wci8pICAKCk90aGVyIHJlZmVyZW5jZXMgd2hpY2ggbWF5IGJlIHVzZWZ1bCB0byB5b3UgaW5jbHVkZTogIAoKLSAiUiBmb3IgZGF0YSBzY2llbmNlIiBieSBIYWRsZXkgV2lja2hhbSAmIEdhcnJldHQgR3JvbGVtdW5kIChodHRwczovL3I0ZHMuaGFkLmNvLm56KSAgCi0gIlIgZ3JhcGhpY3MgY29va2Jvb2siIGJ5IFdpbnN0b24gQ2hhbmcgKGh0dHA6Ly91c2Vycy5tZXR1LmVkdS50ci9vemFuY2FuL1IlMjBHcmFwaGljcyUyMENvb2tib29rLnBkZikgIAoKWW91IGNhbiBkb3dubG9hZCB0aGlzIFIgbm90ZWJvb2sgYW5kIG90aGVyIG1hdGVyaWFsIGZyb206IGh0dHBzOi8vd3d3LmdpZ2F1YWcudWxpZWdlLmJlL2Ntcy9jXzQ3NjYzMzMvZW4vZ2lnYXVhZy10ZWFjaGluZyAKCkkgYW0gcmVsYXRpdmVseSBuZXcgdG8gUiBteXNlbGYuIFNvIGJlIGNsZW1lbnQgcGxlYXNlIDotKS4KCllvdSB3aWxsIG5lZWQgdG8gaW5zdGFsbCB0aGUgZm9sbG93aW5nIFIgcGFja2FnZXMgYW5kIGxpYnJhcmllcyB0byB1c2UgdGhpcyBOb3RlYm9vayAgIAoKYGBge3J9CiMgcGFja2FnZXMgYW5kIGxpYnJhcmllcyB0byBpbnN0YWxsCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiNpbnN0YWxsLnBhY2thZ2VzKCJwcnlyIikKI2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQojaW5zdGFsbC5wYWNrYWdlKCJSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoInByeXIiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKYnJld2VyLnBhbCg5LCJCbHVlcyIpCgpgYGAKCllvdSBtYXkgYWxzbyB3YW50IHRvIGNoZWNrIHlvdXIgd29ya2luZyBkaXJlY3RvcnkgYmVmb3JlIHN0YXJ0aW5nICAKCmBgYHtyfQojIENoZWNrIC8gc2V0IHlvdXIgd29ya2luZyBkaXJlY3RvcnkKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnNldHdkKCIvVXNlcnMvbWljaGVsZ2Vvcmdlcy9Eb2N1bWVudHMvVGVhY2hpbmcvR0lHQV9Eb2N0b3JhbF9TY2hvb2wvSW50dWl0aXZlX3N0YXRpc3RpY3MvUl9JTlRfU1RBVCIpCmdldHdkKCkKCmBgYAoKI0Fib3V0IHAtdmFsdWVzLCBudWxsIChIMCkgYW5kIGFsdGVybmF0aXZlIChIMSkgaHlwb3RoZXNlcwoKKipQTEFZSU5HIFdJVEggQ09JTlMqKiAgCgpBIGNvbW1vbiBtb2R1cyBvcGVyYW5kaSBpbiBzY2llbmNlIGlzIHRvIGNoYWxsZW5nZSBhIHByZWNvbmNlaXZlZCBtb2RlbCAoSDApIHdpdGggb2JzZXJ2YXRpb25zLiAgSWYgdGhlIGxpa2VsaWhvb2Qgb2YgdGhlIG9ic2VydmF0aW9ucyBpcyB2ZXJ5IHNtYWxsIHVuZGVyIEgwLCBvbmUgbWF5IHB1dCB0aGUgdmFsaWRpdHkgb2YgSDAgaW4gcXVlc3Rpb24gYW5kIHBvc3NpYmx5IOKAnHJlamVjdOKAnSBpdC4KClRvIGlsbHVzdHJhdGUgdGhpcywgd2Ugd2lsbCBwbGF5IGF0IOKAnGhlYWRzIG9yIHRhaWxz4oCdIChpLmUuIOKAnHBpbGUgb3UgZmFjZeKAnSkgdG8gdGVzdCB3aGV0aGVyIGNvaW5zIGFyZSBiYWxhbmNlZCwgaS5lLiBoYXZlIGFuIGVxdWFsIGNoYW5jZSB0byBmYWxsIG9uIHRoZSBoZWFkIHZzIHRhaWwgZmFjZSB3aGVuIHRvc3NlZC4gIEVhY2ggb2YgdXMgd2lsbCB0ZXN0IGEgMS3igqwgY29pbiBieSB0b3NzaW5nIGl0LCBzYXkgNTAgdGltZXMgYW5kIHJlY29yZCB0aGUgbnVtYmVyIG9mIHRpbWVzIGl0IGZhbGxzIG9uIGhlYWQuICBJZiB0aGUgY29pbiBpcyBiYWxhbmNlZCAoPUgwKSB3ZSBleHBlY3QgMjUgaGVhZHMgYW5kIDI1IHRhaWxzLiAgQWxsIGRpZmZlcmVudCB2YWx1ZXMgYXJlIGEgInNpZ24gb2YgYmlhcyIsIGkuZS4gYW4gZXhjZXNzIG9mIGhlYWRzIChuX0ggPiAyNSkgb3IgYW4gZXhjZXNzIG9mIHRhaWxzIChuX1QgPiAyNSkuIFlldCB3ZSBhcmUgbm90IHdvcnJpZWQgYWJvdXQgdGhlIGJhbGFuY2Ugb2YgYSBjb2luIGlmIHdlIG9ic2VydmUgMjYgaGVhZHMgYW5kIDI0IHRhaWxzIChvciB2aWNlIHZlcnNhKSwgb3IgZXZlbiAyNSBoZWFkcyBhbmQgMjMgdGFpbHMgKG9yIHZpY2UgdmVyc2EpLiAgIEJ1dCBzaG91bGQgd2UgYmUgd29ycmllZCBhYm91dCB0aGUgY29pbiBpZiB3ZSBvYnNlcnZlIGYuaS4gMzUgaGVhZHMgYW5kIDE1IHRhaWxzPwoKVG8gYWRkcmVzcyB0aGlzLCB3ZSBuZWVkIHRvIGJlIGFibGUgdG8gY29tcHV0ZSB0aGUgcHJvYmFiaWxpdHkgb2YgdGhlIG9ic2VydmF0aW9ucyB1bmRlciBIMCAoPSBiYWxhbmNlZCBjb2luKS4gIEluIHRoaXMgcGVjdWxpYXIgY2FzZSwgdGhlIHByb2JhYmlsaXR5IG9mIGEgZ2l2ZW4gb3V0Y29tZSAobl9IIGFuZCBuX1QpIGNhbiBlYXNpbHkgYmUgY29tcHV0ZWQgdXNpbmcgdGhlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbjoKClsobl9IK25UKSEvbl9IIW5fVCFdIHggMC41XihuX0grbl9UKQoKV2Ugd2lsbCBub3cgdXNlIFIgdG8gZ2VuZXJhdGUgdGhlIGNvcnJlc3BvbmRpbmcgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLiAgRm9yIHRoYXQgd2Ugd2lsbCBnZW5lcmF0ZSBhIGRhdGEgZnJhbWUgaW4gd2hpY2ggdGhlIGZpcnN0IGNvbHVtbiAoTlIpIGNvcnJlc3BvbmRzIHRvIHRoZSBvYnNlcnZlZCBudW1iZXIgb2YgImhlYWRzIiwgYW5kIHNpeCBvdGhlciBjb2x1bW5zIGFyZSBwcmVwYXJlZCB0byByZWNlaXZlIChpKSB0aGUgY29ycmVzcG9uZGluZyBwcm9iYWJpbGl0eSAod2hpY2ggd2Ugd2lsbCBjYWxsIEYpLCAoaWkpIHRoZSBkZXZpYXRpb24gZnJvbSBleHBlY3RhdGlvbiAoREVWKSwgKGlpaSkgdGhlIHByb2JhYmlsaXR5IHRvIG9ic2VydmUgYW4gZXF1YWxseSBvciBtb3JlIGRldmlhbnQgc2VyaWVzIChQIGZvciBwLXZhbHVlKSwgKGl2KSBhIGNvbHVtbiBmb3IgYSBsb2dpY2FsIChUKSwgKHYpIC4uLiwgKHZpKSAuLi4gV2Ugd2lsbCBhc3N1bWUgdGhhdCAtIHRvIHRlc3QgaXRzIGJhbGFuY2UgLSB3ZSB0b3NzIHRoZSBjb2luIDUwIHRpbWVzLiAgIAoKYGBge3J9Cm5yIDwtIDUwCiMgR2VuZXJhdGUgZGF0YSBmcmFtZQp0b3NzIDwtIGRhdGEuZnJhbWUoTlI9MDpuciwgRj0wLCBERVY9MCwgUD0wLCBUPTAsIEJJTj0wLCBTSU09MCkKdG9zcwojIEdlbmVyYXRlIGZ1bmN0aW9uIGNvbXB1dGluZyBjb21iaW5hdGlvbnMgb2YgbiBvYmplY3RzIHRha2VuIHggYXQgYSB0aW1lCmNvbWIgPSBmdW5jdGlvbihuLCB4KSB7CiAgZmFjdG9yaWFsKG4pIC8gZmFjdG9yaWFsKG4teCkgLyBmYWN0b3JpYWwoeCkKfQojIENvbXB1dGUgcHJvYmFiaWxpdGllcyAiZiIKdG9zc1ssMl0gPSAwLjVebnIgKiBjb21iKG5yLHRvc3NbLDFdKQp0b3NzCiMgUGxvdCBwcm9iYWJpbGl0aWVzCnBsb3QodG9zc1ssMV0sdG9zc1ssMl0sY29sPSAiYmx1ZSIpCmBgYAoKV2Ugc2VlIHRoYXQgdGhpcyBkaXN0cmlidXRpb24gcmVzZW1ibGVzIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiwg4oCcYmFsYW5jZWTigJ0gb3V0Y29tZXMgYXJlIG1vcmUgbGlrZWx5IHRoYW4g4oCcdW5iYWxhbmNlZOKAnSBvbmVzIGR1ZSB0byB0aGUg4oCcbkNy4oCdIHRlcm0gaW4gdGhlIGVxdWF0aW9uLgoKVG8gdGVzdCB3aGV0aGVyIG91ciBjb2luIGlzIHRyaWNrZWQgb3Igbm90IHdlIGFjdHVhbGx5IHV0aWxpemUgYSBkaWZmZXJlbnQgcHJvYmFiaWxpdHkgd2hpY2ggd2Ugd2lsbCByZWZlciB0byBhcyDigJx0aGUgcC12YWx1ZeKAnSBmb3VuZCBpbiBhbGwgcHVibGljYXRpb25zLiAgVGhlIHF1ZXN0aW9uIHdlIGFjdHVhbGx5IHdhbnQgdG8gYXNrIHdoZW4gd2UgdGhyb3cgMzUgaGVhZHMgYW5kIDE1IHRhaWwsIGlzICrigJxXaGF0IHdhcyB0aGUgcHJvYmFiaWxpdHkgdG8gdGhyb3cgYW4gZXF1YWxseSB1bmJhbGFuY2VkIG9yIGV2ZW4gbW9yZSB1bmJhbGFuY2VkIHNlcmllcz/igJ0qICBXZWxsLCB3ZSBjb3VsZCBoYXZlIHRocm93biA1MC8wLCA0OS8xLCA0OC8yLCDigKYgMzUvMTUsIGJ1dCBhbHNvIDAvNTAsIDEvNDksIDIvNDgsIOKApiAxNS8zNSwgd2hpY2ggYXJlIGFsbCBvdXRjb21lcyB0aGF0IGFyZSBlcXVhbGx5IG9yIG1vcmUg4oCcdW5iYWxhbmNlZOKAnS4gSW5kZWVkLCB3aGVuIHdlIGNoZWNrZWQgZm9yIHRoZSBiYWxhbmNlIG9yIG5vdCBvZiB0aGUgY29pbiB3ZSBkaWRu4oCZdCBkZWNpZGUgd2hldGhlciB0aGUgYmlhcyBzaG91bGQgZmF2b3IgaGVhZHMgb3IgdGFpbHMuIFdlIHBlcmZvcm1lZCBhIHNvLWNhbGxlZCAqKuKAnHR3by10YWlsZWQgdGVzdOKAnSoqLiAgSGFkIHdlIHN1c3BlY3RlZCBpbiBhZHZhbmNlIHRoYXQgdGhlIGJpYXMgd291bGQgZmF2b3IgdGhlIGhlYWRzLCB3ZSB3b3VsZCBvbmx5IGhhdmUgY29uc2lkZXJlZCA1MC8wLCA0OS8xLCA0OC8yLCDigKYgMzUvMTUgaW4gYSBzby1jYWxsZWQgKirigJxvbmUtdGFpbGVk4oCdKiogdGVzdC4gIFdoZW4gbG9va2luZyBhdCB0aGUgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLCBhbmQgYXNzdW1pbmcgaXQgY29ycmVzcG9uZHMgdG8gYSBjb250aW51b3VzIGRpc3RyaWJ1dGlvbiwgb3VyIGludGVuZCBpcyB0byBkZXRlcm1pbmUgdGhlIHBhcnQgb2YgdGhlIHN1cmZhY2UgdW5kZXIgdGhlIGN1cnZlIHRoYXQgbGllcyBvdXRzaWRlIG9mIHRoZSBib3VuZGFyaWVzIGJldHdlZW4gMzQvMTYgYW5kIDM1LzE1IGFuZCAxNi8zNCBhbmQgMTUvMzUgaW4gdGhlIHR3by10YWlsZWQgdGVzdCwgb3Igb24gdGhlIGxlZnQgb2YgdGhlIDM0LzE2LTM1LzE1IGJvdW5kYXJ5IGluIHRoZSDigJxvbmUtdGFpbGVk4oCdIHRlc3QuCgpXZSB3aWxsIG5vdyB1c2UgUiB0byBjb21wdXRlIHRoaXMgcHJvYmFiaWxpdHkgZm9yIHRoZSBkaWZmZXJlbnQgdmFsdWVzIG9mIG5fSCB1c2luZywgZmlyc3QsIG91ciBzZWxmLW1hZGUgbGl0dGxlIHNjcmlwdCBhbmQgdGhlbiBjaGVjayB3aGV0aGVyIHdlIG9idGFpbiB0aGUgc2FtZSByZXN1bHRzIGFzIGEgZGVkaWN0ZWQgUiBmdW5jdGlvbi4gIE5vdGUgdGhlIHVzZSBvZiAqKiJsb2dpY2FsIHRlc3RzLCBzdWJzZXR0aW5nIGFuZCBlbGVtZW50LXdpc2UgZXhlY3V0aW9uIioqLiAgCgpgYGB7cn0KIyBDb21wdXRlIHRoZSBwcm9iYWJpbGl0eSB0byBoYXZlIGFuIGVxdWFsbHkgb3IgZXZlbiBtb3JlIGJpYXNlZCB0b3NzIHdpdGggb3VyIG93biBsaXR0ZSBzY3JpcHQKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgQ29tcHV0aW5nIGRldmlhdGlvbiBmcm9tIGV4cGVjdGF0aW9uCnRvc3MkREVWID0gYWJzKHRvc3NbLDFdLW5yLzIpCnRvc3MKIyBDb21wdXRlIHAtdmFsdWVzCmZvciAoaSBpbiAwOm5yKXsKICB0b3NzJFQgPSB0b3NzJERFViA+PSB0b3NzW2krMSwzXQogIHRvc3NbaSsxLDRdID0gc3VtKHRvc3MkRip0b3NzJFQpCn0KdG9zcwojIFBsb3QgcC12YWx1ZXMKcGxvdCh0b3NzWywxXSx0b3NzWyw0XSxjb2w9InJlZCIsIHhsYWIgPSAiTlIgSEVBRFMiLCB5bGFiID0gIlAvRiIpCnBvaW50cyh0b3NzWywxXSx0b3NzWywyXSxjb2w9ImJsdWUiKQoKIyBDb21wYXJlIHdpdGggUiBmdW5jdGlvbgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmZvciAoaSBpbiAwOm5yKXsKICBiaW4gPC0gYmlub20udGVzdCh4ID0gdG9zc1tpKzEsMV0sbiA9IG5yLCBwID0gMC41LCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKQogIHRvc3NbaSsxLDZdID0gYmluJHAudmFsdWUKfQp0b3NzCgojIFBsb3QgcC12YWx1ZXMKIyMjIyMjIyMjIyMjIyMjCmxpbmVzKHRvc3NbLDFdLHRvc3NbLDZdLGNvbD0icmVkIikKCiMgUGxvdCAtbG9nKHApCiMjIyMjIyMjIyMjIyMjCnBsb3QgKHRvc3NbLDFdLC1sb2cxMCh0b3NzWyw2XSksY29sPSJyZWQiLHhsYWIgPSAiTlIgSEVBRFMiLCB5bGFiID0gIi1sb2coUCkiKQphYmxpbmUoaCA9IC1sb2cxMCgwLjA1KSkKYGBgCgpGb3IgMzUgaGVhZHMgYW5kIDE1IHRhaWxzLCB0aGUgcC12YWx1ZSBpcyAwLjAwNjYuICBNYXliZSB3ZSBoYXZlIHRvIHdvcnJ5IGFib3V0IHN1Y2ggYSBjb2luIQoKQXNzdW1lIHRoYXQgeW91IGZvcmdvdCB0aGUgZXF1YXRpb24gb2YgdGhlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiwgeW91IGNvdWxkIHN0aWxsIGhhdmUgZGV0ZXJtaW5lZCB0aGUgY29ycmVzcG9uZGluZyBwLXZhbHVlIHF1aXRlIGVhc2lseSB3aXRoIHlvdXIgY29tcHV0ZXIgYnkgKirigJxzaW11bGF0aW9u4oCdKiouICBJbmRlZWQsIHdlIGNhbiBlYXNpbHkgc2ltdWxhdGUgc2VyaWVzIG9mIDUwIHRvc3NlcyB1bmRlciBIMCwgaS5lLiB0aGUgcHJvYmFiaWxpdHkgdG8gdGhyb3cgYSBoZWFkIGlzIGVxdWFsIHRvIHRoYXQgb2YgYSB0YWlsLiAgV2UgY2FuIHRoZW4gY291bnQgaG93IG9mdGVuIOKAkyBpbiB0aGUgc2ltdWxhdGlvbnMgLSB0aGUgbnVtYmVyIG9mIGhlYWRzIGRlcGFydHMgYXMgbXVjaCBvciBtb3JlIGZyb20gdGhlIGV4cGVjdGVkICg9MjUpIHRoYW4gd2l0aCBvdXIgYWN0dWFsIGNvaW4gKGYuaS4gMzUpLCBpLmUuIGhvdyBvZnRlbiB8U2ltLTI1fOKJpXwzNS0yNXwuICAgICAgCldlIHdpbGwgdXNlIFIgdG8gZ2VuZXJhdGUgdGhlIGNvcnJlc3BvbmRpbmcgZGlzdHJpYnV0aW9uIGJ5IHNpbXVsYXRpb24gYW5kIGNvbXBhcmUgaXQgd2l0aCB0aGUgdGhlb3JldGljYWwgb25lLiAKCmBgYHtyfQojIEdlbmVyYXRlIGRpc3RyaWJ1dGlvbiBvZiBOUiBieSBzaW11bGF0aW9uCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKc2FtcGxlICh4PTA6MSxzaXplPW5yLCByZXBsYWNlPVRSVUUpCnN1bShzYW1wbGUgKHg9MDoxLHNpemU9bnIsIHJlcGxhY2U9VFJVRSkpCnJlcGxpY2F0ZSgxMCxzdW0oc2FtcGxlICh4PTA6MSxzaXplPW5yLCByZXBsYWNlPVRSVUUpKSkKbnJfcmVwbCA9IDEwMDAwMApzaW0gPC0gcmVwbGljYXRlKG5yX3JlcGwsc3VtKHNhbXBsZSAoeD0wOjEsc2l6ZT1uciwgcmVwbGFjZT1UUlVFKSkpCnFwbG90KHNpbSxiaW53aWR0aD0xKQpoaXN0KHNpbSxicmVha3M9c2VxKC0wLjUsNTAuNSwxKSwgYm9yZGVyID0gInJlZCIpCgojIENvbXBhcmUgZGlzdHJpYnV0aW9uIG9mIHNpbXVsYXRlZCBhbmQgdGhlb3JldGljYWwgRiB2YWx1ZXMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmZvciAoaSBpbiAwOm5yKXsKICB0b3NzW2krMSw2XSA9IHN1bShzaW0gPT0gaSkvbnJfcmVwbAp9CnRvc3MKcGxvdCh0b3NzWywxXSwgdG9zc1ssMl0sY29sID0gImJsdWUiKQpsaW5lcyh0b3NzWywxXSx0b3NzWyw2XSxjb2wgPSAiYmx1ZSIpCmBgYAoKVGhlIHAtdmFsdWUgb2YgYW4gb2JzZXJ2ZWQgbnVtYmVyIG9mIGhlYWRzIChvciB0YWlscykgdW5kZXIgdGhlIG51bGwgY2FuIHZlcnkgZWFzaWx5IGJlIGNvbXB1dGVkIGFzIGZvbGxvd3M6ICAKCmBgYHtyfQojIENvbXB1dGUgcC12YWx1ZSB1c2luZyBzaW1wbGUgc2ltdWxhdGlvbgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwp0ZXN0X25yID0gMzUKc3VtKHNpbSA+PSB0ZXN0X25yIHwgc2ltIDw9IG5yLXRlc3RfbnIpL25yX3JlcGwKYGBgCgogIAoqKkdFTkVUSUMgQVNTT0NJQVRJT04gU1RVRElFUyoqCiAgClRvIGZ1cnRoZXIgb3VyIGRpc2N1c3Npb25zLCBJIHdpbGwgaW52aXRlIHlvdSBpbiBvbmUgb2YgbXkgb3duIHJlc2VhcmNoIGZpZWxkczogKipnZW5ldGljIGFzc29jaWF0aW9uIHN0dWRpZXMqKi4gIFdlIGFyZSBub3QgYWxsIGVxdWFsIGluIHRoZSBmYWNlIG9mIGRpc2Vhc2U6ICBzb21lIG9mIHVzIGFyZSBtb3JlIHN1c2NlcHRpYmxlIHRvIGFzdGhtYSwgb3RoZXJzIHRvIGNhcmRpb3Zhc2N1bGFyIGlzc3Vlcywgb3RoZXIgdG8gY2FuY2VycywgZXRjLiAgUGFydCBvZiB0aGVzZSBkaWZmZXJlbmNlcyBhcmUgZHVlIHRvIGRpZmZlcmVuY2VzIGluIOKAnGluaGVyaXRlZCBwcmVkaXNwb3NpdGlvbuKAnS4gIFRoaXMgbWVhbnMgdGhhdCB0aGVyZSBhcmUgKipnZW5ldGljIHZhcmlhbnRzKiogaW4gdGhlIHBvcHVsYXRpb24gdGhhdCBpbmNyZWFzZSAocmlzayB2YXJpYW50cykgb3IgZGVjcmVhc2UgKHByb3RlY3RpdmUgdmFyaWFudHMpIGRpc2Vhc2UgcmlzayBvZiB0aG9zZSB0aGF0IGNhcnJ5IHRoZW0uICBJbWFnaW5lIGEgZ2VuZXRpYyBwb2x5bW9ycGhpc20gd2l0aCB0d28gdmFyaWFudHMgKHNheSBhbGxlbGUgKkEqIGFuZCBhbGxlbGUgKmEqKS4gIEltYWdpbmUgdGhhdCB0aGUgYWxsZWxpYyBmcmVxdWVuY2llcyBpbiB0aGUgcG9wdWxhdGlvbiBhcmUgKmZfQSogIGFuZCAqZl9hID0gMS1mX0EqLiAgIEltYWdpbmUgdGhhdCB0aGUgKmEqIGFsbGVsZSBpcyBhIHJpc2sgdmFyaWFudCBmb3IgQ3JvaG7igJlzIGRpc2Vhc2UuICBUaGlzIG1lYW5zIHRoYXQgaWYgeW91IGNhcnJ5ICphKiAoaS5lLiB5b3VyIGdlbm90eXBlIGlzICpBYSogb3IgKmFhKikgeW91ciBjaGFuY2UgdG8gZGV2ZWxvcCBDcm9obuKAmXMgZGlzZWFzZSBpcyBpbmNyZWFzZWQgd2hlbiBjb21wYXJlZCB0byB0aGUgKkFBKiBpbmRpdmlkdWFscy4gICBBcyBhIGNvbnNlcXVlbmNlLCBpZiB5b3Ugc2FtcGxlIGEgY29ob3J0IG9mIENyb2hu4oCZcyBwYXRpZW50cyBhbmQgbWVhc3VyZSB0aGUgZnJlcXVlbmN5IG9mIHRoZSAqYSogYWxsZWxlIGluIHRoaXMgY29ob3J0IG9mIOKAnGNhc2Vz4oCdLCBpdCBpcyBleHBlY3RlZCB0byBiZSBoaWdoZXIgKHNheSAqZl9hK860KikgdGhhbiB0aGUgZnJlcXVlbmN5IG9mIHRoZSAqYSogYWxsZWxlIGluIGEgY29ob3J0IG9mIGhlYWx0aHkg4oCcY29udHJvbHPigJ0gKHNheSAqfmZfYSopLiBJdCBpcyBpbnRlcmVzdGluZyB0byBpZGVudGlmeSBnZW5ldGljIHBvbHltb3JwaGlzbXMgaW4gb3VyIGdlbm9tZSB0aGF0IGNvbnRyaWJ1dGUgdG8gZGlmZmVyZW5jZXMgaW4gaW5oZXJpdGVkIGRpc2Vhc2UgcHJlZGlzcG9zaXRpb24gaW4gdGhlIHBvcHVsYXRpb24sIGFzIHRoaXMgaXMgYSBmaXJzdCBzdGVwIHRvd2FyZHMgaWRlbnRpZnlpbmcgdGhlIGdlbmVzIHdob3NlIGZ1bmN0aW9uIHRoZXkgcGVydHVyYiBhbmQgd2hpY2ggYXJlIHBvdGVudGlhbCBkcnVnIHRhcmdldHMuIFRvIHRlc3Qgd2hldGhlciBhIHBvbHltb3JwaGlzbSBvZiBpbnRlcmVzdCBpcyBpbmZsdWVuY2luZyBkaXNlYXNlIHByZWRpc3Bvc2l0aW9uLCBvbmUgd2lsbCB0eXBpY2FsbHkgY29sbGVjdCBETkEgc2FtcGxlcyBmcm9tICpuX0QqICBjYXNlcywgYW5kICpuX0gqIGNvbnRyb2xzLCBnZW5vdHlwZSBhbGwgaW5kaXZpZHVhbHMgZm9yIHRoZSBwb2x5bW9ycGhpc20gb2YgaW50ZXJlc3QsIGFuZCBjaGVjayB3aGV0aGVyIHRoZSBnZW5vdHlwZXMgYXJlIGFzc29jaWF0ZWQgd2l0aCB0aGUgZGlzZWFzZSwgaS5lLiBwZXJmb3JtIGFuICoqYXNzb2NpYXRpb24gc3R1ZHkqKi4gIFN0YXRlZCBtb3JlIHBsYWlubHksIHRoaXMgc2ltcGx5IG1lYW5zIHRoYXQgb25lIHdpbGwgY29tcGFyZSB0aGUgZnJlcXVlbmN5IG9mIHRoZSAqQSogYW5kICphKiBhbGxlbGVzIGluIGNhc2VzIGFuZCBjb250cm9scyBhbmQgY2hlY2sgd2hldGhlciB0aGVyZSBpcyBhbnkgZXZpZGVuY2UgdGhhdCB0aGV5IGRpZmZlciBzaWduaWZpY2FudGx5LiAgTm90ZSB0aGF0IGZvciBhIGJpYWxsZWxpYyBwb2x5bW9ycGhpc20sIHRlc3RpbmcgKkEqIGlzIHRoZSBzYW1lIChhbGJlaXQgbWlycm9yIGltYWdlKSBhcyB0ZXN0aW5nICphKjogaWYgb25lIGdvZXMgdXAgYnkgYW4gYW1vdW50ICrOtCosIHRoZSBvdGhlciBoYXMgdG8gZ28gZG93biBieSB0aGUgc2FtZSBhbW91bnQuCgpHb29kIOKApiBMZXQgdXMgZG8gdGhpcy4gIEltYWdpbmUgdGhhdCB3ZSBpbXBsZW1lbnQgdGhhdCB3aXRoIDEwMCBjYXNlcyBhbmQgMTAwIGNvbnRyb2xzLCB0aGF0IHRoZSBmcmVxdWVuY3kgb2YgYWxsZWxlICphKiBpcyAwLjEwIGluIGNhc2VzIGFuZCAwLjE1IGluIGNvbnRyb2xzLiAgSXMgdGhhdCBpbnRlcmVzdGluZz8gIElzIHRoZSAqQS9hKiBwb2x5bW9ycGhpc20gc2lnbmlmaWNhbnRseSBhc3NvY2lhdGVkIHdpdGggQ3JvaG7igJlzIGRpc2Vhc2UgYW5kIGEgaGVuY2UgYSBnZW51aW5lIHJpc2sgdmFyaWFudCB0aGF0IG1heSBsZWFkIHVzIHRvIGEgcmVhbCBjYXVzYXRpdmUgZ2VuZT8gIEluIG90aGVyIHdvcmRzLCBpcyAqzrQgPSAwLjE1LTAuMTAgPSAwLjA1KiBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHplcm8/CgpDYW4gd2UgdXNlIGFuIGFwcHJvYWNoIHNpbWlsYXIgdG8gdGhlIG9uZSB1c2VkIHdpdGggdGhlIGNvaW5zIHRvIGV2YWx1YXRlIHRoaXM/ICBJIGd1ZXNzIHdlIGNhbiBpbWFnaW5lIHNvbWV0aGluZyBzaW1pbGFyLiAgIFVuZGVyIEgwLCB0aGUgZnJlcXVlbmN5IG9mICphKiBpbiBjYXNlcyBhbmQgY29udHJvbHMgaXMgdGhlIHNhbWU6ICpmX2EqLiAgIFRodXMsIHdlIGNhbiBwcmVkaWN0IHRoZSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gb2YgKm5fRCxhKiBjYXNlcyBhbmQgKm5fSCxhKiBjb250cm9scyB1c2luZyB0aGUgc2FtZSBlcXVhdGlvbiBhcyBhYm92ZSAoYmFzZWQgb24gdGhlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbikuICBBc3N1bWluZyB0aGF0IHdoYXQgaGFwcGVucyBpbiBjYXNlcyBhbmQgY29udHJvbHMgaXMgaW5kZXBlbmRlbnQsIHRoZSBwcm9iYWJpbGl0eSBvZiB0aGUgY29tYmluYXRpb24gb2YgZXZlbnRzIGlzIGp1c3QgdGhlIHByb2R1Y3Qgb2YgdGhlIGluZGl2aWR1YWwgcHJvYmFiaWxpdGllcy4gRWFjaCBvZiB0aGVzZSBjb21iaW5hdGlvbnMgZ2VuZXJhdGVzIGEgKs60KiwgYW5kIHRodXMgd2UgaGF2ZSAqzrQq4oCZcyBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gdW5kZXIgdGhlIG51bGwuICBHcmVhdCEgT25lIHByb2JsZW0gdGhvdWdoOiAgd2l0aCB0aGUgY29pbnMgd2Uga25ldyB0aGF0IHVuZGVyIEgwICpmX0ggPSBmX1QgPSAwLjUqLCBidXQgd2hhdCBpcyAqZl9hKiB1bmRlciB0aGUgbnVsbD8gV2UgYWN0dWFsbHkgZG9u4oCZdCBrbm93IGZvciBzdXJlLiAgQnV0IGFzc3VtaW5nIHRoYXQgSDAgaXMgdHJ1ZSwgaGVuY2UgdGhhdCAqZl9hKiBpcyB0aGUgc2FtZSBpbiBjYXNlcyBhbmQgY29udHJvbHMsIG91ciBiZXN0IGVzdGltYXRlIG9mIHRoZSB0cnVlIHZhbHVlIG9mICpmX2EqICBpcyB0aGUgZnJlcXVlbmN5IG9mICphKiBpbiBjYXNlcyBhbmQgY29udHJvbHMgY29tYmluZWQgKGxhcmdlc3Qgc2FtcGxlIHdlIGNhbiBhc3NlbWJsZSkuICBUaHVzLCB3ZSB3aWxsIGdlbmVyYXRlIGFuIGVzdGltYXRlICpmzIJfKmEgdXNpbmcgYm90aCBjYXNlcyBhbmQgY29udHJvbHMuICBUaGVyZSB3ZSBnbyAuLi4gd2UgaGF2ZSBldmVyeXRoaW5nIHdlIG5lZWQuCgpgYGB7cn0KIyBEaXN0cmlidXRpb24gb2Ygbl9hIGluIGEgc2FtcGxlIG9mIDEwMCBpbmRpdmlkdWFscwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmZfYSA9IDAuMTI1Cm5yX2luZCA9IDEwMApucl9nYW0gPSAyKm5yX2luZAphc3NfYmluIDwtIGRhdGEuZnJhbWUoTlJfYSA9IDA6bnJfZ2FtLCBGUkVRPTAsIEZfRlJFUT0wLCBERUxUQSA9IDAsIEZfREVMVEEgPSAwLCBQX0RFTFRBID0gMCwgUCA9IDApCmFzc19iaW5bLDJdID0gYXNzX2JpblssMV0vbnJfZ2FtCmFzc19iaW5bLDNdID0gZGJpbm9tKGFzc19iaW5bLDFdLG5yX2dhbSxmX2EsbG9nID0gRkFMU0UpCmFzc19iaW5bLDRdID0gYXNzX2JpblssMV0vbnJfZ2FtCmFzc19iaW4KcGxvdChhc3NfYmluWywyXSxhc3NfYmluWywzXSxjb2w9InJlZCIsIHhsYWIgPSAiRlJFUSIsIHlsYWIgPSAiRiIpCgojIEZyZXF1ZW5jeSBkaXN0cmlidXRpb24gb2YgZGVsdGEgYmV0d2VlbiB0d28gc2FtcGxlcyBvZiAxMDAgaW5kaXZpZHVhbHMgKGYuaS4gY2FzZXMgYW5kIGN0cmxzKSB1bmRlciB0aGUgbnVsbAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmZvciAoaSBpbiAxOm5yX2dhbSsxKXsKICBmb3IgKGogaW4gMTpucl9nYW0rMSl7CiAgICBhc3NfYmluW2Ficyhhc3NfYmluW2ksMV0tYXNzX2JpbltqLDFdKSsxLDVdID0gYXNzX2JpblthYnMoYXNzX2JpbltpLDFdLWFzc19iaW5baiwxXSkrMSw1XSArIChhc3NfYmluW2ksM10gKiBhc3NfYmluW2osM10pCiAgfQp9CmFzc19iaW4KcGxvdChhc3NfYmluWyw0XSxhc3NfYmluWyw1XSxjb2w9InJlZCIsIHhsYWIgPSAiREVMVEEiLCB5bGFiID0gIkYiKQoKIyBQcm9iYWJpbGl0eSB0byBoYXZlIGRlbHRhIGxhcmdlciBvciBlcXVhbCB0aGFuICJ4IgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmZvciAoaSBpbiAxOm5yX2dhbSl7CiAgYXNzX2Jpbltucl9nYW0taSw2XSA9IGFzc19iaW5bbnJfZ2FtKzEtaSw2XSthc3NfYmluW25yX2dhbS1pLDVdCn0KYXNzX2JpbgpwbG90KGFzc19iaW5bLDRdLGFzc19iaW5bLDZdLGNvbD0iYmx1ZSIseGxhYiA9ICJERUxUQSIsIHlsYWIgPSAiRi9QIiwgeGxpbSA9IGMoMCwwLjEpKQpwb2ludHMoYXNzX2JpblssNF0sYXNzX2JpblssNV0sY29sPSJyZWQiKQphYmxpbmUoaCA9IDAuMDUpCmBgYAoKSW4gdGhpcyBzcGVjaWZpYyBjYXNlLCB3ZSBjb3VsZCBmYWxsIGJhY2sgb24gdGhlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbi4gIEJ1dCB0aGlzIHdpbGwgbm90IGFsd2F5cyBiZSB0aGUgY2FzZSBvciB0cmFjdGFibGUuICBPbmUgb2YgdGhlIHRoaW5ncyBzdGF0aXN0aWNpYW5zIGhhdmUgZG9uZSBkdXJpbmcgdGhlIDIwaWVzIGNlbnR1cnkgaXMgdG8gaW1hZ2luZSBhIG51bWJlciBvZiDigJx0cmlja3PigJ0gdGhhdCB3aWxsIGFsbG93IHlvdSBpbiBsb3RzIG9mIGNpcmN1bXN0YW5jZXMgdG8gcGVyZm9ybSBhIHNpbXBsZSBtYW5pcHVsYXRpb24gb2YgeW91ciBkYXRhIHN1Y2ggdGhhdCB0aGUgb3V0Y29tZSBjb3JyZXNwb25kcyB0byBhIOKAnHN0YXRpc3RpY+KAnSB3aXRoIGEga25vd24gcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLiAgWW91IGhhdmUgaGVhcmQgb2YgKipaKiogKHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBtZWFuIDAgYW5kIHZhci9TRCAxKSwgKipjaGktc3F1YXJlZCoqIChzdW0gb2Ygc3F1YXJlZCBaJ3MpLCAqKnQqKiAoWi9zcXJ0KG4pKSBhbmQgKipGKiogKHJhdGlvIG9mIHZhcmlhbmNlcykgc3RhdGlzdGljcy4gIFRoZXNlIGFyZSBhbGwg4oCccXVhbnRpdGllc+KAnSB0aGF0IGhhdmUgYSBrbm93biBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gdW5kZXIgdGhlIG51bGwuICAKCkluIHRoZSBjYXNlIG9mIHRoZSBhc3NvY2lhdGlvbiB0ZXN0LCBvbmUgY2FuIGZvciBpbnN0YW5jZSBnZW5lcmF0ZSBhICoqY29udGluZ2VuY3kgdGFibGUqKiwgYW5kIGNvbXB1dGUgKlNVTShFWFAtT0JTKV4yL0VYUCosIHdoaWNoIGlzIGtub3duIHRvIGhhdmUgYSBjaGktc3F1YXJlZCBkaXN0cmlidXRpb24gd2l0aCBvbmUgZGVncmVlIG9mIGZyZWVkb20uICAKCmBgYHtyfQojIENvbnRpbmdlbmN5IHRhYmxlCiMjIyMjIyMjIyMjIyMjIyMjIyMKU09FID0gMiooMSsyNS8xNzUpClNPRSAKcF9TT0UgPSBwY2hpc3EoU09FLDEsbG93ZXIudGFpbCA9IEZBTFNFKQpwX1NPRQpwbG90KGFzc19iaW5bLDRdLGFzc19iaW5bLDZdLGNvbD0iYmx1ZSIseGxhYiA9ICJERUxUQSIsIHlsYWIgPSAiUCIsIHhsaW0gPSBjKDAsMC4xKSkKYWJsaW5lKGggPSAwLjA1KQpwb2ludHMoMC4wNSxwX1NPRSxjb2w9ImdyZWVuIixwY2ggPSAxOSxjZXggPSAyKQoKTTwtYXMudGFibGUocmJpbmQoYygzMCwxNzApLGMoMjAsMTgwKSkpCk0KWHNxIDwtIGNoaXNxLnRlc3QoTSxjb3JyZWN0PUZBTFNFKQpYc3Ekc3RhdGlzdGljClhzcSRwLnZhbHVlCgoKYGBgCgpBbiBhbHRlcm5hdGl2ZSBpcyB0byBnZW5lcmF0ZSBhIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCAoKipMUlQqKikgd2hpY2ggYWxzbyBoYXMgYSBjaGktc3F1YXJlZCBkaXN0cmlidXRpb24uICAKCmBgYHtyfQojIExpa2VsaWhvb2QgUmF0aW8gVGVzdAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpMMCA9IDAuMTI1XigyMCszMCkgKiAwLjg3NV4oMTcwKzE4MCkKTDEgPSAwLjE1XjMwICogMC44NV4xNzAgKiAwLjEwXjIwICogMC45MF4xODAKbG9nKEwwKQpsb2coTDEpCmxydCA9IC0yKihsb2coTDApLWxvZyhMMSkpCmxydApwX2xydCA9IHBjaGlzcShscnQsMSxsb3dlci50YWlsID0gRkFMU0UpCnBfbHJ0CnBsb3QoYXNzX2JpblssNF0sYXNzX2JpblssNl0sY29sPSJibHVlIix4bGFiID0gIkRFTFRBIiwgeWxhYiA9ICJQIiwgeGxpbSA9IGMoMCwwLjEpKQphYmxpbmUoaCA9IDAuMDUpCnBvaW50cygwLjA1LHBfbHJ0LGNvbD0iYmxhY2siLHBjaCA9IDE5LGNleCA9IDIpCmBgYAoKQSBwcm9ibGVtIHdpdGggdGhlc2Ug4oCcc3RhbmRhcmTigJ0gc3RhdGlzdGljIHRlc3RzIGlzIHRoYXQgdG8gY29uZm9ybSB0byB0aGUgZXhwZWN0ZWQgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLCBhIG51bWJlciBvZiBjb25kaXRpb25zIG5lZWQgdG8gYmUgbWV0IHdoaWNoIG1heSBub3QgYWx3YXlzIGJlIHRoZSBjYXNlLiBUaGlzIGNhbiBnZW5lcmF0ZSBib3RoIGZhbHNlIG5lZ2F0aXZlcywgYnV0IG1vcmUgd29ycmlzb21lbHkgZmFsc2UgcG9zaXRpdmVzIGFzIHdlbGwuICBTbywgZG9u4oCZdCBnZXQgZXhjaXRlZCB0b28gcXVpY2tseSB3aGVuIHlvdSBvYnRhaW4gYSBsb3cgcC12YWx1ZSA7LSkuCgpUaGUgZ2FtZSB3aXRoIHRoZSBiaW5vbWlhbCBkaXN0cmlidXRpb24gaXMgbm90IHRoYXQgZWFzeSwgYW5kIHlvdSBtYXkgbm90IHJlbWVtYmVyIHRoZSBzdGFuZGFyZCBzdGF0aXN0aWMgdHJpY2tzIHRvbyB3ZWxsLiBGb3J0dW5hdGVseSwgaW4gdGhlIDIxc3QgY2VudHVyeSwgY29tcHV0ZXJzIHJlYWxseSBtYXkgaGVscCB5b3Ugb3V0IGEgbG90LiAgSG93IGFib3V0IHVzaW5nIGluIHNpbGljbyBzaW11bGF0aW9ucyBhcyBhYm92ZSwgdG8gZXZhbHVhdGUgd2hldGhlciAqzrQgPSAwLjA1KiBpcyBpbnRlcmVzdGluZyBvciBub3Q/IFdoeSBub3QgZ2VuZXJhdGUgZ2Vub3R5cGVzIGZvciBhIGNhc2UgY29ob3J0IG9mICpuX0QqIGluZGl2aWR1YWxzIGFuZCBhIGNvbnRyb2wgY29ob3J0IG9mICpuX0gqIGluZGl2aWR1YWxzIHVzaW5nIG91ciBiZXN0IGVzdGltYXRlIG9mICpmzIJfKmEgYW5kIG1lYXN1cmUgKs60Kj8gIElmIHdlIHJlcGVhdCB0aGlzIGEgbGFyZ2UgbnVtYmVyIG9mIHRpbWVzLCB3ZSB3aWxsIGluIGVmZmVjdCBnZW5lcmF0ZSB0aGUgZGlzdHJpYnV0aW9uIG9mICrOtCogdW5kZXIgdGhlIG51bGwgYW5kIGRpcmVjdGx5IGV2YWx1YXRlIGhvdyBjb21tb25seSB2YWx1ZXMgYXMgbGFyZ2Ugb3IgbGFyZ2VyIHRoZSB0aGUgKs60KiBzZWVuIHdpdGggcmVhbCBkYXRhIG9jY3VyIHVuZGVyIHRoZSBudWxsLiAKCmBgYHtyfQojIFVzaW5nIHNpbXVsYXRpb25zCiMjIyMjIyMjIyMjIyMjIyMjIyMKZl9hID0gMC4xMjUKc2FtcGxlKGMoMCwxKSxucl9nYW0scmVwbGFjZSA9IFRSVUUscHJvYiA9IGMoMS1mX2EsZl9hKSkKc3VtKHNhbXBsZShjKDAsMSksbnJfZ2FtLHJlcGxhY2UgPSBUUlVFLHByb2IgPSBjKDEtZl9hLGZfYSkpKQpzdW0oc2FtcGxlKGMoMCwxKSxucl9nYW0scmVwbGFjZSA9IFRSVUUscHJvYiA9IGMoMS1mX2EsZl9hKSkpL25yX2dhbQpzaW1fZjwtcmVwbGljYXRlKDEwMDAsc3VtKHNhbXBsZShjKDAsMSksbnJfZ2FtLHJlcGxhY2UgPSBUUlVFLHByb2IgPSBjKDEtZl9hLGZfYSkpKS9ucl9nYW0pCm1lYW4oc2ltX2YpCnNpbV9kPC1yZXBsaWNhdGUoMTAwMDAsc3VtKHNhbXBsZShjKDAsMSksbnJfZ2FtLHJlcGxhY2UgPSBUUlVFLHByb2IgPSBjKDEtZl9hLGZfYSkpKS9ucl9nYW0tc3VtKHNhbXBsZShjKDAsMSksbnJfZ2FtLHJlcGxhY2UgPSBUUlVFLHByb2IgPSBjKDEtZl9hLGZfYSkpKS9ucl9nYW0pCm1lYW4oc2ltX2QpCnN1bShhYnMoc2ltX2QpPj0gMC4wNSkvMTAwMDAKcGxvdChhc3NfYmluWyw0XSxhc3NfYmluWyw2XSxjb2w9ImJsdWUiLHhsYWIgPSAiREVMVEEiLCB5bGFiID0gIlAiLCB4bGltID0gYygwLDAuMSkpCmFibGluZShoID0gMC4wNSkKcG9pbnRzKDAuMDUsc3VtKGFicyhzaW1fZCk+PSAwLjA1KS8xMDAwMCxjb2w9InJlZCIscGNoID0gMTksY2V4ID0gMikKYGBgCgoqKkVYRVJDSUNFUyoqCgoxIENvbXB1dGUgdGhlIHAtdmFsdWUgb2YgMzggZXVyb3MgdG9zc2VzIHlpZWxkaW5nIDEyIGhlYWRzIHVuZGVyIHRoZSBudWxsLiAgCjIuIENvbXB1dGUgdGhlIHAtdmFsdWUgb2YgZmluZGluZyB0aGUgYSBhbGxlbGUgYXQgZnJlcXVlbmN5IG9mIDAuMjAgaW4gMTUwIGNhc2VzLCBhbmQgYXQgZnJlcXVlbmN5IG9mIDAuMjQgaW4gMTI1IGNhc2VzLgoKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIwpucl90b3NzZXMgPSAzOApucl9oZWFkcyA9IDEyCm5yX3JlcGwgPSAxMDAwMApzaW08LXJlcGxpY2F0ZShucl9yZXBsLHN1bShzYW1wbGUgKHg9MDoxLHNpemU9bnJfdG9zc2VzLCByZXBsYWNlPVRSVUUpKSkKc2ltCihhYnMoc2ltLW5yX3Rvc3Nlcy8yKSA+PSBhYnMobnJfaGVhZHMtbnJfdG9zc2VzLzIpKQpzdW0oYWJzKHNpbS1ucl90b3NzZXMvMikgPj0gYWJzKG5yX2hlYWRzLW5yX3Rvc3Nlcy8yKSkKc3VtKGFicyhzaW0tbnJfdG9zc2VzLzIpID49IGFicyhucl9oZWFkcy1ucl90b3NzZXMvMikpL25yX3JlcGwKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbnJfY2FzZXMgPSAxNTAKbnJfY3RybHMgPSAxMjUKYV9jYXNlcyA9IDAuMjAKYV9jdHJscyA9IDAuMjQKbnJfcmVwbCA9IDEwMDAwCmZfYSA9IChhX2Nhc2VzKm5yX2Nhc2VzK2FfY3RybHMqbnJfY3RybHMpLyhucl9jYXNlcytucl9jdHJscykKc2ltX2Q8LXJlcGxpY2F0ZShucl9yZXBsLHN1bShzYW1wbGUoYygwLDEpLDIqbnJfY2FzZXMscmVwbGFjZSA9IFRSVUUscHJvYiA9IGMoMS1mX2EsZl9hKSApICkvMi9ucl9jYXNlcyAtIHN1bShzYW1wbGUoYygwLDEpLDIqbnJfY3RybHMscmVwbGFjZSA9IFRSVUUscHJvYiA9IGMoMS1mX2EsZl9hKSApICkvMi9ucl9jdHJscykKbWVhbihzaW1fZCkKc3VtKGFicyhzaW1fZCk+PSBhYnMoYV9jYXNlcy1hX2N0cmxzKSkvbnJfcmVwbAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmBgYAoKCldlIGFjdHVhbGx5IGhhdmUgYW4gYWx0ZXJuYXRpdmUgdG8gdGhlIHNpbXVsYXRpb25zIHRoYXQgbWF5IGV2ZW4gYmUgYmV0dGVyLiAgVGhlIHF1ZXN0aW9uIGF0IGhhbmQgaXMgd2hldGhlciDigJMgaW4gdGhlIHJlYWwgZGF0YSDigJMgdGhlIGdlbm90eXBlcyBhcmUgc29tZWhvdyBjb3JyZWxhdGVkIHdpdGggZGlzZWFzZSBzdGF0dXMgKGkuZS4gYmVpbmcgY2FzZSB2cyBjb250cm9sKS4gV2hhdCBpZiB3ZSB3ZXJlIHRvIOKAnHNodWZmbGXigJ0gdGhlIGRhdGEsIG1lYW5pbmcgdGhhdCB3ZSB3b3VsZCBhc3NpZ24gdGhlIGF2YWlsYWJsZSBnZW5vdHlwZXMgcmFuZG9tbHkgdG8gYW55IG9mIHRoZSBhdmFpbGFibGUgcGhlbm90eXBlcy4gRm9yIHN1cmUsIGFueSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGdlbm90eXBlIGFuZCBwaGVub3R5cGUgY291bGQgb25seSBiZSBmb3J0dWl0b3VzIHVuZGVyIHN1Y2ggc2NlbmFyaW8uIEhlbmNlIHJlcGVhdGluZyBzdWNoICoqcGVybXV0YXRpb25zKiogbWFueSB0aW1lcyBhbmQgZWFjaCB0aW1lIG1lYXN1cmluZyAqzrQqIChhcyBmb3IgdGhlIHNpbXVsYXRpb25zKSB3aWxsIHlpZWxkIGl0cyBkaXN0cmlidXRpb24gdW5kZXIgdGhlIG51bGwuICBXaXRoIHBlcm11dGF0aW9ucywgdGhlIGRhdGEgcmVzZW1ibGUgdGhlIHJlYWwgZGF0YSBldmVuIGJldHRlciB0aGFuIHdpdGggdGhlIHNpbXVsYXRpb25zLiAgU3BlY2lmaWNhbGx5LCBmb3IgdGhpcyBleGFtcGxlLCB0aGUgZ2Vub3R5cGVzIGluIHRoZSBwZXJtdXRhdGlvbnMgbWF0Y2ggdGhlIHJlYWwgZGF0YSBldmVuIGJldHRlciB0aGFuIHRoZSBnZW5vdHlwZXMgaW4gc2ltdWxhdGlvbnMuICAKCldlIHdpbGwgdXNlIHJlYWwgZGF0YSB0byBpbGx1c3RyYXRlIHRoaXMgYXBwcm9hY2guIFdlIHdpbGwgZmlyc3QgbG9hZCBhIOKAnHByZXByb2Nlc3NlZOKAnSBmaWxlIHdpdGggZ2Vub3R5cGVzIGF0IH4gNDIwIFNOUHMgZm9yIGEgY2FzZS1jb250cm9sIGNvaG9ydCBmb3IgSUJEIHRvdGFsaW5nIDQsMDAwIGluZGl2aWR1YWxzLgoKYGBge3J9CiMgTG9hZCByZWFsIGRhdGFzZXQKIyMjIyMjIyMjIyMjIyMjIyMjIwpHV0FTIDwtIHJlYWQuY3N2KCJ+L0RvY3VtZW50cy9UZWFjaGluZy9HSUdBX0RvY3RvcmFsX1NjaG9vbC9JbnR1aXRpdmVfc3RhdGlzdGljcy9pYmRfZ2Vub3R5cGVzXzc2YjU0MWU2NDA1N2JkZmRhZjg2Xy9HV0FTLmRhdGEiLCBoZWFkZXI9RkFMU0UsIHNlcD0iOyIpCiNWaWV3KEdXQVMpCmBgYAoKVGhlIHJvd3MgaW4gdGhlIGZpbGUgY29ycmVzcG9uZCB0byBpbmRpdmlkdWFscy4gVGhlIGNvbHVtbnMgY29ycmVzcG9uZCB0byDigJxpZOKAnSwg4oCcc2V44oCdICgxIHZzIDIpLCDigJxhZmZlY3Rpb24gc3RhdHVzICgxIHZzIDIpLCBhbmQgdGhlbiBnZW5vdHlwZXMgYXQgYSBzZXJpZXMgb2YgU05QcyAoMCwgMSBvciAyIGNvcGllcyBvZiBhbGxlbGUgYSkuICBMZXTigJlzIHVzIGhhdmUgYSBsb29rIGF0IHNvbWUgb2YgdGhlIGZlYXR1cmVzIG9mIHRoZSBkYXRhc2V0LgoKYGBge3J9CiMgSGF2ZSBhIGxvb2sgYXQgdGhlIGRhdGFzZXQKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKbnJfdmFyIDwtIG5jb2woR1dBUyktMwpucl92YXIKCm5yX2luZF93aXRoX3NleCA8LSBzdW0oR1dBUyRWMiA9PSAxIHwgR1dBUyRWMiA9PSAyKQpucl9pbmRfd2l0aF9zZXgKbnJfbWFsZXMgPC0gc3VtKEdXQVMkVjIgPT0gMSkKbnJfbWFsZXMKCm5yX2luZF93aXRoX3BoZW4gPC0gc3VtKEdXQVMkVjMgPT0gMSB8IEdXQVMkVjMgPT0gMikKbnJfaW5kX3dpdGhfcGhlbgpucl9oZWFsdGh5X2luZCA8LSBzdW0oR1dBUyRWMyA9PSAxKQpucl9oZWFsdGh5X2luZAoKbnJfaW5kX3dpdGhfVjRfZ2Vub3R5cGUgPC0gc3VtKEdXQVMkVjQgPT0gMCB8R1dBUyRWNCA9PSAxIHwgR1dBUyRWNCA9PSAyKQpucl9pbmRfd2l0aF9WNF9nZW5vdHlwZQpmcmVxX2FsbF9hbHRfVjQgPC0gc3VtKEdXQVMkVjQpLygyKnN1bShHV0FTJFY0ID09IDAgfCBHV0FTJFY0ID09IDEgfCBHV0FTJFY0ID09IDIpKQpmcmVxX2FsbF9hbHRfVjQKCm5yX2Nhc2VzX3dpdGhfRjRfZ2Vub3R5cGUgPC0gc3VtKChHV0FTJFY0ID09IDAgfCBHV0FTJFY0ID09IDEgfCBHV0FTJFY0ID09IDIpICYgR1dBUyRWMyA9PSAyKSAKbnJfY2FzZXNfd2l0aF9GNF9nZW5vdHlwZQpmcmVxX2Nhc2VzX2FsdF9WNCA8LSBzdW0oR1dBUyRWNFtHV0FTJFYzID09IDJdKS8oMipzdW0oKEdXQVMkVjQgPT0gMCB8IEdXQVMkVjQgPT0gMSB8IEdXQVMkVjQgPT0gMikgJiBHV0FTJFYzID09IDIpKQpmcmVxX2Nhc2VzX2FsdF9WNAoKbnJfY3RybHNfd2l0aF9GNF9nZW5vdHlwZSA8LSBzdW0oKEdXQVMkVjQgPT0gMCB8IEdXQVMkVjQgPT0gMSB8IEdXQVMkVjQgPT0gMikgJiBHV0FTJFYzID09IDEpIApucl9jdHJsc193aXRoX0Y0X2dlbm90eXBlCmZyZXFfY3RybHNfYWx0X1Y0IDwtIHN1bShHV0FTJFY0W0dXQVMkVjMgPT0gMV0pLygyKnN1bSgoR1dBUyRWNCA9PSAwIHxHV0FTJFY0ID09IDEgfCBHV0FTJFY0ID09IDIpICYgR1dBUyRWMyA9PSAxKSkKZnJlcV9jdHJsc19hbHRfVjQKCmk9NQpzdW0oKEdXQVNbLGkrM10gPT0gMCB8IEdXQVNbLGkrM10gPT0gMSB8IEdXQVNbLGkrM10gPT0gMikpCnN1bSgoR1dBU1ssaSszXSA9PSAwIHwgR1dBU1ssaSszXSA9PSAxIHwgR1dBU1ssaSszXSA9PSAyKSwgbmEucm0gPSBUUlVFKQpzdW0oKEdXQVNbLGkrM10gPT0gMCB8IEdXQVNbLGkrM10gPT0gMSB8IEdXQVNbLGkrM10gPT0gMikgJiBHV0FTWywzXSA9PSAxLCBuYS5ybSA9IFRSVUUpCnN1bSgoR1dBU1ssaSszXSA9PSAwIHwgR1dBU1ssaSszXSA9PSAxIHwgR1dBU1ssaSszXSA9PSAyKSAmIEdXQVNbLDNdID09IDIsIG5hLnJtID0gVFJVRSkKc3VtKEdXQVNbLGkrM11bR1dBU1ssM10gPT0gMV0sIG5hLnJtID0gVFJVRSkvKDIqc3VtKChHV0FTWyxpKzNdID09IDAgfEdXQVNbLGkrM10gPT0gMSB8IEdXQVNbLGkrM10gPT0gMikgJiBHV0FTWywzXSA9PSAxLCBuYS5ybSA9IFRSVUUpKQpgYGAKCkZvciByZWFzb25zIHdoaWNoIHlvdSB3aWxsIHVuZGVyc3RhbmQgbGF0ZXIgSSB3aWxsIHNhdmUgdGhlIG9yaWdpbmFsICJhZmZlY3Rpb24gc3RhdHVzIiBhcyBhIGRpc3RpbmN0IHZlY3Rvci4gIAoKYGBge3J9CiMgU2F2ZSBvcmlnaW5hbCB2ZXJzaW9uIG9mICJhZmZlY3Rpb24gc3RhdHVzIiBhcyBhIHZlY3RvcgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKQUZGX1NUQVRVUyA8LSBHV0FTJFYzCiNBRkZfU1RBVFVTCmBgYAoKV2Ugd2lsbCBmaXJzdCBjb21wdXRlIHRoZSBhc3NvY2lhdGlvbiAod2l0aCBkaXNlYXNlKSBwLXZhbHVlcyBmb3IgdGhlIDQyMCBTTlBzIHVzaW5nIGJvdGggdGhlICoqY29udGluZ2VuY3kgdGFibGUqKiBhcHByb2FjaCBhbmQgdGhlICoqTFJUKiouCgpgYGB7cn0KIyBQcmVwYXJpbmcgYSBkYXRhIGZyYW1lCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpSRVNfR1dBUyA8LSBkYXRhLmZyYW1lKFNOUCA9IDE6bnJfdmFyLCBDSFIgPSAwLCBQT1M9MCwgTlJfR0VOX0NUUj0wLCBBTFRfRlJfQ1RSPTAsIE5SX0dFTl9DQVM9MCwgQUxUX0ZSX0NBUz0wLCBBTFRfRlJfQUxMPTAsIAogICAgICAgICAgICAgICAgICAgICAgIENISVNRPTAsIExQX0NISVNRXzE9MCwgTFBfQ0hJU1FfMj0wLCBMUlQ9MCwgTFBfTFJUPTAsIExQX1BFUk09MCwgTFBfTVVMVEVTVD0wKQpSRVNfR1dBUwoKIyBHZW5lcmF0aW5nIGEgZnVuY3Rpb24gY29tcHV0aW5nIHRoZSBwLXZhbHVlIG9mIGEgY29udGluZ2VuY3kgdGFibGUgdXNpbmcgYSBjaGkgc3F1YXJlZCB0ZXN0CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpteWNoaSA8LSBmdW5jdGlvbihpKXsKICBjdDwtbWF0cml4KGMoMipSRVNfR1dBU1tpLDRdKlJFU19HV0FTW2ksNV0sMipSRVNfR1dBU1tpLDRdKigxLVJFU19HV0FTW2ksNV0pLDIqUkVTX0dXQVNbaSw2XSpSRVNfR1dBU1tpLDddLDIqUkVTX0dXQVNbaSw2XSooMS1SRVNfR1dBU1tpLDddKSksIG5yb3c9MiwgYnlyb3c9VFJVRSkKICBYc3EgPC0gY2hpc3EudGVzdChjdCxjb3JyZWN0PUZBTFNFKQogIFhzcSRwLnZhbHVlCn0KCiMgR2VuZXJhdGluZyBhbmQgc3RvcmluZyBzdW1tYXJ5IGRhdGEgYW5kIHAtdmFsdWVzIGluIGRhdGEgZnJhbWUKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpmb3IgKGkgaW4gMTpucl92YXIpewogIFJFU19HV0FTW2ksNF0gPSBzdW0oKEdXQVNbLGkrM10gPT0gMCB8IEdXQVNbLGkrM10gPT0gMSB8IEdXQVNbLGkrM10gPT0gMikgJiBHV0FTWywzXSA9PSAxLCBuYS5ybSA9IFRSVUUpCiAgUkVTX0dXQVNbaSw1XSA9IHJvdW5kKHN1bShHV0FTWyxpKzNdW0dXQVNbLDNdID09IDFdLCBuYS5ybSA9IFRSVUUpLygyKlJFU19HV0FTW2ksNF0pLGRpZ2l0cz0zKQogIFJFU19HV0FTW2ksNl0gPSBzdW0oKEdXQVNbLGkrM10gPT0gMCB8IEdXQVNbLGkrM10gPT0gMSB8IEdXQVNbLGkrM10gPT0gMikgJiBHV0FTWywzXSA9PSAyLCBuYS5ybSA9IFRSVUUpCiAgUkVTX0dXQVNbaSw3XSA9IHJvdW5kKHN1bShHV0FTWyxpKzNdW0dXQVNbLDNdID09IDJdLCBuYS5ybSA9IFRSVUUpLygyKlJFU19HV0FTW2ksNl0pLGRpZ2l0cz0zKQogIFJFU19HV0FTW2ksOF0gPSByb3VuZCgoUkVTX0dXQVNbaSw0XSpSRVNfR1dBU1tpLDVdK1JFU19HV0FTW2ksNl0qUkVTX0dXQVNbaSw3XSkvKFJFU19HV0FTW2ksNF0rUkVTX0dXQVNbaSw2XSksZGlnaXRzPTMpCiAgUkVTX0dXQVNbaSw5XSA9IDIqKCAoMipSRVNfR1dBU1tpLDRdKlJFU19HV0FTW2ksNV0gLSAyKlJFU19HV0FTW2ksNF0qUkVTX0dXQVNbaSw4XSkgXjIpIC8gKDIqUkVTX0dXQVNbaSw0XSpSRVNfR1dBU1tpLDhdKQogICAgICAgICAgICAgICAgKyAoICgyKlJFU19HV0FTW2ksNF0qKDEtUkVTX0dXQVNbaSw1XSkgLSAyKlJFU19HV0FTW2ksNF0qKDEtUkVTX0dXQVNbaSw4XSkpIF4yKSAvICgyKlJFU19HV0FTW2ksNF0qKDEtUkVTX0dXQVNbaSw4XSkpCiAgUkVTX0dXQVNbaSwxMF0gPSAtbG9nMTAocGNoaXNxKFJFU19HV0FTW2ksOV0sMSxsb3dlci50YWlsID0gRkFMU0UpKQogIFJFU19HV0FTW2ksMTFdID0gLWxvZzEwKG15Y2hpKGkpKQogIExIMSA9ICgyKlJFU19HV0FTW2ksNF0qUkVTX0dXQVNbaSw1XSkqbG9nKFJFU19HV0FTW2ksNV0pICsgKDIqUkVTX0dXQVNbaSw0XSooMS1SRVNfR1dBU1tpLDVdKSkqbG9nKDEtUkVTX0dXQVNbaSw1XSkgKyAoMipSRVNfR1dBU1tpLDZdKlJFU19HV0FTW2ksN10pKmxvZyhSRVNfR1dBU1tpLDddKSArICgyKlJFU19HV0FTW2ksNl0qKDEtUkVTX0dXQVNbaSw3XSkpKmxvZygxLVJFU19HV0FTW2ksN10pCiAgTEgwID0gKDIqUkVTX0dXQVNbaSw0XSpSRVNfR1dBU1tpLDVdKSpsb2coUkVTX0dXQVNbaSw4XSkgKyAoMipSRVNfR1dBU1tpLDRdKigxLVJFU19HV0FTW2ksNV0pKSpsb2coMS1SRVNfR1dBU1tpLDhdKSArICgyKlJFU19HV0FTW2ksNl0qUkVTX0dXQVNbaSw3XSkqbG9nKFJFU19HV0FTW2ksOF0pICsgKDIqUkVTX0dXQVNbaSw2XSooMS1SRVNfR1dBU1tpLDddKSkqbG9nKDEtUkVTX0dXQVNbaSw4XSkKICBSRVNfR1dBU1tpLDEyXSA9IDIqKExIMS1MSDApCiAgUkVTX0dXQVNbaSwxM10gPSAtbG9nMTAocGNoaXNxKFJFU19HV0FTW2ksMTJdLDEsbG93ZXIudGFpbCA9IEZBTFNFKSkKfQpSRVNfR1dBUwoKIyBHZW5lcmF0ZSBtaW5pIE1hbmhhdHRhbiBwbG90CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpwbG90KFJFU19HV0FTWywxXSxSRVNfR1dBU1ssMTFdLGNvbD0icmVkIiwgeGxhYiA9ICJPUkRFUkVEIFNOUHMiLCB5bGFiID0gIi1sb2cocCkiKQphYmxpbmUoaCA9IC1sb2cxMCgwLjA1KSwgbHR5ID0gNCkKcG9pbnRzKFJFU19HV0FTWywxXSxSRVNfR1dBU1ssMTNdLGNvbD0iYmx1ZSIpCgojIENvbXBhcmUgcC12YWx1ZXMgQ1QgdnMgTFJUCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKcGxvdChSRVNfR1dBU1ssMTFdLFJFU19HV0FTWywxM10sY29sPSJyZWQiLCB4bGFiID0gIi1sb2cocCkgQ1QiLCB5bGFiID0gIi1sb2cocCkgTFJUIikKYGBgCgpBcyB5b3UgY2FuIHNlZSwgYm90aCBhcHByb2FjaGVzIHlpZWxkIHZpcnR1YWxseSBpZGVudGljYWwgcmVzdWx0cy4gIAoKV2Ugd2lsbCBub3cgYXBwbHkgdGhlICoqcGVybXV0YXRpb24gdGVzdCoqLiAgVGh1cywgd2Ugd2lsbCByZS1hc3NpZ24gYWZmZWN0aW9uIHN0YXR1cyByYW5kb21seSB0byB0aGUgNCwwMDAgaW5kaXZpZHVhbHMgeWV0IG1haW50YWluaW5nIHRoZSBzYW1lIG51bWJlciBvZiBjYXNlcyBhbmQgY29udHJvbHMuIEJ5IGRvaW5nIHRoaXMgd2Ugb2J2aW91c2x5IGRpc2Nvbm5lY3QgdGhlIGdlbm90eXBlcyBmcm9tIHRoZSBwaGVub3R5cGUgYXMgZGlzY3Vzc2VkIGFib3ZlLiBBbnkgYXNzb2NpYXRpb24gY291bGQgbm93IG9ubHkgYmUgZm9ydHVpdG91cyAoYWx0aG91Z2gg4oCTIHNlZSBiZWxvdykuIFdlIHdpbGwgY29tcHV0ZSBhIOKAnHN0YXRpc3RpY+KAnSB0aGF0IG1lYXN1cmVzIHRoZSBkaWZmZXJlbmNlIGluICpmX2EqIGJldHdlZW4gY2FzZXMgYW5kIGNvbnRyb2xzLiAgSSBjaG9vc2UganVzdCB0byBjb21wdXRlICpkZWx0YSouICBXZSByZXBlYXQgdGhpcyAqbl9wZXJtKiB0aW1lcywgaGVuY2UgcHJvdmlkaW5nIHVzIHdpdGggdGhlIGRpc3RyaWJ1dGlvbiBvZiAqZGVsdGEqIHVuZGVyIHRoZSBudWxsLiAgVGhlIHAtdmFsdWUgb2YgdGhlIHJlYWwgKmRlbHRhKuKAmXMgdW5kZXIgdGhlIG51bGwgdGhlbiBjb3JyZXNwb25kcyB0byB0aGUgbnVtYmVyIG9mIHBlcm11dGF0aW9ucyB5aWVsZGluZyAqZGVsdGEq4oCZcyB0aGF0IGFyZSBsYXJnZXIgb3IgZXF1YWwgdG8gdGhlIHJlYWwgb25lcy4gIAogIAogIAoqKlRoZSBmb2xsb3dpbmcgY29kZSBtYXkgdGFrZSBhIGxvbmcgdGltZSB0byBydW4gaWYgeW91IGhhdmUgbG90cyBvZiBTTlBzIGFuZC9vciBtYW55IGluZGl2aWR1YWxzLiAgSWYgeW91IHByZWZlciBub3QgdG8gcnVuIGl0IG5vdywgeW91IGNhbiBnbyB0byB0aGUgbmV4dCAiUiBjaHVuayIgdG8gaW1wb3J0IHByZWNvbXB1dGVkIHJlc3VsdHMuKioKCmBgYHtyfQojIEdlbmVyYXRpbmcgYSBkYXRhIGZyYW1lICh3aXRoIHNhbWUgc3RydWN0dXJlIGFzIFJFU19HQVdBUykgdG8gc3RvcmUgdGhlIHJlc3VsdHMgb2YgdGhlIHBlcm11dGF0aW9ucyAoU0gtdWZmbGVzKQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKU0hfR1dBUyA8LSBkYXRhLmZyYW1lKFNOUCA9IDE6bnJfdmFyLCBDSFIgPSAwLCBQT1M9MCwgTlJfR0VOX0NUUj0wLCBBTFRfRlJfQ1RSPTAsIE5SX0dFTl9DQVM9MCwgQUxUX0ZSX0NBUz0wLCBBTFRfRlJfQUxMPTAsIAogICAgICAgICAgICAgICAgICAgICAgIENISVNRPTAsIExQX0NISVNRPTAsIExQX0NISVNRXzI9MCwgTFJUPTAsIExQX0xSVD0wLCBMUF9QRVJNPTAsIExQX01VTFRFU1Q9MCkKCiMgR2VuZXJhdGUgYSBmdW5jdGlvbiB0aGF0IHdpbGwgc2h1ZmZsZSB0aGUgYWZmZWN0aW9uIHN0YXR1cyBpbiBHV0FTLAojIGdlbmVyYXRlIGFuZCBzdG9yZSB0aGUgcmVsZXZhbnQgc3VtbWFyeSBkYXRhIGFuZCBwLXZhbHVlcwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKc2h1ZmZsZSA8LSBmdW5jdGlvbihpKXsKICBHV0FTWywzXSA8LSBzYW1wbGUoQUZGX1NUQVRVUyxzaXplID0gNDAwMCxyZXBsYWNlID0gRkFMU0UpCiAgU0hfR1dBU1tpLDRdID0gc3VtKChHV0FTWyxpKzNdID09IDAgfCBHV0FTWyxpKzNdID09IDEgfCBHV0FTWyxpKzNdID09IDIpICYgR1dBU1ssM10gPT0gMSwgbmEucm0gPSBUUlVFKQogIFNIX0dXQVNbaSw1XSA9IHJvdW5kKHN1bShHV0FTWyxpKzNdW0dXQVNbLDNdID09IDFdLCBuYS5ybSA9IFRSVUUpLygyKlNIX0dXQVNbaSw0XSksZGlnaXRzPTMpCiAgU0hfR1dBU1tpLDZdID0gc3VtKChHV0FTWyxpKzNdID09IDAgfCBHV0FTWyxpKzNdID09IDEgfCBHV0FTWyxpKzNdID09IDIpICYgR1dBU1ssM10gPT0gMiwgbmEucm0gPSBUUlVFKQogIFNIX0dXQVNbaSw3XSA9IHJvdW5kKHN1bShHV0FTWyxpKzNdW0dXQVNbLDNdID09IDJdLCBuYS5ybSA9IFRSVUUpLygyKlNIX0dXQVNbaSw2XSksZGlnaXRzPTMpCiAgREVMVEEgPSBhYnMoU0hfR1dBU1tpLDVdLVNIX0dXQVNbaSw3XSkKICBERUxUQQp9CgojIENvbXB1dGUgZGlzdHJpYnV0aW9uIG9mIGRlbHRhIHVuZGVyIHRoZSBudWxsIGFuZCByZXN1bHRpbmcgcC12YWx1ZSBvZiByZWFsIGRlbHRhIGZvciBlYWNoIFNOUCBzZXBhcmF0ZWx5CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbnJfcGVybT01MDAwMApmb3IgKGkgaW4gMTpucl92YXIpIHsKICBwZXJtIDwtIHJlcGxpY2F0ZShucl9wZXJtLHNodWZmbGUoaSkpCiAgbnJfcG9zIDwtIHN1bShwZXJtID49IGFicyhSRVNfR1dBU1tpLDVdLVJFU19HV0FTW2ksN10pKQogIGlmIChucl9wb3MgPT0gMCl7CiAgICBSRVNfR1dBU1tpLDE0XSA9IC1sb2cxMCgxL25yX3Blcm0pCiAgfSBlbHNlIHsKICAgIFJFU19HV0FTW2ksMTRdID0gLWxvZzEwKG5yX3Bvcy9ucl9wZXJtKQogIH0KfQpSRVNfR1dBUwoKIyBDb21wYXJlIHRoZSBwLXZhbHVlcyBvYnRhaW5lZCB3aXRoIHRoZSBkaWZmZXJlbnQgYXBwcm9hY2hlcwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnBsb3QoUkVTX0dXQVNbLDExXSxSRVNfR1dBU1ssMTRdLGNvbD0icmVkIikKcG9pbnRzKFJFU19HV0FTWywxM10sUkVTX0dXQVNbLDE0XSxjb2w9ImdyZWVuIikKcG9pbnRzKFJFU19HV0FTWywxMV0sUkVTX0dXQVNbLDEzXSxjb2w9ImJsYWNrIikKCiMgQ29tcGFyZSB0aGUgTWFuaGF0dGFuIHBsb3RzIG9idGFpbmVkIHdpdGggdGhlIGRpZmZlcmVudCBhcHByb2FjaGVzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnBsb3QoUkVTX0dXQVNbLDFdLFJFU19HV0FTWywxMV0sY29sPSJyZWQiLCB4bGFiID0gIk9SREVSRUQgU05QcyIsIHlsYWIgPSAiLWxvZyhwKSIpCmFibGluZShoID0gLWxvZzEwKDAuMDUpLCBsdHkgPSA0KQpwb2ludHMoUkVTX0dXQVNbLDFdLFJFU19HV0FTWywxM10sY29sPSJncmVlbiIpCnBvaW50cyhSRVNfR1dBU1ssMV0sUkVTX0dXQVNbLDE0XSxjb2w9ImJsYWNrIikKCiMgV3JpdGUgUkVTX0dXQVMgdG8gZmlsZQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKd3JpdGUuY3N2KFJFU19HV0FTLCJHV0FTX1JFUyIscm93Lm5hbWVzID0gRkFMU0UpCgojIFJlYWQgUkVTX0dXQVMKIyMjIyMjIyMjIyMjIyMjCiNHV0FTX1JFUyA8LSByZWFkLmNzdigifi9Eb2N1bWVudHMvVGVhY2hpbmcvR0lHQV9Eb2N0b3JhbF9TY2hvb2wvSW50dWl0aXZlX3N0YXRpc3RpY3MvUl9JTlRfU1RBVC9HV0FTX1JFUyIpCiNWaWV3KEdXQVNfUkVTKQpgYGAKICAKKipSdW4gdGhpcyBSIGNodW5rIHRvIGltcG9ydCBwcmVjb21wdXRlZCByZXN1bHRzIGFuZCBpbXBvcnQgdGhlbSBpbiBSRVNfR1dBUyoqICAKCmBgYHtyfQojIFJlYWQgUkVTX0dXQVMKIyMjIyMjIyMjIyMjIyMjCkdXQVNfUkVTIDwtIHJlYWQuY3N2KCJ+L0RvY3VtZW50cy9UZWFjaGluZy9HSUdBX0RvY3RvcmFsX1NjaG9vbC9JbnR1aXRpdmVfc3RhdGlzdGljcy9SX0lOVF9TVEFUL0dXQVNfUkVTIikKI1ZpZXcoR1dBU19SRVMpClJFU19HV0FTWywxNF0gPC0gR1dBU19SRVNbLDE0XQojUkVTX0dXQVMKCiMgQ29tcGFyZSB0aGUgcC12YWx1ZXMgb2J0YWluZWQgd2l0aCB0aGUgZGlmZmVyZW50IGFwcHJvYWNoZXMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpwbG90KFJFU19HV0FTWywxMV0sUkVTX0dXQVNbLDE0XSxjb2w9InJlZCIpCnBvaW50cyhSRVNfR1dBU1ssMTNdLFJFU19HV0FTWywxNF0sY29sPSJncmVlbiIpCnBvaW50cyhSRVNfR1dBU1ssMTFdLFJFU19HV0FTWywxM10sY29sPSJibGFjayIpCgojIENvbXBhcmUgdGhlIE1hbmhhdHRhbiBwbG90cyBvYnRhaW5lZCB3aXRoIHRoZSBkaWZmZXJlbnQgYXBwcm9hY2hlcwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpwbG90KFJFU19HV0FTWywxXSxSRVNfR1dBU1ssMTFdLGNvbD0icmVkIiwgeGxhYiA9ICJPUkRFUkVEIFNOUHMiLCB5bGFiID0gIi1sb2cocCkiKQphYmxpbmUoaCA9IC1sb2cxMCgwLjA1KSwgbHR5ID0gNCkKcG9pbnRzKFJFU19HV0FTWywxXSxSRVNfR1dBU1ssMTNdLGNvbD0iZ3JlZW4iKQpwb2ludHMoUkVTX0dXQVNbLDFdLFJFU19HV0FTWywxNF0sY29sPSJibGFjayIpCmBgYAoKSW4gdGhpcyBjYXNlLCB0aGUgcC12YWx1ZXMgb2J0YWluZWQgYnkgcGVybXV0YXRpb24gYXJlIHZlcnkgc2ltaWxhciB0byB0aG9zZSBvYnRhaW5lZCB3aXRoIHRoZSBvdGhlciBhcHByb2FjaGVzIFthdCBsZWFzdCBmb3IgcC12YWx1ZXMgPiAxLyhudW1iZXIgb2YgcGVybXV0YXRpb25zKV0gLiAgQnV0IHRoaXMgaXMgbm90IGFsd2F5cyB0aGUgY2FzZS4gIEFzc3VtaW5nIHRoYXQgdGhlIHBlcm11dGF0aW9uIHRlc3RzIHdhcyBwcm9wZXJseSBleGVjdXRlZCwgaXQgaXMgdGhlIG1vc3QgdHJ1c3R3b3J0aHkuICBBcyB5b3UgY2FuIHNlZSwgYSBkaXNhZHZhbnRhZ2Ugb2YgdGhlIHBlcm11dGF0aW9uIHRlc3QgaXMgdGhhdCBpdCBtYXkgYmUgdGltZSBjb25zdW1pbmcgd2l0aCBsYXJnZSBkYXRhc2V0cyAoYXMgaXMgdGhlIGNhc2UgZm9yIEdXQVMpLgoKCioqQ09SUkVDVElORyBGT1IgRklYRUQgRUZGRUNUUyBJTiBQRVJNVVRBVElPTiBURVNUUyoqCgpGaW5kaW5nIGEgc2lnbmlmaWNhbnQgYXNzb2NpYXRpb24gYmV0d2VlbiBhIFNOUCBhbmQgYSBkaXNlYXNlIHN1Z2dlc3RzIHRoYXQgdGhlIFNOUCBtYXkgcGVydHVyYiB0aGUgZnVuY3Rpb24gb2YgYSBuZWFyYnkgZ2VuZSAoaS5lLiBpbiBjaXMpIGhlbmNlIGluY3JlYXNpbmcgZGlzZWFzZSByaXNrLiAgSW5kZWVkLCB1bmNvdmVyaW5nIHN1Y2ggc2NlbmFyaW9zIGlzIHRoZSBtYWluIHJlYXNvbiB3aHkgdGhlc2UgZXhwZXJpbWVudHMgYXJlIGNvbmR1Y3RlZCBpbiB0aGUgZmlyc3QgcGxhY2UuICBIb3dldmVyLCBvbmUgaGFzIHRvIGJlIGNhdXRpb3VzIGluIGludGVycHJldGluZyB0aGUgcmVzdWx0cywgYXMgbW9yZSB0cml2aWFsIGV4cGxhbmF0aW9uIG1heSBhY2NvdW50IGZvciB0aGUgb2JzZXJ2ZWQgYXNzb2NpYXRpb24uIE9uZSBvZiB0aGVzZSBpcyBzby1jYWxsZWQgcG9wdWxhdGlvbiBzdHJhdGlmaWNhdGlvbi4gIEFzIGFuIGV4YW1wbGUsIHRoZSBjYXNlLWNvbnRyb2wgY29ob3J0IG1heSBjb21iaW5lIHNhbXBsZXMgb3JpZ2luYXRpbmcgZnJvbSBkaWZmZXJlbnQgY291bnRyaWVzLiAgVGhlIGZyZXF1ZW5jeSBvZiB0aGUgKmEqIGFsbGVsZSBtYXkgZGlmZmVyIGJldHdlZW4gY291bnRyaWVzIGFzIGEgcmVzdWx0cyBvZiByYW5kb20gZHJpZnQuICBJZiB0aGUgcHJvcG9ydGlvbiBvZiBjYXNlcyB2cyBjb250cm9scyBkaWZmZXJzIGJldHdlZW4gY291bnRyaWVzLCB0aGVzZSB0d28gZmFjdG9ycyBjb21iaW5lZCBtYXkgY2F1c2UgYSBkaWZmZXJlbmNlIGluIHRoZSBmcmVxdWVuY3kgb2YgdGhlICphKiBhbGxlbGUgYmV0d2VlbiAiYWxsIiBjYXNlcyBhbmQgImFsbCIgY29udHJvbHMgKGkuZS4gYWNyb3NzIGNvdW50cmllcykgdGhhdCBpcyBub3QgcmVmbGVjdGluZyBhIGdlbnVpbmUgImNhdXNhbCIgYXNzb2NpYXRpb24gd2l0aCBkaXNlYXNlLCBidXQgcmF0aGVyIHBvcHVsYXRpb24gc3RyYXRpZmljYXRpb24uICBUaGVyZSBhcmUgc2V2ZXJhbCB3YXlzIHRvIGNvcnJlY3QgZm9yIHN0cmF0aWZpY2F0aW9uLiBBcyB3ZSBhcmUgZGlzY3Vzc2luZyB0aGUgcGVybXV0YXRpb24gdGVzdCBoZXJlLCB3ZSB3aWxsIG9ubHkgZGVzY3JpYmUgYSB3YXkgdG8gYWp1c3QgdGhlIHBlcm11dGF0aW9uIHRlc3QgdG8gYWNjb3VudCBmb3IgcG9zc2libGUgImNvbmZvdW5kaW5nIiBlZmZlY3RzLiAgV2hhdCBvbmUgY2FuIGRvIGluIHRoZSBleGFtcGxlIGNpdGVkIGFib3ZlIChpLmUuIGFuIGFzc29jaWF0aW9uIHN0dWR5IGNvbmR1Y3RlZCB3aXRoIHNhbXBsZXMgb3JpZ2luYXRpbmcgZnJvbSBkaWZmZXJlbnQgY291bnRyaWVzIGhhdmluZyBkaWZmZXJlbnQgY2FzZSB2cyBjb250cm9sIHJhdGlvcykgaXMgdG8gKipwZXJmb3JtIHRoZSBwZXJtdXRhdGlvbnMgd2l0aGluIGNvdW50cnkgKGkuZS4gd2l0aGluICJzdHJhdGEiKSoqLiAgQnkgZG9pbmcgc28sIHRoZSBwZXJtdXRhdGlvbnMgcmVtYWluICJhZmZlY3RlZCIgYnkgdGhlIHNhbWUgc3RyYXRpZmljYXRpb24gcHJvYmxlbSBhcyB0aGUgcmVhbCBkYXRhLiAgVGh1cyB0aGUgKmRlbHRhKidzIG9idGFpbmVkIGZyb20gdGhlIHBlcm11dGVkIGRhdGEgd2lsbCB0ZW5kIHRvIGJlIGluZmxhdGVkIGFzIHdlbGwgKGFzIGEgcmVzdWx0IG9mIHN0cmF0aWZpY2F0aW9uKS4gIFRoZSAqZGVsdGEqIHNlZW4gd2l0aCByZWFsIGRhdGEgd2lsbCB0aGVyZWZvcmUgbm90IGJlIHNlZW4gYXMgcGFydGljdWxhcmx5IGV4Y2VwdGlvbmFsIGluIHJlZ2FyZCB0byB0aGUgZGlzdHJpYnV0aW9uIG9mICpkZWx0YSoncyBvYnRhaW5lZCBhY3Jvc3MgdGhlIHBlcm11dGF0aW9ucy4gSGVuY2UsIHRoZSBjb3JyZXNwb25kaW5nIHAtdmFsdWUgd2lsbCBub3QgYmUgZGVlbWVkIHBhcnRpY3VsYXJseSBzbWFsbCBub3IgaW50ZXJlc3RpbmcuICAKICAKKipFWEVSQ0lDRSoqICAKCkFzIGFuIGV4ZXJjaWNlLCB5b3UgbWF5IHdhbnQgdG8gd3JpdGUgYW4gUiBzY3JpcHQgdGhhdCBwZXJtdXRlcyBmb3IgaW5zdGFuY2Ugd2l0aGluICpzZXgqIGluIHRoZSBHV0FTIGRhdGFzZXQuCgoKCiNDb3JyZWN0aW5nIGZvciBtdWx0aXBsZSB0ZXN0aW5nCgoqKlBMQVlJTkcgV0lUSCBDT0lOUyBBR0FJTioqCiAgCkxldCB1cyBnbyBiYWNrIHRvIG91ciBvbmUgRXVybyBjb2lucy4gV2Ugd2lsbCBlYWNoIHRvc3Mgb3VyIEV1cm8gY29pbiA1MCB0aW1lcywgcmVjb3JkIHRoZSBudW1iZXIgb2YgaGVhZHMsIGFuZCBjb21wdXRlIHRoZSBjb3JyZXNwb25kaW5nIHAtdmFsdWUsIGkuZS4gYXNzdW1pbmcgdGhhdCBvdXIgRXVybyBpcyBiYWxhbmNlZC4KSSBhc3N1bWUgKHRoZXJlIHNob3VsZCBiZSBhcm91bmQgMjAgc3R1ZGVudHMgaW4gdGhlIHJvb20pIHRoYXQgd2Ugd2lsbCBvYnNlcnZlIHRoYXQgLSBmb3IgYXQgbGVhc3Qgb25lIG9mIHVzIC0gdGhlIHAtdmFsdWUgdHVybnMgb3V0IHRvIGJlIDw9IDAuMDUuIEFyZSB0aGVyZSB0aHVzICJ1bmJhbGFuY2VkIiIgZXVybyBjb2lucyBpbiBjaXJjdWxhdGlvbj8gT3Igbm90PwoKTGV0IHVzIGFzayB0aGUgY29tcHV0ZXIuICBXZSB3aWxsIHNpbXVsYXRlIHdoYXQgd2UganVzdCBkaWQgaW4gdGhlIHJvb20gZm9yIDEwLCAyMCwgMzAsIC4uLiAxMDAgc3R1ZGVudHMgYW5kIHNlZSBob3cgbWFueSBjb2lucyBhcmUgLSBvbiBhdmVyYWdlIC0gZGVjbGFyZWQgInVuYmFsYW5jZWQiIChwIDw9IDAuMDUpIHBlciAiY2xhc3MiLiAgR2l2ZW4gdGhhdCB3ZSBzaW11bGF0ZWQgYmFsYW5jZWQgY29pbnMgaW4gdGhlIGNvbXB1dGVyIChhbmQgYXNzdW1pbmcgd2UgZGlkIHRoaXMgY29ycmVjdGx5KSB0aGVzZSBhcHBhcmVudGx5IHVuYmFsYW5jZWQgY29pbnMgc2hvdWxkIGFsbCBiZSAqKmZhbHNlIHBvc2l0aXZlcyoqLiAKCmBgYHtyfQojIEJ1aWxkaW5nIGEgZnVuY3Rpb24gdGhhdCBtaW1pY3Mgc2VyaWVzIG9mICJoZWFkcyBhbmQgdGFpbCIKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm5yX3Rvc3NlcyA9IDMwMApzZXJpZXMgPC0gc2FtcGxlKDA6MSxucl90b3NzZXMsIHJlcGxhY2UgPSBUUlVFKQpzZXJpZXMKbnJfaGVhZHMgPC0gc3VtKHNlcmllcykKbnJfaGVhZHMKYmluX3Rlc3QgPC0gYmlub20udGVzdCh4ID0gbnJfaGVhZHMsIG5yX3Rvc3NlcywgcCA9IDAuNSwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikKYmluX3Rlc3QgPC0gYmlub20udGVzdCh4ID0gc3VtKHNhbXBsZSgwOjEsbnJfdG9zc2VzLCByZXBsYWNlID0gVFJVRSkpLCBucl90b3NzZXMsIHAgPSAwLjUsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpCmJpbl9wIDwtIGJpbl90ZXN0JHAudmFsdWUKYmluX3AKY29pbl90ZXN0IDwtIGZ1bmN0aW9uKG4pewogIGJpbl90ZXN0IDwtIGJpbm9tLnRlc3QoeCA9IHN1bShzYW1wbGUoMDoxLG4sIHJlcGxhY2UgPSBUUlVFKSksbiAsIHAgPSAwLjUsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpCiAgYmluX3AgPC0gYmluX3Rlc3QkcC52YWx1ZQogIGJpbl9wCn0KY29pbl90ZXN0KG5yX3Rvc3NlcykKCiMgQXBwbHlpbmcgdGhlIHRlc3QgdG8gY2xhc3NlcyByYW5naW5nIGZyb20gMTIwIHRvIDEwMCBzdHVkZW50cywgd2l0aCAxMDAgcmVwZXRpdGlvbnMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKTlJfRlA8LW1hdHJpeCgxOjEwMDAsIG5yb3c9MTAwLCBieXJvdz1UUlVFKQojTlJfRlAgPC1kYXRhLmZyYW1lKFNUMTA9MToxMDAwLFNUMjA9MCxTVDMwPTAsU1Q0MD0wLFNUNTA9MCxTVDYwPTAsU1Q3MD0wLFNUODA9MCxTVDkwPTAsU1QxMDA9MCkKZm9yIChpIGluIDE6MTAwKXsKICBmb3IgKGogaW4gMToxMCl7CiAgICBzdHVkX3NlciA8LSByZXBsaWNhdGUoaioxMCxjb2luX3Rlc3QobnJfdG9zc2VzKSkKICAgIE5SX0ZQW2ksal0gPC0gc3VtKHN0dWRfc2VyIDw9IDAuMDUpCiAgfQp9CmhlYWQoTlJfRlAsMykKYm94cGxvdChOUl9GUCkKZm9yIChpIGluIDE6MTApewogIG1lYW5fZnAgPC0gbWVhbihOUl9GUFssaV0pICAKfQptZWFuX2ZwCmBgYAoKVGh1cywgZXZlbiB3aGVuIGFsbCBjb2lucyBhcmUgYmFsYW5jZWQsIGEgY2VydGFpbiBwcm9wb3J0aW9uIG9mIHN0dWRlbnRzIHdpbGwgdGhyb3cgYSBzZXJpZXMgb2YgaGVhZHMgYW5kIHRhaWxzIHdpdGggcCA8PSAwLjA1IHVuZGVyIHRoZSBudWxsLiAgSW4gdGhlIGV4YW1wbGUsIHRoaXMgcHJvcG9ydGlvbiBpcyBvZiB0aGUgb3JkZXIgb2YgMC44MyBzdHVkZW50cyBvbiBhdmVyYWdlIHBlciBjbGFzcyBvZiAyMCwgYW5kIDQgc3R1ZGVudHMgb24gYXZlcmFnZSBwZXIgY2xhc3Mgb2YgMTAwLiAgWW91IHdpbGwgbm90aWNlIHRoYXQgdGhpcyB2YWx1ZSBpcyBzbGlnaGx0bHkgYmVsb3cgNSUuCgpJbiBmYWN0LCBhbmQgKipieSBkZWZpbml0aW9uKiosIHdlIGV4cGVjdCA1JSBvZiB0aGUgcmVhbGl6ZWQgdGVzdHMgdG8gYmUgc2lnbmlmaWNhbnQgYXQgdGhlIDUlIGxldmVsLCBpLmUuIHdpdGggcCA8PSAwLjA1LiBVc2luZyB0aGlzIHRocmVzaG9sZCwgd2UgZXhwZWN0IHRvIGhhdmUgb25lIGZhbHNlLXBvc3RpdmUgZXZlcnkgMjAgdGVzdHMsIGkuZS4gdGhlICoqVHlwZSBJIGVycm9yIHJhdGUqKi4KClRoZSByZWFzb24gd2h5IHdlIG9ic2VydmVkIGEgc2xpZ2h0bHkgbG93ZXIgVHlwZSBJIGVycm9yIHJhdGUgaW4gdGhlIGV4YW1wbGUgcmVmbGVjdHMgc29tZSBpZGlvc3luY3Jhc2llcyBvZiB0aGUgYmlub21pYWwgZGlzdHJpYnV0aW9uLiAgSWYgd2UgaW5jcmVhc2UgdGhlIHNpemUgb2YgdGhlIHNlcmllcyAoaS5lLiB0aGUgbnVtYmVyIG9mIHRvc3NlcyksIHdlIGluZGVlZCBvYnRhaW4gdmVyeSBjbG9zZSB0byB0aGUgZXhwZWN0ZWQgVHlwZSBFcnJvciByYXRlIG9mIEkgd2l0aCAibm9taW5hbCIgcC12YWx1ZSB0aHJlc2hvbGQgb2YgMC4wNS4KCmBgYHtyfQpucl90b3NzZXM9MTUwMDAKc3VtKHNhbXBsZSAoeD0wOjEsc2l6ZT1ucl90b3NzZXMsIHJlcGxhY2U9VFJVRSkpCnJlcGxpY2F0ZSgyMCwyKnBiaW5vbShucl90b3NzZXMvMi1hYnMoc3VtKHNhbXBsZSAoeD0wOjEsc2l6ZT1ucl90b3NzZXMsIHJlcGxhY2U9VFJVRSkpLW5yX3Rvc3Nlcy8yKSxzaXplPW5yX3Rvc3Nlcyxwcm9iPTAuNSkpCnBzaW0yPC1yZXBsaWNhdGUoMjAwMDAsMipwYmlub20obnJfdG9zc2VzLzItYWJzKHN1bShzYW1wbGUgKHg9MDoxLHNpemU9bnJfdG9zc2VzLCByZXBsYWNlPVRSVUUpKS1ucl90b3NzZXMvMiksc2l6ZT1ucl90b3NzZXMscHJvYj0wLjUpKQpoaXN0KHBzaW0yLGJyZWFrcz1zZXEoLTAuMSwxLjEsMC4wNSksIGJvcmRlciA9ICJyZWQiKQpgYGAKClRoZSBncmFwaCBzaG93cyB0aGF0IHRoZSBkaXN0cmlidXRpb24gb2YgcC12YWx1ZXMgdW5kZXIgdGhlIG51bGwgaXMgKioidW5pZm9ybSIqKiwgaS5lLiA1JSBvZiB0aGUgdGVzdHMgaGF2ZSBwLXZhbHVlIDAgPCBwIDwgMC4wNSwgNSUgaGF2ZSBwLXZhbHVlIDAuMDUgPCBwIDwgMC4xMCwgNSUgaGF2ZSBwLXZhbHVlIDAuMTAgPCBwIDwgMC4xNSwgZXRjIC4uLiBBbmQgdGhpcyBpcyBleGFjdGx5IHdoYXQgb25lIHdvdWxkIGV4cGVjdGVkIGdpdmVuIHRoZSB2ZXJ5IHdheSB0aGUgcC12YWx1ZXMgd2VyZSBkZWZpbmVkICh0aGluayBhYm91dCB0aGlzIC4uLikuICAKCkEgdmVyeSBjb21tb24gd2F5IHRvIGV4YW1pbmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwLXZhbHVlcyBmb3IgYSBudW1iZXIgb2YgdGVzdHMgaXMgYnkgbWVhbnMgb2YgKioiUVEtcGxvdHMiKiogKG9yIFF1YW50aWxlLVF1YW50aWxlIFBsb3RzKS4gVGhlIGZvbGxvd2luZyBjb2RlIGdlbmVyYXRlcyBhIFFRIHBsb3QgZm9yIHRoZSBzYW1lIHNldCBvZiBzaW11bGF0aW9ucy4gIAoKYGBge3J9CiMgRnVuY3Rpb24gZ2VuZXJhdGluZyBhIFFRIHBsb3Qgb2YgcC12YWx1ZXMgImJvcnJvd2VkIiBmcm9tIHRoZSBpbnRlcm5hdAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKZ2dkLnFxcGxvdCA9IGZ1bmN0aW9uKHB2ZWN0b3IsIG1haW49TlVMTCwgLi4uKSB7CiAgbyA9IC1sb2cxMChzb3J0KHB2ZWN0b3IsZGVjcmVhc2luZz1GKSkKICBlID0gLWxvZzEwKCAxOmxlbmd0aChvKS9sZW5ndGgobykgKQogIHBsb3QoZSxvLHBjaD0xOSxjZXg9MSwgbWFpbj1tYWluLCAuLi4sCiAgICAgICB4bGFiPWV4cHJlc3Npb24oRXhwZWN0ZWR+fi1sb2dbMTBdKGl0YWxpYyhwKSkpLAogICAgICAgeWxhYj1leHByZXNzaW9uKE9ic2VydmVkfn4tbG9nWzEwXShpdGFsaWMocCkpKSwKICAgICAgIHhsaW09YygwLG1heChlKSksIHlsaW09YygwLG1heChvKSkpCiAgbGluZXMoZSxlLGNvbD0icmVkIikKfQpnZ2QucXFwbG90KHBzaW0yKQpgYGAKCkNsZWFybHksIHdlIGhhdmUgdG8gZG8gc29tZXRoaW5nIGFib3V0IHRoaXMgaWYgd2Ugd2FudCB0byBhdm9pZCBnZW5lcmF0aW5nIGZhbHNlIHBvc2l0aXZlcy4gIElmIG91ciBleHBlcmltZW50IGVudGFpbHMgdGhlIHJlYWxpemF0aW9uIG9mIG11bHRpcGxlIHRlc3RzIChmLmkuIG9uZSBleHBlcmltZW50IGNvdWxkIGJlIGEgY2xhc3Mgb2YgMjAgc3R1ZGVudHMgcmVhbGl6aW5nIHRvZ2V0aGVyIDIwIHRlc3RzKSwgd2UgbmVlZCB0byBhZGp1c3QgdGhlIHRocmVzaG9sZCB2YWx1ZSBzdWNoIHRoYXQgZmFsc2UgcG9zaXRpdmVzIGFyZSBvbmx5IGV4cGVjdGVkIG9uY2UgZXZlcnkgMjAgKipleHBlcmltZW50cyoqLiAgU3VjaCBhIHRocmVzaG9sZCBpcyByZWZlcnJlZCB0byBhcyBhbiAqKmV4cGVyaW1lbnQtd2lkZSB0aHJlc2hvbGQqKi4gIEEgdGVzdCB0aGF0IHlpZWxkcyBhIHAtdmFsdWUgPCB0byB0aGlzIHRocmVzaG9sZCBpcyBzYWlkIHRvIGJlICoqZXhwZXJpbWVudC13aWRlIHNpZ25pZmljYW50KiouICBBIHRlc3QgdGhhdCB5aWVsZHMgYSBwLXZhbHVlIDwgdG8gdGhlIHVuY29ycmVjdGVkIChvciAqKm5vbWluYWwqKikgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCBvZiAwLjA1IGlzIHNhaWQgdG8gYmUgKipub21pbmFsbHkgc2lnbmlmaWNhbnQqKi4gIFBlb3BsZSBzb21ldGltZXMgYWxzbyB1c2UgKipzdWdnZXN0aXZlIHRocmVzaG9sZHMqKi4gIFRoZSBzdWdnZXN0aXZlIHRocmVzaG9sZCBpcyBleHBlY3RlZCB0byBiZSAiZXhjZWVkZWQiIG9uIGF2ZXJhZ2Ugb25jZSBwZXIgZXhwZXJpbWVudCAodW5kZXIgdGhlIG51bGwpLiBJIHdpbGwgbm90IGdvaW5nIGluIGEgZGV0YWlsZWQgZGVzY3JpcHRpb24gb2YgdGhlIHN1Z2dlc3RpdmUgdGhyZXNob2xkLgoKKipUSEUgRkFDVCBUSEFUIE1BTlkgU0NJRU5USVNUUyBETyBOT1QgUkVBTElaRSBUSElTIFNVRkZJQ0lFTlRMWSBJUyBPTkUgT0YgVEhFIE1BSU4gQ0FVU0VTIFdIWSBUT08gTUFOWSBSRVNVTFRTIFJFUE9SVEVEIElOIFRIRSBMSVRFUkFUVVJFIEFSRSBGQUxTRSBQT1NJVElWRVMuIEpVU1QgUkVBTElaRSAyMCBCT0dVUyBURVNUUyAoRVhQUklNRU5UUykgRVZFUlkgWUVBUiwgQVBQTFkgQSA1JSBTSUdOSUZJQ0FOQ0UgVEhSRVNIT0xEIFRPIEFMTCBZT1VSIFRFU1RTLCBBTkQgWU9VIEFSRSBCT1VORCBUTyBSRVBPUlQgT05FIEZQIElOIFlPVVIgWUVBUkxZIFBBUEVSLiBJIEdVRVNTIFlPVSBNVVNUIFNUQVJUIFRPIFNFRS9GRUVMIE9ORSBPRiBUSEUgRElGRklDVUxUSUVTOiBXSEVSRSBETyBFWFBFUklNRU5UUyBCRUdJTiBBTkQgRU5EPyBETyBXRSBORUVEIEEgTElGRS1USU1FIFNJR05JRklDQU5DRSBUSFJFU0hPTEQ/KiogIAoKSG93IGRvIHdlIHByb3Blcmx5IGFkanVzdCB0aGUgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCB3aGVuIHBlcmZvcm1pbmcgbXVsdGlwbGUgdGVzdHM/ICAKCkFzc3VtZSB0aGF0IHdlIHBlcmZvcm0gKm4qIHRlc3RzLCB0aGUgYWRqdXN0ZWQgdGhyZXNob2xkIGNhbiBiZSBkZXJpdmVkIHVzaW5nICoqU2lkYWsncyBjb3JyZWN0aW9uKio6CgowLjA1ID0gMS0oMS1wX2MpXm4KCmhlbmNlIGNvcnJlc3BvbmRpbmcgdG8KCnBfYyA9IDEgLSAxMF4obG9nMTAoMC45NSkvbikKClRoaXMgdGhyZXNob2xkIGlzIG1vcmUgb2Z0ZW4gYXBwcm94aW1hdGVkIHVzaW5nIHRoZSBzaW1wbGVyICoqQm9uZmVycm9uaSBjb3JyZWN0aW9uKio6CgpwX2MgPSAwLjA1L24KCmBgYHtyfQp0ID0gMC4wNQpTSURfQk9OIDwtIGRhdGEuZnJhbWUobj0xOjEwMDAsU0lEQUs9MCxCT05GPTAsTFNJREFLPTAsTEJPTkY9MCkKU0lEX0JPTlssMl0gPSByb3VuZCgxLTEwXihsb2cxMCgxLXQpL1NJRF9CT05bLDFdKSxkaWdpdHM9MTApClNJRF9CT05bLDNdID0gcm91bmQodC9TSURfQk9OWywxXSxkaWdpdHM9MTApClNJRF9CT05bLDRdID0gLWxvZzEwKDEtMTBeKGxvZzEwKDEtdCkvU0lEX0JPTlssMV0pKQpTSURfQk9OWyw1XSA9IC1sb2cxMCh0L1NJRF9CT05bLDFdKQpTSURfQk9OCgpwbG90KFNJRF9CT05bLDRdLFNJRF9CT05bLDVdLGNvbD0icmVkIiwgeGxhYiA9ICJMX1NJREFLIiwgeWxhYiA9ICJMX0JPTkYiKQpwbG90KFNJRF9CT05bLDFdLFNJRF9CT05bLDRdLCBjb2w9InJlZCIsIHhsYWIgPSAiTl90ZXN0cyIsIHlsYWIgPSAiTF9CT05GIHRocmVzaG9sZCIpCmBgYAogIApUaGUgZ3JhcGhzIHNob3cgdGhhdCAoaSkgdGhlIEJvbmZlcnJvbmkgY29ycmVjdGlvbiBpcyBhbiBleGNlbGxlbnQgYXBwcm94aW1hdGlvbiwgYW5kIChpaSkgdGhlIGVmZmVjdCBvZiB0aGUgbnVtYmVyIG9mIHRlc3RzIChYIGF4aXMpIG9uIHRoZSBwLXZhbHVlIChpbiAtbG9nIHVuaXRzKSB0aGF0IG5lZWRzIHRvIGJlIGFwcGxpZWQgdG8gY29udHJvbCB0aGUgZXhwZXJpbWVudC13aWRlIHR5cGUgSSBlcnJvciBhdCAwLjA1LiAgCgoqKkVYRVJDSUNFKioKClRyeSB0byBnZW5lcmF0ZSBhIHNtYWxsIHNjcmlwdCB0aGF0IHNob3dzIHRoYXQgd2hlbiB5b3UgYXBwbHkgU2lkYWsncyBvciBCb25mZXJyb25pJ3MgY29ycmVjdGlvbiB5b3Ugb25seSBvYnRhaW4gZmFsc2UgcG9zaXRpdmVzIChGUCkgZXZlcnkgMjAgZXhwZXJpbWVudHMgY29uZHVjdGVkLiBTb21lIGV4cGVyaW1lbnRzIHdpbGwgeWllbGQgMCBGUCdzLCBzb21lIDEsIHNvbWUgMiwgc29tZSAzLCAuLi4gVGhlIHRocmVzaG9sZCBpcyBzdWNoIHRoYXQgdGhlIHByb3BvcnRpb24gb2YgZXhwZXJpbWVudHMgd2l0aCAwIEZQIGNvcnJlc3BvbmRzIHRvIDk1JSBvZiB0aGUgZXhwZXJpbWVudHMuICAKCioqUkVUVVJOSU5HIFRPIEdFTkVUSUMgQVNTT0NJQVRJT04gU1RVRElFUyoqCgpXaGVuIHBlcmZvcm1pbmcgKioiR2Vub21lLVdpZGUgQXNzb2NpYXRpb24gU3R1ZGllcyIgb3IgR1dBUyoqLCBvbmUgcGVyZm9ybXMgKGFzIGluIGFsbCAtb21pYyBzdHVkaWVzKSBtYW55LCBtYW55IHRlc3RzIChodW5kcmVkcyBvZiB0aG91c2FuZHMgdG8gbWlsbGlvbnMpLiBJbiB0aGlzIGNhc2UsIGV2ZXJ5IFNOUCBpcyB0ZXN0ZWQgZm9yIGl0cyBhc3NvY2lhdGlvbiB3aXRoIHRoZSBkaXNlYXNlLiAgQXBwbHlpbmcgYSBub21pbmFsIHRocmVzaG9sZCBvZiAwLjA1IGlzIHRoZXJlZm9yZSBib3VuZCB0byBnaXZlIGEgRlAgZXZlcnkgMjAgU05QcyB0ZXN0ZWQuICBXZSB0aGVyZWZvcmUgaGF2ZSB0byBjb3JyZWN0IHRoZSB0aHJlc2hvbGQgYWNjb3JkaW5nbHkgdG8gY29udHJvbCB0aGUgcmF0ZSBvZiBGUHMuICAKCkluIHRoZSBwcmV2aW91cyBleGFtcGxlIHdlIHRlc3RlZCA0MjAgU05Qcy4gIEEgc2ltcGxlIHdheSBpcyB0aGVyZWZvcmUgdG8gY29ycmVjdCB0aGUgMC4wNSB0aHJlc2hvbGQgZm9yIHRoZSByZWFsaXphdGlvbiBvZiA0MjAgdGVzdHMgdXNpbmcgZWl0aGVyIFNpZGFrJ3Mgb3IgQm9uZmVycm9uaSdzIGVxdWF0aW9uLgoKYGBge3J9CnBsb3QoUkVTX0dXQVNbLDFdLFJFU19HV0FTWywxMV0sY29sPSJyZWQiLCB4bGFiID0gIk9SREVSRUQgU05QcyIsIHlsYWIgPSAiLWxvZyhwKSIpCmFibGluZShoID0gLWxvZzEwKDAuMDUpKQphYmxpbmUoaCA9IC1sb2cxMCgwLjA1Lyhucl92YXIpKSwgbHR5ID0gMikKYGBgCiAgClRoZSBwbGFpbiBob3Jpem9udGFsIGxpbmUgY29ycmVzcG9uZHMgdG8gdGhlIG5vbWluYWwgKHVuY29ycmVjdGVkKSB0aHJlc2hvbGQgb2YgMC4wNSwgd2hpbGUgdGhlIGRhc2hlZCBob3Jpem9udGFsIGxpbmUgY29ycmVzcG9uZHMgdGhlIHRocmVzaG9sZCwgQm9uZmVycm9uaS1jb3JyZWN0ZWQgZm9yIHRoZSByZWFsaXphdGlvbiBvZiA0MjAgdGVzdHMsIHRoYXQgc2hvdWxkIGNvbnRyb2wgdGhlIGV4cGVyaW1lbnQtd2lkZSBmYWxzZSBwb3NpdGl2ZSByYXRlIHRvIG5vIG1vcmUgdGhhbiAwLjA1LiAgCgpUaGlzIG1heSwgaG93ZXZlciwgYmUgb3ZlcmtpbGwuICBJbmRlZWQsIG91ciBnZW5vbWUgaXMgY2hhcmFjdGVyaXplZCBieSBhIHBoZW5vbWVub24gY2FsbGVkICoqImxpbmthZ2UgZGlzZXF1aWxpYnJpdW0iIG9yIExEKiouICBUaGlzIG1lYW5zIHRoYXQgdGhlIGdlbm90eXBlcyBvZiBjbG9zZWx5IGxpbmtlZCBTTlBzIGFyZSAiY29ycmVsYXRlZCIsIGkuZS4gdGhleSBjYW4gYmUgdmVyeSBzaW1pbGFyIHRvIGVhY2ggb3RoZXIuICBJbmRpdmlkdWFscyB0aGF0IGFyZSBoZXRlcm96eWdvdXMgZm9yIHRoZSBmaXJzdCBTTlAgKHNheSB3aXRoIGFsbGVsZXMgKkEqIGFuZCAqYSopIHdpbGwgdGVuZCB0byBiZSBoZXRlcm96eWdvdXMgZm9yIHRoZSBzZWNvbmQgU05QIChzYXkgd2l0aCBhbGxlbGVzICpCKiBhbmQgKmIqKS4gIEluZGl2aWR1YWxzIHRoYXQgYXJlIGhvbW96eWdvdXMgKkFBKiBtYXkgdGVuZCB0byBiZSBtb3JlIG9mdGVuICpiYiogdGhhbiBleHBlY3RlZCBieSBjaGFuY2UuIEluIG90aGVyIHdvcmRzLCB0aGUgZ2Vub3R5cGVzIGF0IHRoZSAiKkEqIiBhbmQgIipCKiIgU05QcyBhcmUgbm90IGluZGVwZW5kZW50LiAgQXQgdGhlIGV4dHJlbWUgKCJwZXJmZWN0IExEIikgdGhlIGdlbm90eXBlcyBvZiB0d28gYWRqYWNlbnQgU05QcyBtYXkgYmUgcGVyZmVjdGx5IHJlZHVuZGFudCBpbiB0aGUgc3R1ZGllZCBjb2hvcnQocyk6IGlmIHlvdSBrbm93IG9uZSwgeW91IGNhbiBwZXJmZWN0bHkgcHJlZGljdCB0aGUgb3RoZXIuICBUd28gU05QcyBpbiBwZXJmZWN0IExEIGNsZWFybHkgZG8gbm90IGNvcnJlc3BvbmQgdG8gdHdvIGRpZmZlcmVudCB0ZXN0czsgdGhleSBhcmUgb25lIGFuZCB0aGUgc2FtZS4gIElmICp4KiBzdWNoIHBhaXJzIGV4aXN0ZWQgaW4gb3VyIGRhdGFzZXQsIHRoZSBhY3R1YWwgbnVtYmVyIG9mIHJlYWxpemVkIHRlc3RzIHdvdWxkIGJ5IDQyMC0qeCosIGhlbmNlIHlpZWxkaW5nIGEgbGVzcyBzdHJpbmdlbnQgZXhwZXJpbWVudC13aWRlIHRocmVzaG9sZCAob2Z0ZW4gcmVmZXJyZWQgdG8gYXMgKipnZW5vbWUtd2lkZSoqIGluIHRoZSBjYXNlIG9mIEdXQVMpLiAgCgpGb3IgdHdvIFNOUHMgdGhhdCBhcmUgbm90IHBlcmZlY3RseSByZWR1bmRhbnQsIHlldCBzdGlsbCBpbiBMRCwgdGhlIG91dGNvbWUgb2YgdGhlIGFzc29jaWF0aW9uIHRlc3Qgd2lsbCB0ZW5kIHRvIGJlIGNvcnJlbGF0ZWQuICBUaGV5IGNhbiBub3QgYmUgc2VlbiBhcyB0d28gaW5kZXBlbmRlbnQgdGVzdHMgZWl0aGVyLiBUb2dldGhlciwgdGhleSBhY2NvdW50IG1heWJlIGZvciAxLjUgYnV0IG5vdCBmb3IgMiB0ZXN0cy4gVGhlIHF1ZXN0aW9uIHRodXMgYmVjb21lczogdG8gKipob3cgbWFueSBpbmRlcGVuZGVudCB0ZXN0cyoqIGRvZXMgb3VyIGxpdHRsZSBHV0FTIGNvcnJlc3BvbmRzPyAgSWYgd2Uga25ldyB0aGF0IHdlIGNvdWxkIGFwcGx5IHRvIGFwcHJvcHJpYXRlIFNpZGFrL0JvbmZlcnJvbmkgY29ycmVjdGlvbiB0byBkZXRlcm1pbmUgdGhlIGNvcnJlY3QgZXhwZXJpbWVudC13aWRlIHRocmVzaG9sZC4gICAKClRoZXJlIGFyZSBhIG51bWJlciBvZiB3YXlzIHRvIGFjaGlldmUgdGhpcy4gICoqUGVybXV0YXRpb24gdGVzdGluZyBwcm92aWRlcyBhIHZlcnkgaW50ZXJlc3Rpbmcgd2F5IHRvIGNvcnJlY3QgZm9yIHRoZSBlZmZlY3RpdmUgbnVtYmVyIG9mIHRlc3RzIHBlcmZvcm1lZCoqLCBhcyB3ZSB3aWxsIG5vdyBzZWUuICAKCldlIHByZXZpb3VzbHkgKHNlZSBhYm92ZSkgdXNlZCBhIHBlcm11dGF0aW9uIHRlc3QgdG8gZXZhbHVhdGUgdGhlIHNpZ25pZmljYW5jZSBvZiB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiBvbmUgU05QIGFuZCB0aGUgZGlzZWFzZS4gIFRoZSBhZmZlY3Rpb24gc3RhdHVzIHdhcyBzaHVmZmxlZCBhY3Jvc3MgdGhlIGluZGl2aWR1YWxzIGhlbmNlIGRpc2Nvbm5lY3RpbmcgYW55IHBvc3NpYmxlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGdlbm90eXBlIGFuZCBwaGVub3R5cGUgKD0gZGlzZWFzZSkuICBXZSBhcmUgZ29pbmcgdG8gZG8gdGhlIHNhbWUgdGhpbmcgaGVyZSwgYnV0IHJhdGhlciB0aGFuIHRlc3Rpbmcgb25lIFNOUCBvbmx5LCB3ZSBhcmUgZ29pbmcgdG8gdGVzdCBhbGwgdGhlIFNOUHMgd2l0aCB0aGUgc2FtZSBwaGVub3R5cGUgcGVybXV0YXRpb24uICBUaHVzIHdlIGFyZSBnb2luZyB0byBwZXJmb3JtIHRoZSBzYW1lIG11bHRpcGxlIHRlc3RzIGFzIHdlIGRpZCB3aXRoIHRoZSByZWFsIGRhdGEuICBXZSB3YW50IHRvIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgYmV0d2VlbiB0ZXN0cyB0aGF0IGV4aXN0ZWQgd2l0aCB0aGUgcmVhbCBkYXRhIChkdWUgdG8gTEQgYmV0d2VlbiB0aGUgU05QcyksIGlzIGZhaXRoZnVsbHkgbWFpbnRhaW5lZCBpbiB0aGUgcGVybXV0YXRpb25zLiAgVGh1cywgd2Ugc2h1ZmZsZSB0aGUgcGhlbm90eXBlcyBiZXR3ZWVuIHRoZSBpbmRpdmlkdWFscywgYnV0IHRoZSAidmVjdG9ycyIgb2YgaW5kaXZpZHVhbCBnZW5vdHlwZXMgcmVtYWluIHVuYWx0ZXJlZC4gIFRodXMsIGlmIHRoZSAqQWEqIGdlbm90eXBlIGF0IFNOUCAiKkEqIiB3YXMgcHJlZmVyZW50aWFsbHkgYXNzb2NpYXRlZCB3aXRoIHRoZSAqQmIqIGdlbm90eXBlIGF0IFNOUCAiKkIqIiBpbiB0aGUgcmVhbCBkYXRhLCB0aGlzIHdpbGwgcmVtYWluIHNvIGluIHRoZSBwZXJtdXRlZCBkYXRhLiAgCgpXZSBzdGlsbCB3YW50IHRvIGNvbXBhcmUgdGhlIGFsbGVsaWMgZnJlcXVlbmNpZXMgYmV0d2VlbiBjYXNlcyBhbmQgY29udHJvbHMgaW4gdGhlIHBlcm11dGF0aW9ucy4gIEJ1dCB0aGlzIHRpbWUsIHdlIGhhdmUgdG8gcGF5IGF0dGVudGlvbiB0aGF0IG91ciBtZWFzdXJlIGJlIGNvbXBhcmFibGUgYWNyb3NzIFNOUHMuICBJdCBzaG91bGRuJ3QgZm9yIGluc3RhbmNlIGJlIGRlcGVuZGVudCBvbiAqZl9hKiwgd2hpY2ggKmRlbHRhKiBpcy4gIEEgZ29vZCBpZGVhIGluIHRoaXMgY2FzZSBpcyB0byBmaW5kIGluc3BpcmF0aW9uIGluIGNsYXNzaWMgc3RhdGlzdGljcywgaS5lLiB1c2UgdGhlIHRyYW5zZm9ybWF0aW9ucyBzaW1pbGFyIHRvIHRob3NlIHlpZWxkaW5nIHRoZSBjaGktc3F1YXJlZCwgdCBhbmQgRiB0ZXN0LCBvciBldmVuIHRoZSBlbnN1aW5nIHAtdmFsdWVzLiAgVGhpcyBpcyB3aGF0IEkgd2lsbCBiZSBkb2luZyBoZXJlLCB1c2luZyB0aGUgIkNUIiB0ZXN0LiAgCgpUaHVzLCBmb3IgZWFjaCBwZXJtdXRhdGlvbiB3ZSB3aWxsIGtlZXAgdGhlICoqYmVzdCBwLXZhbHVlKiogKG9yIC1sb2cocC12YWx1ZSkpLiAgSWYgd2UgcGVyZm9ybSAqbl9wZXJtKiBzdWNoIHBlcm11dGF0aW9ucywgd2Ugd2lsbCB0aGVyZWZvcmUgZW5kIHVwIHdpdGggYSBsaXN0IG9mICpuX3Blcm0qIGJlc3QgcC12YWx1ZXMuIFdlIGNhbiByYW5rIG9yIHNvcnQgdGhlc2UgYmVzdCBwLXZhbHVlcy4gIFRoZSA1JSBleHBlcmltZW50LXdpZGUgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCB0aGVuIGNvcnJlc3BvbmRzIHRvIHRoZSA1JSBwZXJjZW50aWxlIG9mIHRoaXMgbGlzdCwgaS5lLiBhIHZhbHVlIHRoYXQgd2FzIG9ubHkgIm1hdGNoZWQiIG9yICJleGNlZWRlZCIgKG1lYW5pbmcgYW4gZXF1YWwgb3IgbG93ZXIgYmVzdCBwLXZhbHVlIGZvdW5kKSBmb3IgNSUgb2YgcGVybXV0YXRpb25zLiBbV2UgY2FuIGRvIHRoZSBzYW1lIHRoaW5nIHVzaW5nIC1sb2cocCkgdmFsdWVzLCBhbmQgZGV0ZXJtaW5lIHRoZSA5NSUgcGVyY2VudGlsZV0uIFRodXMsIHRoaXMgaXMgYW4gZWxlZ2FudCB3YXkgdG8gZGV0ZXJtaW5lIHRoZSBleHBlcmltZW50LXdpZGUgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCB0aGF0IGFwcHJvcHJpYXRlbHkgY29ycmVjdHMgZm9yIHRoZSBudW1iZXIgb2YgdGVzdHMgdGhhdCB3ZXJlIHBlcmZvcm1lZCBhbmQgdGhlaXIgY29ycmVsYXRpb25zLiAgCgpXZSBjYW4gdXNlIHRoZSBzYW1lIGFwcHJvYWNoIHRvIGRldGVybWluZSB0aGUgY29ycmVjdGVkIHAtdmFsdWUgZm9yIGVhY2ggU05QLiAgT25lIGp1c3QgaGFzIHRvIGRldGVybWluZSBpbiB3aGF0IGZyYWN0aW9uIG9mIHRoZSBwZXJtdXRhdGlvbnMgYW4gZXF1YWxseSAiZ29vZCIgb3IgImJldHRlciIgcC12YWx1ZSAob3IgLWxvZyhwKSkgdmFsdWUgd2FzIG9idGFpbmVkLiAgSXQgaXMgbm90ZXdvcnRoeSB0aGF0IGFjY3VyYXRlIGVzdGltYXRpb24gb2Ygc21hbGwgKGV4cGVyaW1lbnQtd2lkZSkgcC12YWx1ZXMgYnkgcGVybXV0YXRpb25zIHJlcXVpcmVzIHJ1bm5pbmcgYSBjb21tZW5zdXJhdGUgbnVtYmVyIG9mIHRoZW0uICAKCkxldCB1cyBpbGx1c3RyYXRlIHRoaXMgd2l0aCByZWFsIGRhdGEuICAKCmBgYHtyfQojIFByZXZpb3VzIG1pbmkgTWFuaGF0dGFuIHBsb3Qgd2l0aCBub21pbmFsayBhbmQgU2lkYWsvQm9uZmVycm9uaSBjb3JyZWN0ZWQgc2lnbmlmaWNhbmNlIHRocmVzaG9sZHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnBsb3QoUkVTX0dXQVNbLDFdLFJFU19HV0FTWywxMV0sY29sPSJyZWQiLCB4bGFiID0gIk9SREVSRUQgU05QcyIsIHlsYWIgPSAiLWxvZyhwKSIpCmFibGluZShoID0gLWxvZzEwKDAuMDUpKQphYmxpbmUoaCA9IC1sb2cxMCgwLjA1LyhuY29sKEdXQVMpLTMpKSwgbHR5ID0gMikKCiMgR2VuZXJhdGluZyBhIGRhdGEgZnJhbWUgKHdpdGggc2FtZSBzdHJ1Y3R1cmUgYXMgUkVTX0dBV0FTKSB0byBzdG9yZSB0aGUgcmVzdWx0cyBvZiB0aGUgcGVybXV0YXRpb25zIChTSC11ZmZsZXMpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAKU0hfR1dBUyA8LSBkYXRhLmZyYW1lKFNOUCA9IDE6KG5jb2woR1dBUyktMyksIENIUiA9IDAsIFBPUz0wLCBOUl9HRU5fQ1RSPTAsIEFMVF9GUl9DVFI9MCwgTlJfR0VOX0NBUz0wLCBBTFRfRlJfQ0FTPTAsIEFMVF9GUl9BTEw9MCwgCiAgICAgICAgICAgICAgICAgICAgICBDSElTUT0wLCBMUF9DSElTUT0wLCBMUF9DSElTUV8yPTAsIExSVD0wLCBMUF9MUlQ9MCwgTFBfUEVSTT0wKQpTSF9HV0FTCgojIERlZmluZSBmdW5jdGlvbiB0byBjb21wdXRlIHAtdmFsdWUgYmFzZWQgb24gQ1QgdGVzdAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpteWNoaV9zaCA8LSBmdW5jdGlvbihpKXsKICBjdDwtbWF0cml4KGMoMipTSF9HV0FTW2ksNF0qU0hfR1dBU1tpLDVdLDIqU0hfR1dBU1tpLDRdKigxLVNIX0dXQVNbaSw1XSksMipTSF9HV0FTW2ksNl0qU0hfR1dBU1tpLDddLDIqU0hfR1dBU1tpLDZdKigxLVNIX0dXQVNbaSw3XSkpLCBucm93PTIsIGJ5cm93PVRSVUUpCiAgWHNxIDwtIGNoaXNxLnRlc3QoY3QsY29ycmVjdD1GQUxTRSkKICBYc3EkcC52YWx1ZQp9CgojIENvbXB1dGUgcmVsZXZhbnQgc3RhdHMgZm9yIGFsbCBTTlBzIChXZSB3aWxsIHVzZSB0aGUgQ1QgdGVzdCBpbiB0aGlzIGV4YW1wbGUpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKZm9yIChpIGluIDE6bnJfdmFyKXsKICBTSF9HV0FTW2ksNF0gPSBzdW0oKEdXQVNbLGkrM10gPT0gMCB8IEdXQVNbLGkrM10gPT0gMSB8IEdXQVNbLGkrM10gPT0gMikgJiBHV0FTWywzXSA9PSAxLCBuYS5ybSA9IFRSVUUpCiAgU0hfR1dBU1tpLDVdID0gcm91bmQoc3VtKEdXQVNbLGkrM11bR1dBU1ssM10gPT0gMV0sIG5hLnJtID0gVFJVRSkvKDIqU0hfR1dBU1tpLDRdKSxkaWdpdHM9MykKICBTSF9HV0FTW2ksNl0gPSBzdW0oKEdXQVNbLGkrM10gPT0gMCB8IEdXQVNbLGkrM10gPT0gMSB8IEdXQVNbLGkrM10gPT0gMikgJiBHV0FTWywzXSA9PSAyLCBuYS5ybSA9IFRSVUUpCiAgU0hfR1dBU1tpLDddID0gcm91bmQoc3VtKEdXQVNbLGkrM11bR1dBU1ssM10gPT0gMl0sIG5hLnJtID0gVFJVRSkvKDIqU0hfR1dBU1tpLDZdKSxkaWdpdHM9MykKICBTSF9HV0FTW2ksMTFdID0gLWxvZzEwKG15Y2hpX3NoKGkpKQp9ClNIX0dXQVMKCgoKIyBEZWZpbmUgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgc2h1ZmZsZWQgZGF0YSwgY29tcHV0ZSB0aGUgY29ycmVzcG9uZGluZyBzdGF0cyBGT1IgQUxMIFNOUHMgKHZzIHByZXZpb3VzIGZ1bmN0aW9uKSwgCiNhbmQgZXh0cmFjdCB0aGUgdG9wIC1sb2cocCkgdmFsdWUgYWNyb29zIGFsbCBTTlBzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnNodWZmbGVfMiA8LSBmdW5jdGlvbigpewogIEdXQVNbLDNdIDwtIHNhbXBsZShBRkZfU1RBVFVTLHNpemUgPSA0MDAwLHJlcGxhY2UgPSBGQUxTRSkKICBmb3IgKGkgaW4gMTpucl92YXIpewogICAgU0hfR1dBU1tpLDRdID0gc3VtKChHV0FTWyxpKzNdID09IDAgfCBHV0FTWyxpKzNdID09IDEgfCBHV0FTWyxpKzNdID09IDIpICYgR1dBU1ssM10gPT0gMSwgbmEucm0gPSBUUlVFKQogICAgU0hfR1dBU1tpLDVdID0gcm91bmQoc3VtKEdXQVNbLGkrM11bR1dBU1ssM10gPT0gMV0sIG5hLnJtID0gVFJVRSkvKDIqU0hfR1dBU1tpLDRdKSxkaWdpdHM9MykKICAgIFNIX0dXQVNbaSw2XSA9IHN1bSgoR1dBU1ssaSszXSA9PSAwIHwgR1dBU1ssaSszXSA9PSAxIHwgR1dBU1ssaSszXSA9PSAyKSAmIEdXQVNbLDNdID09IDIsIG5hLnJtID0gVFJVRSkKICAgIFNIX0dXQVNbaSw3XSA9IHJvdW5kKHN1bShHV0FTWyxpKzNdW0dXQVNbLDNdID09IDJdLCBuYS5ybSA9IFRSVUUpLygyKlNIX0dXQVNbaSw2XSksZGlnaXRzPTMpCiAgICBTSF9HV0FTW2ksMTFdID0gLWxvZzEwKG15Y2hpX3NoKGkpKQogICAgYXNzaWduKCJTSF9HV0FTIixTSF9HV0FTLGVudmlyID0gZ2xvYmFsZW52KCkpCiAgfQogIE1BWCA8LSBtYXgoU0hfR1dBU1ssMTFdKQogIE1BWAogICNsaXN0KHJhbi5pbiA9IGVudmlyb25tZW50KCkscGFyZW50ID0gcGFyZW50LmVudihlbnZpcm9ubWVudCgpKSwgb2JqZWN0cyA9IGxzLnN0cihlbnZpcm9ubWVudCgpKSkKfQojIE5vdGUgdGhhdCB0aGUgb3V0Y29tZSBvZiB0aGUgbG9vcCBuZWVkcyB0byBiZSBhc3NpZ25lZCB0byBHV0FTIGluIGdsb2JhbGVudgoKIyBQZXJmb3JtIHBlcm11dGF0aW9ucyBhbmQgZ2VuZXJhdGUgbGlzdCBvZiBiZXN0IHAtdmFsdWVzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpucl9wZXJtPTEwMAptdWx0X3Rlc3QgPC0gcmVwbGljYXRlIChucl9wZXJtLHNodWZmbGVfMigpKQptdWx0X3Rlc3QKCiMgRXh0cmFjdCBleHBlcmltZW50LXdpZGUgdGhyZXNob2xkCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm10X3RocmVzaCA8LSBxdWFudGlsZShtdWx0X3Rlc3QsMC45NSkKbXRfdGhyZXNoCgojIEFkZCBuZXcgdGhyZXNob2xkIHRvIG1pbmkgTWFuaGF0dGFuIHBsb3QKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnBsb3QoUkVTX0dXQVNbLDFdLFJFU19HV0FTWywxMV0sY29sPSJyZWQiLCB4bGFiID0gIk9SREVSRUQgU05QcyIsIHlsYWIgPSAiLWxvZyhwKSIpCmFibGluZShoID0gLWxvZzEwKDAuMDUpKQphYmxpbmUoaCA9IC1sb2cxMCgwLjA1L25yX3ZhciksIGx0eSA9IDIpCmFibGluZShoID0gbXRfdGhyZXNoLCBsdHkgPSA0KQoKIyBEZXRlcm1pbmUgY29ycmVjdGVkIHAtdmFsdWVzIGZvciBpbmRpdmRpdWFsIFNOUHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKeD01LjQ5NTMxNmUrMDAKbXVsdF90ZXN0CihtdWx0X3Rlc3QgPj0geCkKc3VtKG11bHRfdGVzdCA+PSB4KQpzdW0obXVsdF90ZXN0ID49IHgpL25yX3Blcm0KLWxvZzEwKHN1bShtdWx0X3Rlc3QgPj0geCkvbnJfcGVybSkKCmZvciAoaSBpbiAxOm5yX3Zhcil7CiAgaWYgKHN1bShtdWx0X3Rlc3QgPj0gUkVTX0dXQVNbaSwxMV0pID09IDApewogICAgUkVTX0dXQVNbaSwxNV0gPSAtbG9nMTAoMS9ucl9wZXJtKQogIH0gZWxzZSB7CiAgICBSRVNfR1dBU1tpLDE1XSA9IC1sb2cxMChzdW0obXVsdF90ZXN0ID49IFJFU19HV0FTW2ksMTFdKS9ucl9wZXJtKQogIH0KfQpSRVNfR1dBUwoKIyBBZGQgY29ycmVjdGVkIHAtdmFsdWVzIHRvIE1hbmhhdHRhbiBwbG90CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKcG9pbnRzKFJFU19HV0FTWywxXSxSRVNfR1dBU1ssMTVdLGNvbD0iYmxhY2siKQpgYGAKCiNFeHBsb2l0aW5nIHRoZSBkaXN0cmlidXRpb24gb2Ygb2JzZXJ2ZWQgcC12YWx1ZXMgdG8gZXN0aW1hdGUgdGhlIEZhbHNlIERpc2NvdmVyeSBSYXRlIG9yIEZEUgoKSW4gdGhlIHByZXZpb3VzIHNlY3Rpb25zLCB3ZSBjYW1lIHRvIHJlYWxpemUgdGhhdCBtdWx0aXBsZSB0ZXN0aW5nIGlzIGFuIGltcG9ydGFudCBpc3N1ZSB0aGF0IG5lZWRzIHRvIGJlIGFkZHJlc3NlZCBieSBhZGp1c3RpbmcgdGhlIHNpZ25pZmljYW5jZSB0aHJlc2hvbGRzIGFjY29yZGluZ2x5LiAgVG8gZG8gdGhpcywgd2UgZGV0ZXJtaW5lZCB0aGUgKGVmZmVjdGl2ZSkgbnVtYmVyIG9mIHRlc3QgcGVyZm9ybWVkIChvbmUgd2F5IG9yIHRoZSBvdGhlcikgYW5kIHRoZW4gY29ycmVjdGVkIHRoZSB0aHJlc2hvbGRzIChvbmUgd2F5IG9yIHRoZSBvdGhlcikuICAKCkEgcXVpdGUgcmFkaWNhbGx5IGRpZmZlcmVudCBhbmQgaW50ZXJlc3RpbmcgYXBwcm9hY2ggY29uc2lzdHMgaW4gZXhhbWluaW5nIHRoZSBkaXN0cmlidXRpb24gb2Ygbm9taW5hbCBwLXZhbHVlcywgc2VlIGhvdyBpdCBjb21wYXJlcyB3aXRoIHRoZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBleHBlY3RlZCBpZiBhbGwgcGVyZm9ybWVkIHRlc3RzIGFyZSByZWFsIEgwIHRlc3QgKHNlZSBhYm92ZSksIGFuZCBsZWFybiBmcm9tIGl0LiAgCiAgCkxldCB1cyBnbyBiYWNrIHRvIG91ciBFdXJvIGNvaW5zLCBhbmQgZmlyc3QgcmUtZ2VuZXJhdGUgdGhlIHVuaWZvcm0gZGlzdHJpYnV0aW9uIG9mIHAtdmFsdWVzIGV4cGVjdGVkIGlmIGFsbCBjb2lucyBhcmUgYmFsYW5jZWQuICBBcyBhYm92ZSwgSSB3aWxsIHRlc3QgMjAsMDAwIGNvaW5zIGJ5IHRvc3NpbmcgZWFjaCBvZiB0aGVtIDE1LDAwMCB0aW1lcy4gIAogIApgYGB7cn0KIyBHZW5lcmF0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgcC12YWx1ZXMgZm9yIDIwLDAwMCBiYWxhbmNlZCBjb2lucwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm5yX2RyPTE1MDAwCnN1bShzYW1wbGUgKHg9MDoxLHNpemU9bnJfZHIsIHJlcGxhY2U9VFJVRSkpCnJlcGxpY2F0ZSgyMCwyKnBiaW5vbShucl9kci8yLWFicyhzdW0oc2FtcGxlICh4PTA6MSxzaXplPW5yX2RyLCByZXBsYWNlPVRSVUUpKS1ucl9kci8yKSxzaXplPW5yX2RyLHByb2I9MC41KSkKcHNpbTI8LXJlcGxpY2F0ZSgyMDAwMCwyKnBiaW5vbShucl9kci8yLWFicyhzdW0oc2FtcGxlICh4PTA6MSxzaXplPW5yX2RyLCByZXBsYWNlPVRSVUUpKS1ucl9kci8yKSxzaXplPW5yX2RyLHByb2I9MC41KSkKaGlzdChwc2ltMixicmVha3M9c2VxKC0wLjEsMS4xLDAuMDUpLCBib3JkZXIgPSAicmVkIiwgeGxhYiA9ICJCaW5uZWQgcC12YWx1ZXMiKQpgYGAKICAKV2Ugd2lsbCBub3cgcmVwZWF0IHRoZSBleHBlcmltZW50IHdpdGggMjAsMDAwIHVuYmFsYW5jZWQgY29pbnMuICBUaGUgcHJvYmFiaWxpdHkgdG8gb2J0YWluIGhlYWRzIGlzIHNsaWdobHkgaW5jcmVhc2VkIHRvIDAuNTEgKGluc3RlYWQgb2YgMC41IGZvciBiYWxhbmNlZCBjb2lucykuCiAgCmBgYHtyfQojIEdlbmVyYXRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwLXZhbHVlcyBmb3IgMjAsMDAwIHVuYmFsYW5jZWQgY29pbnMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm5yX2RyPTE1MDAwCnN1bShzYW1wbGUgKHg9MDoxLHNpemU9bnJfZHIsIHJlcGxhY2U9VFJVRSwgcHJvYiA9IGMoMC40OSwwLjUxKSkpCnJlcGxpY2F0ZSgyMCwyKnBiaW5vbShucl9kci8yLWFicyhzdW0oc2FtcGxlICh4PTA6MSxzaXplPW5yX2RyLCByZXBsYWNlPVRSVUUsIHByb2IgPSBjKDAuNDksMC41MSkpKS1ucl9kci8yKSxzaXplPW5yX2RyLHByb2I9MC41KSkKcHNpbTM8LXJlcGxpY2F0ZSgyMDAwMCwyKnBiaW5vbShucl9kci8yLWFicyhzdW0oc2FtcGxlICh4PTA6MSxzaXplPW5yX2RyLCByZXBsYWNlPVRSVUUsIHByb2IgPSBjKDAuNDksMC41MSkpKS1ucl9kci8yKSxzaXplPW5yX2RyLHByb2I9MC41KSkKaGlzdChwc2ltMyxicmVha3M9c2VxKC0wLjEsMS4xLDAuMDUpLCBib3JkZXIgPSAicmVkIiwgeGxhYiA9ICJCaW5uZWQgcC12YWx1ZXMiKQpgYGAKClRoZSBkaXN0cmlidXRpb24gaXMgc2V2ZXJlbHkgc2hpZnRlZCB0b3dhcmRzIGxvd2VyIHAtdmFsdWVzIHN1Z2dlc3RpbmcgZWl0aGVyIHRoYXQgb3VyIHN0YXRpc3RpY2FsIHRlc3QgaGFzIGEgcHJvYmxlbSwgb3IgKGFzIGlzIHRoZSBjYXNlIGhlcmUpIHRoYXQgbWFueSBvZiBvdXIgdGVzdHMgKGluIHRoaXMgY2FzZSBhbGwpIGFyZSB0cnVlIEgxIGh5cG90aGVzZXMuICAKCkxldCB1cyBrbm93IHNpbXVsYXRlIGEgc2l0dWF0aW9uIHRoYXQgcmVzZW1ibGVzIHdoYXQgd2Ugb2Z0ZW4gZmFjZSBpbiB0aGUgcmVhbCB3b3JsZCwgaS5lLiB0aGF0IHRoZSB0ZXN0cyBwZXJmb3JtZWQgaW5jbHVkZSBib3RoIHRydWUgSDAgYW5kIHRydWUgSDEuICBUaGUgcHJvcG9ydGlvbiBvZiB0cnVlIEgwIGlzIG9mdGVuIHJlZmVycmVkIHRvIGFzICJwaTAiLiAgSW4gdGhlIGZvbGxvd2luZyBleGFtcGxlICJwaTAiIGlzIHNpbXVsYXRlZCB0byBiZSBhcHByb3hpbWF0ZWx5IDUwJS4gIAogIApgYGB7cn0KIyBHZW5lcmF0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgcC12YWx1ZXMgZm9yIGEgbWl4dHVyZSBvZiBiYWxhbmNlZCBhbmQgdW5iYWxhbmNlZCBjb2lucwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm1peHQgPC0gZnVuY3Rpb24oKXsKICBpZiAocnVuaWYoMSwwLDEpID4gMC41KXsKICAgIDIqcGJpbm9tKG5yX2RyLzItYWJzKHN1bShzYW1wbGUgKHg9MDoxLHNpemU9bnJfZHIsIHJlcGxhY2U9VFJVRSkpLW5yX2RyLzIpLHNpemU9bnJfZHIscHJvYj0wLjUpCiAgfSBlbHNlewogICAgMipwYmlub20obnJfZHIvMi1hYnMoc3VtKHNhbXBsZSAoeD0wOjEsc2l6ZT1ucl9kciwgcmVwbGFjZT1UUlVFLCBwcm9iID0gYygwLjQ5LDAuNTEpKSktbnJfZHIvMiksc2l6ZT1ucl9kcixwcm9iPTAuNSkKICB9Cn0KbnJfZHI9MTUwMDAKbnJfZXhwPTIwMDAwCnBzaW00IDwtIHJlcGxpY2F0ZShucl9leHAsbWl4dCgpKQpoaXN0KHBzaW00LGJyZWFrcz1zZXEoLTAuMSwxLjEsMC4wNSksIGJvcmRlciA9ICJyZWQiLCB4bGFiID0gIkJpbm5lZCBwLXZhbHVlcyIpCmBgYAogIAogClRoZSBkaXN0cmlidXRpb24gcmVtYWlucyBoZWF2aWx5IHNoaWZ0ZWQgdG93YXJkcyBsb3cgcC12YWx1ZXMgZHVlIHRvIHRoZSBoaWdoIHByb3BvcnRpb24gb2YgSDEgaHlwb3RoZXNlcyBhbW9uZ3N0IHRoZSB0ZXN0cy4gIFdlIG5vcm1hbGx5IGV4cGVjdCBhcm91bmQgMSwwMDAgb2JzZXJ2YXRpb25zIHBlciA1JSBiaW4gdW5kZXIgdGhlIG51bGwuIFRoaXMgaXMgYXBwcm94aW1hdGVseSB0aGUgY2FzZSBmb3IgYmlucyB3aXRoIHAtdmFsdWVzID4gMC4zIGluIG91ciBleGFtcGxlLiAgQnV0IGJpbnMgd2l0aCBwLXZhbHVlcyA8IDAuMyB0ZW5kIHRvIGJlIG92ZXItcmVwcmVzZW50ZWQuICBUaGUgZmlyc3QgYmluLCBmb3IgaW5zdGFuY2UsY29udGFpbnMgPiA3LDAwMCBvYnNlcnZhdGlvbnMsIHdoaWxlIG9ubHkgMSwwMDAgYXJlIGV4cGVjdGVkIHVuZGVyIHRoZSBudWxsLiAgVGh1cywgd2UgY2FuIHJlYXNvbmFibHkgY29uY2x1ZGUgdGhhdCBpbiB0aGlzIGJpbiBhcHByb3hpbWF0ZWx5IDYgb3V0IG9mIDcgdGVzdHMgcHJvYmFibHkgY29ycmVzcG9uZCB0byB0cnVlIEgxIGh5cG90aGVzZXMuICBPciBzdGF0ZWQgb3RoZXJ3aXNlLCBpZiB3ZSBzZWxlY3QgdGhlIHRlc3RzIGluIHRoZSBmaXJzdCBiaW4gYXMgcG90ZW50aWFsbHkgaW50ZXJlc3RpbmcgKHdlIHRlbmQgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMpLCBnaXZlbiB0aGUgb2JzZXJ2ZWQgZGlzdHJpYnV0aW9uIG9mIHAtdmFsdWVzLCB0aGUgcHJvcG9ydGlvbiBvZiBmYWxzZSBwb3NpdGl2ZXMgaW4gdGhpcyBiaW4gd2lsbCBiZSBhcHByb3hpbWF0ZWx5IDEgaW4gNy4gIFRoZSByaWdodCB3YXkgdG8gc2F5IHRoaXMgaXMgdGhhdCwgaW4gdGhlIGZpcnN0IGJpbiwgdGhlICoqRmFsc2UgRGlzY292ZXJ5IFJhdGUgKEZEUikqKiBoYXMgdG8gYmUgYXBwcm94aW1hdGVseSAxLzcuICAKCkxldCB1cyBjb21wdXRlIHRoaXMgYSBiaXQgbW9yZSBhY2N1cmF0ZWx5OiAgCiAgCmBgYHtyfQojIENvbXB1dGluZyB0aGUgRkRSIGZvciB0aGUgZ3JvdXAgb2YgdGVzdHMgaW4gdGhlIDAtMC4wNSBiaW4KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnN1bShwc2ltNCA8PSAwLjA1KQpGRFIgPSAobnJfZXhwKjAuMDUpL3N1bShwc2ltNCA8PSAwLjA1KQpGRFIKYGBgCiAgCkFub3RoZXIgY29tbW9uIHdheSB0byBsb29rIGF0IHRoaXMgZGlzdHJpYnV0aW9ucyBpcyBieSBtZWFucyBvZiB0aGUgUVEgcGxvdHMgdGhhdCB3ZXJlIGFscmVhZHkgZGlzY3Vzc2VkIGJlZm9yZS4gIAogIApgYGB7cn0KIyBRUSBwbG90IGZvciBtaXh0dXJlIG9mIGJhbGFuY2VkIGFuZCB1bmJhbGFuY2VkIGNvaW5zCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpnZ2QucXFwbG90ID0gZnVuY3Rpb24ocHZlY3RvciwgbWFpbj1OVUxMLCAuLi4pIHsKICBvID0gLWxvZzEwKHNvcnQocHZlY3RvcixkZWNyZWFzaW5nPUYpKQogIGUgPSAtbG9nMTAoIDE6bGVuZ3RoKG8pL2xlbmd0aChvKSApCiAgcGxvdChlLG8scGNoPTE5LGNleD0xLCBtYWluPW1haW4sIC4uLiwKICAgICAgIHhsYWI9ZXhwcmVzc2lvbihFeHBlY3RlZH5+LWxvZ1sxMF0oaXRhbGljKHApKSksCiAgICAgICB5bGFiPWV4cHJlc3Npb24oT2JzZXJ2ZWR+fi1sb2dbMTBdKGl0YWxpYyhwKSkpLAogICAgICAgeGxpbT1jKDAsbWF4KGUpKSwgeWxpbT1jKDAsbWF4KG8pKSkKICBsaW5lcyhlLGUsY29sPSJyZWQiKQp9CmdnZC5xcXBsb3QocHNpbTQpCmBgYAoKICAKSW4gdGhlIHByZXZpb3VzIGV4YW1wbGUsIHdlIGNvbXB1dGVkIHRoZSBGRFIgZm9yIHRoZSBncm91cCBvZiB0ZXN0cyBmYWxsaW5nIGluIHRoZSBsb3dlc3QgYmluLiBXZSBjYW4gYWxzbyBjb21wdXRlIHRoZSBGRFIgZm9yIGluZGl2aWR1YWwgdGVzdHMuICBUaGVzZSB2YWx1ZXMgY29ycmVzcG9uZCB0byBzby1jYWxsZWQgcS12YWx1ZXMuICBUaGlzIGlzIGluIGZhY3QgYSBiaXQgbWlzbGVhZGluZy4gQXMgeW91IHdpbGwgc29vbiB1bmRlcnN0YW5kLCB0aGUgcS12YWx1ZSBjb21wdXRlZCBmb3IgYW4gaW5kaXZpZHVhbCB0ZXN0IGlzIGFjdHVhbGx5IHRoZSBqb2ludCBGRFIgZm9yIGFsbCB0aGUgdGVzdCB3aXRoIHAtdmFsdWUgZXF1YWwgb3Igc21hbGxlciB0aGFuIHRoZSBleGFtaW5lZCBvbmUuICBMZXQgdXMgY29tcHV0ZSB0aGUgcS12YWx1ZXMgZm9yIHRoZSAicHNpbTQiIChtaXhlZCBiYWxhbmNlZCBhbmQgdW5iYWxhbmNlZCBjb2lucykgZGF0YXNldC4gIAoKICAKYGBge3J9CiMgQ29tcHV0aW5nIGFuYiBleGFtaW5pbmcgcS12YWx1ZXMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKI3BzaW00CnJhbmtfc2ltNDwtcmFuayhwc2ltNCxuYS5sYXN0ID0gVFJVRSwgdGllcy5tZXRob2QgPSAicmFuZG9tIikKI3Jhbmtfc2ltNAojc29ydF9zaW00PC1zb3J0KHBzaW00LGRlY3JlYXNpbmc9RkFMU0UpCiNzb3J0X3NpbTQKCmZkcjwtKG5yX2V4cCpwc2ltNCkvcmFua19zaW00Cmxwc2ltNDwtbG9nMTAoMS9wc2ltNCkKbGZkcjwtbG9nMTAoMS9mZHIpCiNwbG90KGxwc2ltNCxsZmRyKQoKI2JvbmY8LXBzaW00Km5yX2V4cAojbGJvbmY8LWxvZzEwKDEvYm9uZikKI3Bsb3QobGJvbmYsbHBzaW00KQoKc2lkPC0xLSgxLXBzaW00KV5ucl9leHAKbHNpZDwtbG9nMTAoMS9zaWQpCiNwbG90KGxzaWQsbHBzaW00KQoKcGxvdChsc2lkLGxmZHIpCmBgYAogIApbKyBpbnRlcnByZXRhdGlvbl0gIAoKQXMgYSBtYXR0ZXIgb2YgZmFjdCB3ZSBjYW4gZG8gYmV0dGVyLiAgRnJvbSB0aGUgZGlzdHJpYnV0aW9uIG9mIHAtdmFsdWVzLCB3ZSBjYW4gaGF2ZSBhbiBpZGVhIG9mICJwaTAiLCBpLmUuIHRoZSBwcm9wb3J0aW9uIG9mIEgwIGh5cG90aGVzZXMgYW1vbmdzdCB0aGUgcmVhbGl6ZWQgdGVzdHMuIFdlIHdpbGwgYXNzdW1lIGZvciB0aGF0LCB0aGF0IHRoZSAiaGlnaCBwLXZhbHVlIGJpbnMiIiBwcmltYXJpbHkgZW5jb21wYXNzIEgwIGh5cG90aGVzZXMuICBJbmRlZWQsIHR5cGljYWxseSB0aGUgaGVpZ2h0IG9mIHRoZXNlIGJpbnMgImZsYXR0ZW5zIG91dCIuICBUaHVzIHRoZSBhdmVyYWdlIHByb3BvcnRpb24gb2Ygb2JzZXJ2YXRpb25zIGluIHRoZXNlIGJpbnMgbXVsdGlwbGllZCBieSB0aGUgdG90YWwgbnVtYmVyIG9mIGJpbnMgKHNheSAyMCkgZ2l2ZXMgdXMgYW4gZXN0aW1hdGUgb2YgdGhlIHByb3BvcnRpb24gb2YgSDAgaHlwb3RoZXNlcyBpbiB0aGUgZGF0YS4gIFRoaXMgZXN0aW1hdGUgY2FuIHRoZW4gYmUgdXNlZCB0byBjb21wdXRlIGltcHJvdmVkIHEtdmFsdWVzLiBUaGUgaWRlYSBiZWhpbmQgdGhpcyBhcHByb2FjaCBpcyBkZXNjcmliZWQgaW4gU3RvcmV5IGV0IGFsLiAoMjAwMylbaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wdWJtZWQvMTI4ODMwMDVdLgoKTGV0IHVzIGltcGxlbWVudCBpdCB0byBvdXIgcHNpbTQgZGF0YSwgdXNpbmcgU3RvcmV5J3Mgc29mdHdhcmUsIHdoaWNoIHdlIHdpbGwgZmlyc3QgaW5zdGFsbC4gICAKCmBgYHtyfQojIEluc3RhbGxpbmcgU3RvcmV5J3MgcGFja2FnZQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQpsaWJyYXJ5KCJkZXZ0b29scyIpCiNpbnN0YWxsX2dpdGh1YigiamRzdG9yZXkvcXZhbHVlIikKbGlicmFyeShxdmFsdWUpCmBgYAoKV2hpbGUgcGxheWluZyB3aXRoIHRoaXMgSSByZWFsaXplZCB0aGF0IHBzaW00IGNvbnRhaW5zIHZhbHVlcyA+IDEuICBXZSB3aWxsIGZpcnN0IGNvcnJlY3QgdGhlc2UgdmFsdWVzIGFuZCBzZXQgdGhlbSB0byAxLgoKYGBge3J9CiMgRWxpbWluYXRpbmcgcC12YWx1ZXMgPiAxIGZyb20gcHNpbTQKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwptYXgocHNpbTQpCnBzaW00W3BzaW00PjFdPC0xCm1heChwc2ltNCkKYGBgCgpXZSB3aWxsIHRoZW4gcmVjb21wdXRlIEZEUidzIHVzaW5nICJvdXIiIG1ldGhvZC4KICAKYGBge3J9CiMgQ29tcHV0aW5nIEZEUiB3aXRoICJvdXIiIG1ldGhvZAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnJhbmtfc2ltNDwtcmFuayhwc2ltNCxuYS5sYXN0ID0gVFJVRSwgdGllcy5tZXRob2QgPSAicmFuZG9tIikKI3Jhbmtfc2ltNApmZHI8LShucl9leHAqcHNpbTQpL3Jhbmtfc2ltNApsZmRyPC1sb2cxMCgxL2ZkcikKYGBgCgpMZXQgdXMgbm93IHVzZSBTdG9yZXkncyBwcm9ncmFtLiAgCiAgCmBgYHtyfQojIENvbXB1dGluZyBGRFIgd2l0aCBTdG9yZXkncyBtZXRob2QKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpxb2JqIDwtIHF2YWx1ZShwID0gcHNpbTQpCiNxb2JqCmxxPC1sb2cxMCgxL3FvYmokcXZhbHVlcykKbHA8LWxvZzEwKDEvcW9iaiRwdmFsdWVzKQpgYGAKCldlIGNhbiBub3cgY29tcGFyZSB0aGUgdHdvIHNldHMgb2YgdmFsdWVzLiAgCiAgCmBgYHtyfQpwbG90KGxmZHIsbHEpCmxpbmVzKGxmZHIsbGZkcixjb2wgPSAicmVkIikKYGBgCgpXZSBjYW4gYWxzbyB1c2UgU3RvcmV5J3MgcHJvZ3JhbSB0byBlc3RpbWF0ZSBwaTAgdmFsdWVzLiAKCmBgYHtyfQojIEdlbmVyYXRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwLXZhbHVlcyBmb3IgYSBtaXh0dXJlIG9mIGJhbGFuY2VkIGFuZCB1bmJhbGFuY2VkIGNvaW5zCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbWl4dCA8LSBmdW5jdGlvbihwaV96ZXJvKXsKICBpZiAocnVuaWYoMSwwLDEpIDwgcGlfemVybyl7CiAgICAyKnBiaW5vbShucl9kci8yLWFicyhzdW0oc2FtcGxlICh4PTA6MSxzaXplPW5yX2RyLCByZXBsYWNlPVRSVUUpKS1ucl9kci8yKSxzaXplPW5yX2RyLHByb2I9MC41KQogIH0gZWxzZXsKICAgIDIqcGJpbm9tKG5yX2RyLzItYWJzKHN1bShzYW1wbGUgKHg9MDoxLHNpemU9bnJfZHIsIHJlcGxhY2U9VFJVRSwgcHJvYiA9IGMoMC40OSwwLjUxKSkpLW5yX2RyLzIpLHNpemU9bnJfZHIscHJvYj0wLjUpCiAgfQp9Cm5yX2RyPTE1MDAwCm5yX2V4cD0xMDAwMApwc2ltX3NlcmllcyA8LSBkYXRhLmZyYW1lKFYwPTE6bnJfZXhwLFYyNT0wLFY1MD0wLFY3NT0wLFYxMDA9MCkKI3BzaW1fc2VyaWVzCmZvciAoaSBpbiAxOjUpewogIHBzaW1fc2VyaWVzWyxpXSA8LSByZXBsaWNhdGUobnJfZXhwLG1peHQocGlfemVybyA9IDAuMTAqKGktMSkpKQp9CiNwc2ltX3NlcmllcwpwaTAgPSBkYXRhLmZyYW1lKFYxPTA6MSxWMj1OQSxWMz1OQSxWND1OQSxWNT1OQSkKZm9yIChpIGluIDE6NSl7CiAgcGkwWzEsaV0gPSAwLjEwKihpLTEpCiAgcHNpbV9zZXJpZXNbLGldW3BzaW1fc2VyaWVzWyxpXT4xXTwtMQogIHFvYmogPC0gcXZhbHVlKHAgPSBwc2ltX3Nlcmllc1ssaV0pCiAgcGkwWzIsaV08LXFvYmokcGkwCn0KcGkwCmBgYApJbiB0aGVzZSBzaW11bGF0aW9ucywgU3RvcmV5J3MgcHJvZ3JhbSBzZWVtIHRvIHNsaWdodGx5IGJ1dCBzeXN0ZW1hdGljYWxseSBvdmVyZXN0aW1hdGUgcGkwIC4uLiA6LSkgCgojRXhhbXBsZXMgb2YgdGhlIGRlc2lnbiBhbmQgdXNlIG9mIGVtcGlyaWNhbCBzdGF0aXN0aWNhbCB0ZXN0IGluIGdlbm9tZSBzdHVkaWVzCgoxLiBSb3Nld2ljaywgTi4gZXQgYWwuIENpcy1wZXJ0dXJiYXRpb24gb2YgY2FuY2VyIGRyaXZlcnMgYnkgdGhlIEhUTFYtMS9CTFYgcHJvdmlydXNlcyBpcyBhbiBlYXJseSBkZXRlcm1pbmFudCBvZiBsZXVrZW1vZ2VuZXNpcy4gTmF0IENvbW11biA4OjE1MjY0ICgyMDE3KSBbaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9uY29tbXMxNTI2NF0gIAoKVGhpcyBwYXBlciBtYWtlcyBleHRlbnNpdmUgdXNlIG9mIHNpbXVsYXRpb25zIHRvIGV2YWx1YXRlIHRoZSBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2Ugb2YgZ2Vub21pYyBmZWF0dXJlcyBhc3NvY2lhdGVkIHdpdGggQkxWIHByb3ZpcmFsIGluc2VydGlvbiBzaWdodHMuICBUaGUgQkxWIGFuZCBIVExWLUkgcmV0cm92aXJ1c2VzIGNhdXNlIGxldWtlbGlhIGluIGNhdHRsZS9zaGVlcCBhbmQgaHVtYW4sIHJlc3BlY3RpdmVseSwgYW5kIHRoaXMgYWZ0ZXIgYSBsb25nIGluY3ViYXRpb24gcGVyaW9kLiAgSXQgd2FzIHByZXZpb3VzbHkgYXNzdW1lZCB0aGF0IHRoZSBwcm92aXJhbCBpbnRlZ3JhdGlvbiBzaXRlIHdhcyByYW5kb20sIGFuZCB0aGF0IHR1bW9yIGRldmVsb3BtZW50IHdhcyBkdWUgdG8gKGkpIHRoZSB0cmFuc2Zvcm1hdGlvbiBwb3RlbnRpYWwgb2YgdmlydXMtZW5jb2RlZCBwcm90ZWlucyBpbmNsdWRpbmcgVGF4IGluIHRoZSBlYXJseSBwaGFzZXMgb2YgdGhlIGRpc2Vhc2UsIGFuZCAoaWkpIHNvbWF0aWMgbXV0YXRpb25zIGFjY3J1aW5nIGluIGNhbmNlciBkcml2ZXIgZ2VuZXMgYWNyb3NzIHRoZSBnZW5vbWUgaW4gdGhlIGxhdGVyIHN0YWdlcyBvZiB0aGUgZGlzZWFzZS4gIFRoaXMgcGFwZXIgc2hvd3MgdGhhdCB0aGUgaW50ZWdyYXRpb24gb2YgQkxWIHByb3ZpcnVzZXMgaW4gc2hlZXAgaXMgYWJzb2x1dGVseSBub3QgcmFuZG9tLiAgUHJvdmlydXNlcyB0ZW5kIHRvIHByZWZlcmVudGlhbGx5ICJsYW5kIiBpbiBob3RzcG90cyBvZiBpbnRlZ3JhdGlvbi4gTW9yZW92ZXIsIHRoZXNlIGhvdHNwb3RzIGFyZSBlbnJpY2hlZCBpbiBrbm93biBjYW5jZXIgZHJpdmVyIGdlbmVzLCBzdHJvbmdseSBzdWdnZXN0aW5nIHRoYXQgdGhlIGludGVncmF0aW9uIHNpdGUgY29udHJpYnV0ZXMgdG8gZWFybHkgY2VsbCB0cmFuc29mbXJhdGlvbi4gKipTaW11bGF0aW9uIHdhcyB1c2VkIGluIHNldmVyYWwgZXhwZXJpbWVudHMgdG8gZXZhbHVhdGUgdGhlIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBvZiB0aGUgb2JzZXJ2ZWQgcHJvdmlyYWwgY2x1c3RlcmluZy4qKgoKSWRlbnRpZnlpbmcgaW50ZWdyYXRpb24gaG90c3BvdHM6CioiSG90c3BvdHMgd2VyZSB0aGVuIGRlZmluZWQgYXMgZm9sbG93czogZm9yIGVhY2ggSVMgd2UgY291bnRlZCB0aGUgbnVtYmVyIG9mIElTIGxvY2F0ZWQgaW4gYSA1MCBrYiB3aW5kb3cgY2VudHJlZCBvbiB0aGF0IElTLiBXZSB0aGVuIHJhbmRvbWx5IHBpY2tlZCA2Niw1NTcgSVMgaW4gdGhlIG92aW5lIGdlbm9tZSwgcGVyZm9ybWVkIHRoZSBzYW1lIGNvdW50aW5nIHByb2NlZHVyZSBhbmQgcmV0YWluZWQgdGhlIHNpbXVsYXRlZCBJUyB3aW5kb3cgaGFyYm91cmluZyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgSVMuIFdlIHBlcmZvcm1lZCBOPTEsMDAwLDAwMCBpdGVyYXRpb25zIG9mIHRoaXMgcHJvY2VkdXJlIHRvIGdlbmVyYXRlIGEgZGlzdHJpYnV0aW9uIHJlZmxlY3RpbmcgcmFuZG9tIGludGVncmF0aW9uLiBXZSB0aGVuIGFzc2lnbmVkIGEgUC12YWx1ZSB0byBlYWNoIElTLiBIb3RzcG90cyB3ZXJlIGRlZmluZWQgYnkgZ3JvdXBpbmcgY29uc2VjdXRpdmUgSVMgd2luZG93cyB0aGF0IHNob3dlZCBhIFAtdmFsdWUgPD0gMC4wNSwgdGhlIHBvc2l0aW9uIG9mIHRoZSB0d28gZXh0cmVtZSBJUyA1IGtiIGRldGVybWluaW5nIHRoZSBib3VuZGFyaWVzIG9mIHRoZSBob3RzcG90LiIqCgogIAoyLiBSb3NzaW4sIEUuSi4gZXQgYWwuIFByb3RlaW5zIGVuY29kZWQgaW4gZ2Vub21pYyByZWdpb25zIGFzc29jaWF0ZWQgd2l0aCBpbW11bmUtbWVkaWF0ZWQgZGlzZWFzZSBwaHlzaWNhbGx5IGludGVyYWN0IGFuZCBzdWdnZXN0IHVuZGVybHlpbmcgYmlvbG9neS4gUExvUyBHZW5ldGljcyA3OiBlMTAwMTI3MyAoMjAxMSkgW2h0dHBzOi8vam91cm5hbHMucGxvcy5vcmcvcGxvc2dlbmV0aWNzL2FydGljbGU/aWQ9MTAuMTM3MS9qb3VybmFsLnBnZW4uMTAwMTI3M10gIAoKKiJUaGVyZWZvcmUsIHdlIGFwcGx5IGEgcGVybXV0YXRpb24gbWV0aG9kIHRoYXQgaXMgcm9idXN0IHRvIG5vbi1zcGVjaWZpYyBiaW5kaW5nIGFuZCBkaWZmZXJlbmNlcyBpbiBwdWJsaWNhdGlvbiBkZW5zaXR5LiBXZSBwZXJmb3JtIGEgd2l0aGluLWRlZ3JlZSBub2RlLWxhYmVsIHBlcm11dGF0aW9uIHRoYXQgaXMgY2FycmllZCBvdXQgYXMgZm9sbG93czogYSByYW5kb20gbmV0d29yayBpcyBidWlsdCB0aGF0IGhhcyBuZWFybHkgdGhlIGV4YWN0IHNhbWUgc3RydWN0dXJlIGFzIHRoZSBvcmlnaW5hbCBJbldlYiBuZXR3b3JrLCBvbmx5IHRoZSBub2RlIGxhYmVscyAoaS5lLiB0aGUgcHJvdGVpbiBuYW1lcykgYXJlIHJhbmRvbWx5IHJlLWFzc2lnbmVkIHRvIG5vZGVzIG9mIGVxdWFsIGJpbmRpbmcgZGVncmVlOyB0aGlzIG1ldGhvZCBhc3N1bWVzIGEgbnVsbCBkaXN0cmlidXRpb24gb2YgY29ubmVjdGl2aXR5IHRoYXQgaXMgZW50aXJlbHkgYSBmdW5jdGlvbiBvZiB0aGUgYmluZGluZyBkZWdyZWUgb2YgaW5kaXZpZHVhbCBwcm90ZWlucy4gUmFuZG9tIG5ldHdvcmtzIHdpbGwgaGF2ZSB0aGUgc2FtZSBzaXplLCBudW1iZXIgb2YgZWRnZXMgYW5kIHBlci1wcm90ZWluIGJpbmRpbmcgZGVncmVlIGFzIEluV2ViOyB3ZSBidWlsZCA1MCwwMDAgZGlmZmVyZW50IHJhbmRvbSBuZXR3b3Jrcy4gV2l0aCB0aGlzIG1ldGhvZCwgd2UgYXJlIGFibGUgdG8gdGVzdCB0aGUgbm9uLXJhbmRvbW5lc3Mgb2Ygb3VyIG5ldHdvcmsgY29uZGl0aW9uYWwgb24gdGhlIGV4YWN0IGJpbmRpbmcgZGVncmVlIGRpc3RyaWJ1dGlvbiBvZiBvdXIgZGlzZWFzZSBwcm90ZWlucy4iKgoKCiNUaGUgd2lubmVycycgY3Vyc2UgIAoKSW4gdGhlIHByZXZpb3VzIHNlY3Rpb24gd2Ugc2hvd2VkIGhvdyBub3QgcHJvcGVybHkgYWNjb3VudGluZyBmb3IgbXVsdGlwbGUgdGVzdGluZyBpcyBhIGNvbW1vbiBzb3VyY2Ugb2YgZmFsc2UgcG9zaXRpdmUsIGkuZS4gbm9uIHJlcHJvZHVjaWJsZSByZXN1bHRzLiAgQW5vdGhlciBwb3NzaWJsZSBjYXVzZSBvZiB0aGUgYXBwYXJlbnQgbm9uLXJlcHJvZHVjaWJpbGl0eSBvZiByZXN1bHRzIGlzIHdoZW4gZXhwZXJpbWVudHMgYXJlICJ1bmRlcnBvd2VyZWQiLiBUaGlzIGlzIHdlbGwgaWxsdXN0cmF0ZWQgaW4gR1dBUyBzdHVkaWVzLiAgU2V2ZXJhbCBncm91cHMgYXJvdW5kIHRoZSB3b3JsZCBpbml0aWFsbHkgcGVyZm9ybWVkICJ0aGVpciBvd24iIEdXQVMsIGkuZS4gdGhleSBhc3NlbXBsZWQgYSBjYXNlLWNvbnRyb2wgY29ob3J0IG9mIC0gc2F5IC0gMSwwMDAgY2FzZXMgYW5kIDEsMDAwIGNvbnRyb2xzIC0gYW5kIHJhbiB0aGVpciBvd24gYW5hbHlzZXMuICBUaGlzIHdvdWxkIHR5cGljYWxseSB5aWVsZCBvbmUgb3IgdHdvIGdlbm9tZS13aWRlIHNpZ25pZmljYW50IHNpZ25hbHMuICBBbGwgb2YgdGhlc2UgZGlzY292ZXJpZXMgd2VyZSBhY2NvbXBhbmllZCBieSBhIGNvbmZpcm1hdGlvbiBpbiBhbiBpbmRlcGVuZGVudCAiY29uZmlybWF0aW9uIiBjb2hvcnQsIGhlbmNlIHN0cm9uZ2x5IHN1cHBvcnRpbmcgdGhlaXIgZ2VudWluZSBuYXR1cmUgW05vdGUgdGhhdCB0aGUgc2lnbmlmaWNhbmNlIHRocmVzaG9sZHMgdXNlZCBpbiB0aGUgY29uZmlybWF0aW9uIHN0ZXAgYXJlICJsZWFuaWVyIiBhcyBtdWNoIGZld2VyIHRlc3RzIGFyZSBjb25kdWN0ZWQgaW4gdGhlIGNvbmZpcm1hdGlvbiB0aGFuIGluIHRoZSBkaXNjb3ZlcnkgcGhhc2VdLiAgIFlldCwgdGhlIHNpZ25hbHMgdGhhdCB3ZXJlIGRpc2NvdmRlcmVkIGluIHRoZXNlIGluaXRpYWwgR1dBUyBuZWFybHkgYWx3YXlzIGRpZmZlcmVkIGJldHdlZW4gc3R1ZGllcy4gIFdoeSBpcyB0aGF0PyAgClRoZSByZWFzb24gaXMgdGhhdCB0aGUgU05QIGVmZmVjdHMgd2VyZSBzbWFsbGVyIHRoYW4gYW50aWNpcGF0ZWQuICBBcyBhIHJlc3VsdCwgdGhlIGluaXRpYWwgR1dBUyBzdHVkaWVzIHdlcmUgaW5pdGlhbGx5ICJ1bmRlcnBvd2VyZWQiIHRvIGRldGVjdCB0aGVtLiAgQXNzdW1pbmcgdGhhdCB5b3Ugb25seSBoYXZlIDEwJSBwb3dlciB0byBkZXRlY3QgdGhlIHNpZ25hbHMgb2YgaW50ZXJlc3QgZ2l2ZW4geW91ciBzYW1wbGUgc2l6ZSwgeW91IHdpbGwgYnkgZGVmaW5pdGlvbiBvbmx5IGZpbmQgMTAlIG9mIHRoZSBleGlzdGluZ3Mgc2lnbmFsIGluIHlvdXIgc3R1ZHkuICBZb3VyIGNvbGxlYWd1ZSwgd2hvIGlzIGluIHRoZSBzYW1lIHNpdHVhdGlvbiwgbWF5IGJ5IGNoYW5jZSBkZXRlY3QgYW5vdGhlciBvZiB0aGUgZXhpc3Rpbmcgc2lnbmFscyBpbiBoZXJzL2hpcyBzdHVkeSwgZXRjLiAgV2hhdCBsaWVzIGJlaGluZCB0aGUgImJ5IGNoYW5jZSIgc3RhdGVtZW50IGluIHRoaXMgY29udGV4dD8gIFdlbGwgdG8gZGV0ZWN0IGEgc2lnbmFsIGluIGFuIHVuZGVycG93ZXJlZCBzdHVkeSwgdGhlIGNvcnJlc3BvbmRpbmcgZWZmZWN0IGhhcyB0byBiZSAiYWNjaWRlbnRhbGx5IiBzbGlnaHRseSBpbmZsYXRlZCBpbiB0aGF0IHN0dWR5LiAgT3RoZXJ3aXNlIGl0IHdvdWxkIG5vdCBleGNlZWQgdGhlIHNpZ25pZmljYW5jZSB0aHJlc2hvbGQuIFRoaXMgaXMgdGhlIGVzc2VuY2Ugb2Ygd2hhdCBpcyBjb21tb25seSByZWZlcnJlZCB0byBhcyAqKnRoZSB3aW5uZXJzJyBjdXJzZSoqLiAgVGhhdCB0aGUgZWZmZWN0cyBhcmUgaW5kZWVkIGluZmxhdGVkIGluIHRoZSBkaXNjb3ZlcnkgcGhhc2UgaXMgY29uZmlybWVkIHdoZW4gcmUtZXN0aW1hdGluZyB0aGUgZWZmZWN0IGluIHRoZSBjb25maXJtYXRpb24gY29ob3J0OiB0aGV5IGFyZSBuZWFybHkgYWx3YXlzIGluZmVyaW9yIHRvIHdoYXQgdGhleSB3ZXJlIGluIHRoZSBkaXNjb3ZlcnkgcGhhc2UuICBBbGwgdGhpcyBtYWRlIHBlb3BsZSBxdWlja2x5IHJlYWxpemUgdGhhdCBzYWx2YXRpb24gbGF5cyBpbiBjb2xsYWJvcmF0aW9uLiBBIG5ldyBsYXllciBvZiBlZmZlY3RzIHRoYXQgd291bGQgYmUgaW1wb3NzaWJsZSB0byBkZXRlY3QgaW4gaW5kaXZpZHVhbCBzdHVkaWVzIGluZGVlZCBlbWVyZ2VkIHdoZW4gcGVyZm9ybWluZyAqKm1ldGEtYW5hbGF5c2VzKiogYnkgbWVyZ2luZyB0aGUgaW5kaXZpdWFsIGRhdGFzZXRzLiAgVGhpcyBpcyBpbmRlZWQgd2hhdCBoYXBwZW5lZCBmb3IgbmVhcmx5IGFsbCBzdHVkaWVkIGRpc2Vhc2VzLCB5aWVsZGluZyBhbiBhbWF6aW5nICJjcm9wIiBvZiBHV0FTIGhpdHMgZm9yIG5lYXJseSBhbGwgb2YgdGhlbSBbc2VlIEVCSSdzIEdXQVMgY2F0YWxvZyBhdCBodHRwczovL3d3dy5lYmkuYWMudWsvZ3dhcy9dLiAgCiAgCkxldCB1cyBleHBsb3JlIHRoaXMgYSBiaXQgbW9yZSBxdWFudGl0YXRpdmVseS4gV2UgYXJlIGdvaW5nIHRvIHNpbXVsYXRlIHRoZSBpZGVudGlmaWNhdGlvbiwgYnkgYXNzb2NpYXRpb24gc3R1ZHksIG9mIGEgZ2VuZXRpYyB2YXJpYW50IGFmZmVjdGluZyBhIHF1YW50aXRhdGl2ZSB0cmFpdC4gIEZvciBzaW1wbGljaXR5IHdlIGFyZSBnb2luZyB0byBhc3N1bWUgdGhhdCB3ZSB3b3JrIHdpdGggYSBoYXBsb2lkIG9yZ2FuaXNtLiAgVGh1cyB0aGUgZ2Vub3R5cGUgb2YgaW5kaXZpZHVhbHMgaXMgZWl0aGVyICpBKiAoIjAiIGluIHRoZSBzaW11bGF0aW9ucykgb3IgKmEqICgiMSIgaW4gdGhlIHNpbXVsYXRpb25zKS4gIFdlIHdpbGwgc2V0IHRoZSBmcmVxdWVuY3kgb2YgdGhlIGEgYWxsZWxlIGF0IDAuMjUgKHRoZSBzY3JpcHQgYmVsb3cgYWxsb3dzIHRvIHZhcnkgZl9hIGFzIHdlbGwgYXMgdG8gdGVzdCBhIHJhbmdlIG9mIHZhbHVlcykuICBXZSB3aWxsIGFzc3VtZSB0aGF0IHRoZSB0cmFpdCBvZiBpbnRlcmVzdCBpcyBub3JtYWxseSBkaXN0cmlidXRlZCB3aXRoIG1lYW4gMCBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIDEgd2l0aGluIGdlbm90eXBlIChpLmUuICJyZXNpZHVhbCIgdmFyaWFuY2UpLiBXZSB3aWxsIGFzc3VtZSB0aGF0IHRoZSBlZmZlY3Qgb2YgdGhlICphKiBhbGxlbGUgaXMgdG8gaW5jcmVhc2UgdGhlIHBoZW5vdHlwZSBieSAqZGVsdGEqLiAgSW4gb3VyIHNpbXVsYXRpb25zLCAqZGVsdGEqIHdpbGwgdmFyeSBmcm9tIHNheSAwLjI1IHRvIDEgcmVzaWR1YWwgc3RhbmRhcmQgZGV2aWF0aW9uLiAgV2Ugd2lsbCB2YXJ5IHRoZSBzYW1wbGUgc2l6ZSBmcm9tLCBzYXkgMjAwIHRvID4xLDQwMC4gIFdlIHdpbGwgdGVzdCB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoZSBlZmZlY3QgaW4gb3VyIHNpbXVsYXRlZCBkYXRhIHNldCB1c2luZyBhIHQtdGVzdC4gV2Ugd2lsbCBzZWxlY3QgYSAgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCAoZi5pLiBwIDwgMC4wMDAwMDEpIHRvIGRlY2lkZSB3aGV0aGVyICpkZWx0YSogaXMgc2lnbmlmaWNhbnQgb3Igbm90LiAgV2Ugd2lsbCBleGFtaW5lIHRoZSBpbXBhY3Qgb2YgdGhlIHN0dWRpZWQgcGFyYW1ldGVycyBvbiAoaSkgdGhlIHBvd2VyIHRvIGRldGVjdCB0aGUgc2lnbmFsIGF0IHRoZSBjaG9zZW4gc2lnbmlmaWNhbmNlIHRocmVzaG9sZCwgKGlpKSB0aGUgaW1wYWN0IG9mIHBvd2VyIG9uIHRoZSBlc3RpbWF0ZSBvZiAqZGVsdGEqLiAgICAgICAgCiAgCioqVGhlIGZvbGxvd2luZyBjb2RlIG1heSB0YWtlIGEgbG9uZyB0aW1lIHRvIHJ1biBpZiBydW4gbGFyZ2UgbnVtYmVycyBvZiBzaW11bGF0aW9ucy4gIElmIHlvdSBwcmVmZXIgbm90IHRvIHJ1biBpdCBub3csIHlvdSBjYW4gZ28gdG8gdGhlIG5leHQgIlIgY2h1bmsiIHRvIGltcG9ydCBwcmVjb21wdXRlZCByZXN1bHRzLioqCgpgYGB7cn0KIyBTZXQgYWxsX2NvbWIgYXQgemVybyBwcmlvciB0byBzdGFydGluZwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmFsbF9jb21iID0gTlVMTAoKIyBTZWxlY3QgcGFyYW1ldGVyIChhbGxlbGUgZnJlcXVlbmN5LCBzaXplIG9mIHRoZSBlZmZlY3QsIHNhbXBsZSBzaXplKSBzcGFjZSB3aGljaCB5b3Ugd2FudCB0byBleHBsb3JlCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpmcmVxPC1jKDAuMjUpCmVmZmVjdDwtYygwLjIwLDAuMzAsMC40MCwwLjUwLDAuNjAsMC43MCwwLjgwLDAuOTAsMSkKc3NpemU8LWMoMjAwLDQwMCwgNjAwLCA4MDAsIDEwMDAsIDEyMDAsIDE0MDApCgojIEdlbmVyYXRlIGFsbF9jb21iIG1hdHJpeCB1c2luZyAiZXhwYW5kIiBzdWNoIHRoYXQgYWxsIHBvc3NpYmxlIHBhcmVtZXRlciBjb21iaW5hdGlvbnMgY29ycmVzcG9uZCB0byBvbmUgcm93CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKYWxsX2NvbWI8LWV4cGFuZC5ncmlkKGZyZXEsZWZmZWN0LHNzaXplKQphbGxfY29tYlssNDo5XT0wICAKbmFtZXMoYWxsX2NvbWIpPWMoIkFGIiwiRUZGIiwiU1MiLCJBRCIsIlNVQ0MiLCJEUyIsIkFEUCIsIlNVQ0NQIiwiRFNQIikKCiMgU2VsZWN0IHNpZ25pZmljYW5jZSB0aHJlc2hvbGQgdG8gdXNlCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnBfdHJlc2g9MC4wMDAwMDEKCiMgR2VuZXJhdGUgZnVuY3Rpb24gdG8gc2ltdWxhdGUgYSBwb3B1bGF0aW9uIHdpdGggZ2l2ZW4gdmFsdWVzIHRvIGJlIGZvdW5kIGluIGFsbF9jb21iIGFuZCBwZXJmb3JtIGl0cyBhbmFseXNpcwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKcnVuX3NpbTwtZnVuY3Rpb24oail7CiAgc2ltPU5VTEwKICAjIEdlbmVyYXRlIGEgZGF0YS5mcmFtZSBpbiB3aGljaCB0byBzdG9yZSBpbmRpdmlkdWFsIGluZm9ybWF0aW9uCiAgc2ltPC1kYXRhLmZyYW1lKEdFTj0xOmFsbF9jb21iW2osM10sUkVTPU5BLFBIRU5fMD1OQSxQSEVOXzE9TkEpCiAgc2ltJEdFTj1zYW1wbGUoeD0wOjEsc2l6ZT1hbGxfY29tYltqLDNdLHJlcGxhY2U9VFJVRSwgcHJvYiA9IGMoMS1hbGxfY29tYltqLDFdLGFsbF9jb21iW2osMV0pKQogIHNpbSRSRVM9cm5vcm0oYWxsX2NvbWJbaiwzXSwwLDEpCiAgc2ltJFBIRU5fMCA9IHNpbSRSRVMKICBzaW0kUEhFTl8xID0gc2ltJFJFUythbGxfY29tYltqLDJdCiAgc2ltJFBIRU5fMFtzaW0kR0VOPT0xXSA9IE5BCiAgc2ltJFBIRU5fMVtzaW0kR0VOPT0wXSA9IE5BCiAgIyBDYWxjdWxhdGUgcmVhbGl6ZWQgZGVsdGEKICBkZWx0YSA9IG1lYW4oc2ltJFBIRU5fMSxuYS5ybSA9IFRSVUUpIC0gbWVhbihzaW0kUEhFTl8wLG5hLnJtID0gVFJVRSkKICAjIFN0b3JlIHJlYWxpemVkIGRhdGEgaW4gYXBwcm9wcmlhdGUgcGxhY2UgaW4gYWxsX2NvbWIKICBhbGxfY29tYltqLDRdPWFsbF9jb21iW2osNF0rZGVsdGEKICAjIHRlc3Qgc2lnbmlmaWNhbmNlIG9mIGRlbHRhIHVzaW5nIHQtdGVzdCAgICAKICB0X3JlczwtdC50ZXN0KHNpbSRQSEVOXzAsc2ltJFBIRU5fMSwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikKICAjIFJlY29yZCB3aGV0aGVyIHNpZ25pZmljYW50IGFuZCBpZiBpdCBpcywgc3RvcmUgcmVzdWx0cyBpbiBhcHByb3ByaWF0ZSBwbGFjZSBpbiBhbGxfY29tYgogIGlmICh0X3JlcyRwLnZhbHVlIDwgcF90cmVzaCl7CiAgICBhbGxfY29tYltqLDVdPWFsbF9jb21iW2osNV0rMQogICAgYWxsX2NvbWJbaiw2XT1hbGxfY29tYltqLDZdK2RlbHRhCiAgfSAKICAjIFJlc2V0IFNJTQogIHNpbT1OVUxMCiAgIyBUcmFuc2ZlciByZXN1bHRzIHRvIGdsb2JhbGVudgogIGFzc2lnbigiYWxsX2NvbWIiLGFsbF9jb21iLGVudmlyID0gZ2xvYmFsZW52KCkpCn0KCiMgRGVmaW5lIG51bW5lciBvZiBzaW11bGF0aW9ucyB0byBwZXJmb3JtIGFuZCBydW4gdGhlc2Ugb25lIHJvdyBhdCBhIHRpbWUKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpucl9zaW1zID0gMjAwMDAKZm9yIChqIGluIDE6bnJvdyhhbGxfY29tYikpewogIHJlcGxpY2F0ZShucl9zaW1zLHJ1bl9zaW0oaikpCn0KCiMgR2VuZXJhdGVzIGNvbHVtbnMgaW4gYWxsX2NvbWIgdG8gZXhwcmVzcyByZXN1bHRzIGFzIGEgZnJhY3Rpb24gb2YgdGhlIG51bWJlciBvZiByZWFsaXplZCBzaW11bGF0aW9ucwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmFsbF9jb21iJEFEUCA9IGFsbF9jb21iJEFEL25yX3NpbXMKYWxsX2NvbWIkU1VDQ1AgPSBhbGxfY29tYiRTVUNDL25yX3NpbXMKYWxsX2NvbWIkRFNQID0gYWxsX2NvbWIkRFMvYWxsX2NvbWIkU1VDQwoKI2ZvciAoaSBpbiAxOm5yb3coYWxsX2NvbWIpKXsKIyAgaWYgKGFsbF9jb21iW2ksMTBdID09ICJOYU4iKXsKIyAgICBhbGxfY29tYltpLDEwXSA9IE5BCiMgIH0KI30KCiMgVmlldyBhbGxfQ29tYgojIyMjIyMjIyMjIyMjIyMjIyMjIwphbGxfY29tYgoKIyBHZW5lcmF0ZSBwbG90cwojIyMjIyMjIyMjIyMjIyMjCnBsb3QoYWxsX2NvbWJbMTo5LDJdLGFsbF9jb21iWzE6OSwyXSx0eXBlID0gImwiLCB4bGFiID0gIkVmZmVjdCIseWxhYiA9ICJCaWFzIGluIGRlbHRhIC8gUG93ZXIiLCBjb2wgPSAicmVkIikKbGluZXMoYWxsX2NvbWJbMTo5LDJdLGFsbF9jb21iWzE6OSw5XSwgY29sID0gIiMwODMwNkIiKQpsaW5lcyhhbGxfY29tYlsxMDoxOCwyXSxhbGxfY29tYlsxMDoxOCw5XSwgY29sID0gIiMwODUxOUMiKQpsaW5lcyhhbGxfY29tYlsxOToyNywyXSxhbGxfY29tYlsxOToyNyw5XSwgY29sID0gIiMyMTcxQjUiKQpsaW5lcyhhbGxfY29tYlsyODozNiwyXSxhbGxfY29tYlsyODozNiw5XSwgY29sID0gIiM0MjkyQzYiKQpsaW5lcyhhbGxfY29tYlszNzo0NSwyXSxhbGxfY29tYlszNzo0NSw5XSwgY29sID0gIiM2QkFFRDYiKQpsaW5lcyhhbGxfY29tYls0Njo1NCwyXSxhbGxfY29tYls0Njo1NCw5XSwgY29sID0gIiM5RUNBRTEiKQpsaW5lcyhhbGxfY29tYls1NTo2MywyXSxhbGxfY29tYls1NTo2Myw5XSwgY29sID0gIiNDNkRCRUYiKQpsaW5lcyhhbGxfY29tYlsxOjksMl0sYWxsX2NvbWJbMTo5LDhdLCBjb2wgPSAiIzA4MzA2QiIsIGx0eSA9IDIpCmxpbmVzKGFsbF9jb21iWzEwOjE4LDJdLGFsbF9jb21iWzEwOjE4LDhdLCBjb2wgPSAiIzA4NTE5QyIsIGx0eSA9IDIpCmxpbmVzKGFsbF9jb21iWzE5OjI3LDJdLGFsbF9jb21iWzE5OjI3LDhdLCBjb2wgPSAiIzIxNzFCNSIsIGx0eSA9IDIpCmxpbmVzKGFsbF9jb21iWzI4OjM2LDJdLGFsbF9jb21iWzI4OjM2LDhdLCBjb2wgPSAiIzQyOTJDNiIsIGx0eSA9IDIpCmxpbmVzKGFsbF9jb21iWzM3OjQ1LDJdLGFsbF9jb21iWzM3OjQ1LDhdLCBjb2wgPSAiIzZCQUVENiIsIGx0eSA9IDIpCmxpbmVzKGFsbF9jb21iWzQ2OjU0LDJdLGFsbF9jb21iWzQ2OjU0LDhdLCBjb2wgPSAiIzlFQ0FFMSIsIGx0eSA9IDIpCmxpbmVzKGFsbF9jb21iWzU1OjYzLDJdLGFsbF9jb21iWzU1OjYzLDhdLCBjb2wgPSAiI0M2REJFRiIsIGx0eSA9IDIpCgp3cml0ZS5jc3YoYWxsX2NvbWIsIn4vRG9jdW1lbnRzL1RlYWNoaW5nL0dJR0FfRG9jdG9yYWxfU2Nob29sL0ludHVpdGl2ZV9zdGF0aXN0aWNzL1JfSU5UX1NUQVQvV0lOX0NVUlNFIixyb3cubmFtZXMgPSBGQUxTRSkKCmBgYAoKKipSdW4gdGhpcyBSIGNodW5rIHRvIGltcG9ydCBwcmVjb21wdXRlZCByZXN1bHRzKiogIAoKYGBge3J9CiMgTG9hZCBwcmVjb21wdXRlZCBhbGxfY29tYiBmaW5lCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmFsbF9jb21iIDwtIHJlYWQuY3N2KCJ+L0RvY3VtZW50cy9UZWFjaGluZy9HSUdBX0RvY3RvcmFsX1NjaG9vbC9JbnR1aXRpdmVfc3RhdGlzdGljcy9SX0lOVF9TVEFUL1dJTl9DVVJTRSIpCiNWaWV3KGFsbF9jb21iKQoKIyBHZW5lcmF0ZSBwbG90cwojIyMjIyMjIyMjIyMjIyMjCnBsb3QoYWxsX2NvbWJbMTo5LDJdLGFsbF9jb21iWzE6OSwyXSx0eXBlID0gImwiLCB4bGFiID0gIlJlYWwgZWZmZWN0Iix5bGFiID0gIkVzdGltYXRlZCBlZmZlY3QgLyBQb3dlciIsIGNvbCA9ICJyZWQiKQpsaW5lcyhhbGxfY29tYlsxOjksMl0sYWxsX2NvbWJbMTo5LDldLCBjb2wgPSAiIzA4MzA2QiIpCmxpbmVzKGFsbF9jb21iWzEwOjE4LDJdLGFsbF9jb21iWzEwOjE4LDldLCBjb2wgPSAiIzA4NTE5QyIpCmxpbmVzKGFsbF9jb21iWzE5OjI3LDJdLGFsbF9jb21iWzE5OjI3LDldLCBjb2wgPSAiIzIxNzFCNSIpCmxpbmVzKGFsbF9jb21iWzI4OjM2LDJdLGFsbF9jb21iWzI4OjM2LDldLCBjb2wgPSAiIzQyOTJDNiIpCmxpbmVzKGFsbF9jb21iWzM3OjQ1LDJdLGFsbF9jb21iWzM3OjQ1LDldLCBjb2wgPSAiIzZCQUVENiIpCmxpbmVzKGFsbF9jb21iWzQ2OjU0LDJdLGFsbF9jb21iWzQ2OjU0LDldLCBjb2wgPSAiIzlFQ0FFMSIpCmxpbmVzKGFsbF9jb21iWzU1OjYzLDJdLGFsbF9jb21iWzU1OjYzLDldLCBjb2wgPSAiI0M2REJFRiIpCmxpbmVzKGFsbF9jb21iWzE6OSwyXSxhbGxfY29tYlsxOjksOF0sIGNvbCA9ICIjMDgzMDZCIiwgbHR5ID0gMikKbGluZXMoYWxsX2NvbWJbMTA6MTgsMl0sYWxsX2NvbWJbMTA6MTgsOF0sIGNvbCA9ICIjMDg1MTlDIiwgbHR5ID0gMikKbGluZXMoYWxsX2NvbWJbMTk6MjcsMl0sYWxsX2NvbWJbMTk6MjcsOF0sIGNvbCA9ICIjMjE3MUI1IiwgbHR5ID0gMikKbGluZXMoYWxsX2NvbWJbMjg6MzYsMl0sYWxsX2NvbWJbMjg6MzYsOF0sIGNvbCA9ICIjNDI5MkM2IiwgbHR5ID0gMikKbGluZXMoYWxsX2NvbWJbMzc6NDUsMl0sYWxsX2NvbWJbMzc6NDUsOF0sIGNvbCA9ICIjNkJBRUQ2IiwgbHR5ID0gMikKbGluZXMoYWxsX2NvbWJbNDY6NTQsMl0sYWxsX2NvbWJbNDY6NTQsOF0sIGNvbCA9ICIjOUVDQUUxIiwgbHR5ID0gMikKbGluZXMoYWxsX2NvbWJbNTU6NjMsMl0sYWxsX2NvbWJbNTU6NjMsOF0sIGNvbCA9ICIjQzZEQkVGIiwgbHR5ID0gMikKYGBgClRoZSBkYXNoZWQgbGluZXMgY29ycmVzcG9uZCB0byB0aGUgcG93ZXIgdG8gZGV0ZWN0IHRoZSBzaW11bGF0ZWQgZWZmZWN0cyAoWCBheGlzKSB3aXRoIHBvcHVsYXRpb24gb2YgaW5jcmVhc2luZyBzaXplIChkYXJrIHRvIGxpZ2h0IGJsdWUpLiAgVGhlIHJlZCBkaWFnb25hbCBjb3JyZXNwb25kcyB0byB0aGUgZXhwZWN0YXRpb24gYXNzdW1pbmcgdGhhdCB0aGUgZWZmZWN0cyBhcmUgcGVyZmVjdGx5IGVzdGltYXRlZC4gVGhlIHJlZ3VsYXIgbGluZXMgY29ycmVzcG9uZCB0byB0aGUgZXN0aW1hdGVzIGVmZmVjdHMgaW4gdGhlIHBvcHVsYXRpb25zIG9mIGluY3JlYXNpbmcgc2l6ZSAoZGFyayB0byBsaWdodCBibHVlKS4gIFdoYXQgd2Ugc2VlIGlzIHRoYXQgd2hlbiB0aGUgcG93ZXIgZGVwYXJ0cyBmcm9tIDEwMCUsIHRoZSBlZmZlY3RzIHRlbmQgdG8gYmUgb3ZlcmVzdGltYXRlZC4gUXVpdGUgaW50ZXJlc3RpbmdseSwgYXQgc3Vib3B0aW1hbCBwb3dlciB0aGUgZXN0aW1hdGVkIGVmZmVjdHMgYXBwZWFyIHRvIGJlIGRldGVybWluZWQgYnkgdGhlIHNhbXBsZSBzaXplIG1vcmUgdGhhbiBieSB0aGUgYWN0dWFsIGVmZmVjdC4gIFRodXMsIHVuZGVyIHRoZXNlIGNvbmRpdGlvbnMsIHRoZSBlc3RpbWF0ZXMgdGVsbCB1cyBtb3JlIGFib3V0IG91ciBleHBlcmltZW50YWwgZGVzaWduIHRoYW4gYWJvdXQgdGhlIGJpb2xvZ3kgd2UgYXJlIHRyeWluZyB0byBzdHVkeS4KCkhvdyBjYW4gd2UgYWRkcmVzcyB0aGlzICJjdXJzZSI/ICBFc3BlY2lhbGx5IGluIC1vbWljIHN0dWRpZXMsIGl0IGlzIGEgZ29vZCBpZGVhIHRvIGRpc3Rpbmd1aXNoIGEgZGlzY292ZXJ5IHBoYXNlIGZyb20gYSBjb25maXJtYXRpb24gcGhhc2UuICBFZmZlY3RzIGFyZSBmaXJzdCBkaXNjb3ZlcmVkIGluIGEgImRpc2NvdmVyeSIgc2FtcGxlLCBhcHBseWluZyBzdHJpbmdlbnQgc2lnbmlmaWNhbmNlIHRocmVzaG9sZHMgdGhhdCBwcm9wZXJseSBhY2NvdW50IGZvciBtdWx0aXBsZSB0ZXN0aW5nLiBJbiBhIHNlY29uZCBzdGFnZSwgdGhlICJkaXNjb3ZlcmVkIiBlZmZlY3RzIGFyZSB0aGVuIGNvbmZpcm1lZCBpbiBhbiBpbmRlcGVuZGVudCAiY29uZmlybWF0aW9uIiBzYW1wbGUsIHVzaW5nIGEgbW9yZSBsZW5pZW50IHRocmVzaG9sZCB0aGF0IG9ubHkgY29ycmVjdHMgZm9yIHRoZSBudW1iZXIgb2YgZGlzY292ZXJpZXMuICBJZiBzaWduaWZpY2FudCBpbiB0aGUgY29uZmlybWF0aW9uIHNhbXBsZSwgdGhlIGVmZmVjdCBpcyBkZWVtZWQgcmVhbCwgd2hpbGUgdGhlIGNvbmZvcm1hdGlvbiBjb2hvcnQgcHJvdmlkZXMgYSBsZXNzIGJpYXNlZCBlc3RpbWF0ZSBvZiB0aGUgc2l6ZSBvZiB0aGUgdHJ1ZSBlZmZlY3QuICAgICAgICAKCiAgCiNUYWtlIGhvbWUgbWVzc2FnZXMgIAoKMS4gVGhlIHAtdmFsdWUgb2YgYSB0ZXN0IGlzIHRoZSBwcm9iYWJpbGl0eSB0byBoYXZlIGFuIGVxdWFsbHkgb3IgbW9yZSB1bmxpa2VseSBvdXRjb21lIG9mIGEgdGVzdCB1bmRlciB0aGUgbnVsbCBoeXBvdGhlc2lzIChIMCkuICAKCjIuIHAtdmFsdWVzIGNhbiBiZSBjb21wdXRlZCB3aXRoIHN0YW5kYXJkIHN0YXRpc3RpYyB0ZXN0cyBvciwgaW5jcmVhc2luZ2x5LCB1c2luZyBzZWxmLWRlc2lnbmVkIGVtcGlyaWNhbCB0ZXN0cyB1c2luZyBpbiBzaWxpY28gc2ltdWxhdGlvbiBhbmQvb3IgcGVybXV0YXRpb24uICAKICAKMy4gV2hlbiBwZXJmb3JtaW5nIG11bHRpcGxlIHRlc3RzLCB0aGUgdGhyZXNob2xkIHAtdmFsdWUgdG8gZGVjbGFyZSBzaWduaWZpY2FuY2UgaGFzIHRvIGJlIGFkanVzdGVkIGluIG9yZGVyIHRvIGNvbnRyb2wgdGhlIG51bWJlciBvZiBleHBlcmltZW50LXdpZGUgZmFsc2UgcG9zaXRpdmVzLiAqKk5PVCBET0lORyBUSElTIEFQUFJPUFJJQVRFTFkgSVMgQSBNQUpPUiBTT1VSQ0UgT0YgRkFMU0UgUE9TSVRJVkVTIElOIFRIRSBMSVRURVJBVFVSRS4qKiAgCiAgCjQuIFJhdGhlciB0aGFuIGFkanVzdGluZyB0aGUgdGhyZXNob2xkIHZhbHVlIGZvciB0aGUgZWZmZWN0aXZlIG51bWJlciBvZiByZWFsaXplZCB0ZXN0cywgb25lIG1heSBleHBsb2l0IHRoZSBvYnRhaW5lZCBkaXN0cmlidXRpb24gb2YgcC12YWx1ZXMgdG8gY29tcHV0ZSBGRFIgb3IgcS12YWx1ZXMuICBUaGlzIGlzIGVzcGVjaWFsbHkgZWZmZWN0aXZlIHdoZW4gdGhlIHByb3BvcnRpb24gb2YgdHJ1ZSBIMSBoeXBvdGhlc2VzIGlzIGhpZ2ggYW1vbmdzdCB0aGUgcmVhbGl6ZWQgdGVzdHMsIGhlbmNlIGNhdXNpbmcgYSBtYWpvciBzaGlmdCBvZiB0aGUgcC12YWx1ZSBkaXN0cmlidXRpb24gdG8gbG93IHZhbHVlcy4gIAogIAo1LiBXaGVuIHRoZSBzdGF0aXN0aWNhbCBwb3dlciB0byBkZXRlY3QgYSB0cnVlIEgxIGlzIGxpbWl0ZWQgKGZvciBpbnN0YW5jZSBiZWNhdXNlIHRoZSBzYW1wbGUgc2l6ZSBpcyB0b28gc21hbGwpLCB0aGUgZWZmZWN0IHdpbGwgb2Z0ZW4gYmUgbWlzc2VkIChmYWxzZSBuZWdhdGl2ZXMsIHR5cGUgSUkgZXJyb3IpLiAgKipUSElTIElTIEEgVkFMSUQgQ0FVU0UgT0YgTk9OLVJFUFJPRFVDSUJJTElUWSBPRiBQVUJMSVNIRUQgUkVTVUxUUy4qKiAgVG8gZGV0ZWN0IHRoZSBlZmZlY3Qgb25lIGhhcyB0byBiZSBhIGJpdCBsdWNreSwgaS5lLiB0aGUgZWZmZWN0IG5lZWRzIHRvIGJlIC0gYnkgY2hhbmNlIC0gb3ZlcmVzdGltYXRlZCBpbiB5b3VyIGRhdGEuIFRodXMsIHdoZW4gb25lIGRldGVjdHMgYW4gZWZmZWN0IHRoYXQgb25lIGhhZCBhIHNtYWxsIGNoYW5jZSB0byBkZXRlY3QsIGl0IHdpbGwgYmUgb3ZlcmVzdGltYXRlZCBpbiB0aGUgImRpc2NvdmVyeSIgc2FtcGxlICg9ICoqV2lubmVycycgY3Vyc2UqKikuICBBcyBtYXR0ZXIgb2YgZmFjdCwgdW5kZXIgY29uZGl0aW9ucyBvZiBsb3cgc3RhdGlzdGljYWwgcG93ZXIsIHRoZSBlc3RpbWF0ZXMgb2YgdGhlIGVmZmVjdHMgYXJlIGRldGVybWluZWQgbW9yZSBieSB0aGUgc2FtcGxlIHNpemUgdGhhbiBieSB0aGUgYWN0dWFsIGVmZmVjdCBzaXplLiAgICAgIAoKI0Fja25vd2xlZGdlbWVudHMgIAogIApJIHRoYW5rIHRoZSAyMDE5IHN0dWRlbnRzIGZvciBhIHZlcnkgcGxlYXNhbnQgYW5kIGludGVyYWN0aXZlIHRocmVlIGRheXMgKDIxLTIzLzEwKS4gIEkgd291bGQgYWxzbyBsaWtlIHRvIHRoYW5rIG9uZSBvZiB0aGUgc3R1ZGVudHMgKDIwMTksIFJlbmF1ZCBOaXZlbGxlKSBmb3Igc2hhcmluZyBoaXMgZXhjZWxsZW50IFIgc2NyaXB0cywgYW5kIGhlbHBpbmcgdXMgYWxsIHRvIHByb2dyZXNzLgoKCgoKCgoKCgoKCg==