1 Introduction

1.1 Population

  • The aim of a scientific study is to draw conclusions on the general population.

  • Here, we study the effect of captopril on the blood pressure of patients with hypertension.

  • We will collect data and we will model the data

  • Therefore, we always have to translate the research question with respect to model parameter or a combination of model parameters.

  • e.g. the population mean \[E(X)=\mu\]

  • Does the blood pressure decreases on average after administering captopril to patients with hypertension?


1.2 Overview

  • Experimental Design & Data Exploration
  • Point estimators (Estimation)
  • Interval estimators (Statistical inference)
  • Hypothesis tests (Statistical inference)

2 Experimental Design

  • 15 patients were drawn at random from the population of patients with hypertension
  • pre-test/post-test design: the systolic and diasystolic blood pressure are measured before and after administering captopril
  • Advantage: we can assess the effect of administering captopril on the blood pressure for each individual patient.
  • Disadvantage?


3 Data exploration and Descriptive Statistics

captopril <- read_csv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/captopril.txt")
head(captopril)
# A tibble: 6 x 5
     id  SBPb  DBPb  SBPa  DBPa
  <dbl> <dbl> <dbl> <dbl> <dbl>
1     1   210   130   201   125
2     2   169   122   165   121
3     3   187   124   166   121
4     4   160   104   157   106
5     5   167   112   147   101
6     6   176   101   145    85
summary(captopril)
       id            SBPb            DBPb            SBPa    
 Min.   : 1.0   Min.   :146.0   Min.   : 98.0   Min.   :129  
 1st Qu.: 4.5   1st Qu.:163.5   1st Qu.:103.0   1st Qu.:146  
 Median : 8.0   Median :174.0   Median :112.0   Median :157  
 Mean   : 8.0   Mean   :176.9   Mean   :112.3   Mean   :158  
 3rd Qu.:11.5   3rd Qu.:192.5   3rd Qu.:121.5   3rd Qu.:168  
 Max.   :15.0   Max.   :210.0   Max.   :130.0   Max.   :201  
      DBPa      
 Min.   : 82.0  
 1st Qu.: 98.0  
 Median :103.0  
 Mean   :103.1  
 3rd Qu.:108.0  
 Max.   :125.0  
captoprilTidy <- captopril %>% gather(type,bp,-id) 
captoprilTidy %>% 
  group_by(type) %>%
  summarize_at("bp",list(mean=~mean(.,na.rm=TRUE),
                    sd=~sd(.,na.rm=TRUE),
                    n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
  mutate(se=sd/sqrt(n)) 
# A tibble: 4 x 5
  type   mean    sd     n    se
  <chr> <dbl> <dbl> <int> <dbl>
1 DBPa   103.  12.6    15  3.24
2 DBPb   112.  10.5    15  2.70
3 SBPa   158   20.0    15  5.16
4 SBPb   177.  20.6    15  5.31
captoprilTidy %>% 
  group_by(type) %>%
  summarize_at("bp",list(mean=~mean(.,na.rm=TRUE),
                    sd=~sd(.,na.rm=TRUE),
                    n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
  mutate(se=sd/sqrt(n)) %>%
  ggplot(aes(x=type,y=mean)) + 
  geom_bar(stat="identity") +
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se),width=.2) +
  ylim(0,210) +
  ylab("blood pressure (mmHg)")

  • This figure is not informative! It does not show the raw data.
captoprilTidy %>% 
  ggplot(aes(x=type,y=bp)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter") + 
  ylim(0,210)

We see that a lot of the space that was taken by the barplot does not contain data!

captoprilTidy %>% 
  ggplot(aes(x=type,y=bp)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter") 

  • This plot would have been informative if the data was gathered on different individuals.

  • However, the blood pressures are measured op the same subject!

  • We will make a plot by filtering the systolic blood pressures

captoprilTidy %>%
  filter(type%in%c("SBPa","SBPb")) %>%
  mutate(type=factor(type,levels=c("SBPb","SBPa"))) %>%
  ggplot(aes(x=type,y=bp)) +
  geom_line(aes(group = id)) +
  geom_point()

  • We have paired data. So we might estimate the effect of the treatment directly by comparing the blood pressure after treatment to the blood pressure before the treatment.
captopril$deltaSBP<-captopril$SBPa-captopril$SBPb
captopril%>%
  ggplot(aes(x="Systolic blood pressure",y=deltaSBP)) +
  geom_boxplot(outlier.shape=NA) + 
  geom_point(position="jitter")+
  ylab("Difference (mm mercury)") +
  xlab("")

captopril %>%
  summarize_at("deltaSBP",list(mean=~mean(.,na.rm=TRUE),
              sd=~sd(.,na.rm=TRUE),
              n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
  mutate(se=sd/sqrt(n))
# A tibble: 1 x 4
   mean    sd     n    se
  <dbl> <dbl> <int> <dbl>
1 -18.9  9.03    15  2.33
  • Pre-test/post-test design: Effect of captopril in sample using \(X=\Delta_\text{after-before}\)!

  • How will we model \(X=\Delta_\text{after-na}\) and estimate the effect of captopril?

captopril%>%
  ggplot(aes(sample=deltaSBP)) +
  stat_qq() +
  stat_qq_line()

The systolic blood pressure differences are approximately normally distributed.


4 Estimation

  • No substantial deviations from normality

  • We can assume that the differences \(X \sim N(\mu, \sigma^2)\).

  • Effect of captopril in the population is captured by the average blood pressure difference \(\mu\).

  • The average blood pressure \(\mu\) in the population can be estimated using the sample mean \(\bar x\)=-18.93

  • The standard deviation \(\sigma\) with the sample standard deviation \(\text{S}\)=9.03.

  • Is the effect that we observe in the sample large enough to conclude that there is an effect of the captopril treatment on the blood pressure at population level?

  • Our estimates will change from sample to sample!

  • How are the estimators \(\bar X\) and \(S\) distributed?

4.1 Point estimator the sample mean

  • Suppose that \(X\) is a random sample from the population and assume that \(X \sim N(\mu,\sigma^2)\)

  • Estimate \(\mu\) based on sample \(X_1,...,X_n\), using the sample mean \[\bar X = \frac{X_1+ X_2+ ... + X_n}{n} = \frac{\sum_{i=1}^{n} X_i}{n}\] of random variables \(X_1,X_2, ..., X_n\).

  • Sample mean \(\bar X\) is a random variable that varies from sample to sample

  • Study the theoretical distribution of the sample mean to get insight

    1. in how the sample mean can vary in a new similar study
    2. how far \(\bar X\) can be from the population mean \(\mu\)

4.1.1 Overview

  1. The sample mean is unbiased
  2. Precision of sample mean
  3. Distribution of sample mean

4.1.2 The sample mean is unbiased

  • We can generalize our observations based on the sample towards the population if the estimate is good approximation of the population value.

  • A representative sample is required to generalize the results from the sample towards the population

  • Avoid bias (so that the population mean is not systematically under or overestimated)

  • Report how the sample is taken!

  • Randomisation!

  • Draw the subjects at random from population so every subject has the same probability to end up in the sample.

  • Subjects with hypertension are sampled at random from the population

  • Simple random sample: \(X_1,...,X_n\) for characteristic \(X\)

  • \(X_1,...,X_n\) have same distribution
  • They have same mean \(\mu\) and variance \(\sigma^2\)

  • \(E(X_1)=...=E(X_n)=\mu\) and \(\text{Var}(X_1)=...=\text{Var}(X_n)=\sigma^2\)

  • \(\bar X\) is an unbiased estimator for \(\mu\)

Click to see proof

\[\begin{eqnarray*} E(\bar X) &=& E \left(\frac{X_1+ X_2+ ... + X_n}{n}\right) \\ &= & \frac{E(X_1)+ E(X_2)+ ... + E(X_n)}{n} \\ &=& \frac{\mu + \mu + ... +\mu}{n} \\ &= & \mu \end{eqnarray*}\]


4.1.3 Imprecision/standard error

  • Also for representative samples the results are imprecise.
  • Different samples from the same population give different results.

  • We illustrated this by using the NHANES

    • We will draw 15 females at random from the NHANES study and we will register their log2 direct cholesterol values
    • We repeat this 50 times to assess the variation from sample to sample
    • We will plot the boxplot for each sample and will indicate the mean
library(NHANES)

fem <- NHANES %>% 
  filter(Gender=="female" & !is.na(DirectChol)) %>%
  select("DirectChol")

n<-15 # number of subjects per sample
nSim=50 # number of simulations

femSamp<-matrix(nrow=n,ncol=nSim)
for (j in 1:nSim)
{
  femSamp[,j]<-sample(fem$DirectChol,15)
  if (j<4) {
    p <- femSamp %>% 
      log2 %>%
      data.frame %>% 
      gather("sample","log2cholesterol") %>%
      ggplot(aes(x=sample,y=log2cholesterol)) +
      geom_boxplot() + 
      stat_summary(fun.y=mean, geom="point", shape=19, size=3, color="red", fill="red") +
      geom_hline(yintercept = mean(fem$DirectChol %>% log2)) +
      ylab("cholesterol (log2)") 
    print(p)
  }
}

femSamp %>% 
  log2 %>% 
  data.frame %>% 
  gather("sample","log2cholesterol") %>%
  ggplot(aes(x=sample,y=log2cholesterol)) +
  geom_boxplot() + 
  stat_summary(fun.y=mean, geom="point", shape=19, size=3, color="red", fill="red") +
  geom_hline(yintercept = mean(fem$DirectChol %>% log2)) +
  ylab("cholesterol (log2)")

We observe that the mean nicely fluctuates around the population mean.

Copy the code, increase the sample size to 100 subjects and observe what happens!


4.1.4 How to do this based on a single sample?

  • Insight in how close we can expect \(\bar X\) to \(\mu\)?

  • How varies \(\bar X\) from sample to sample?

  • Variability on \(\bar X\)

  • We have to determine this based on a single sample!

  • We need to make assumptions

  • We assume that the random variables \(X_1, X_2, ..., X_n\) originate from \(n\) independent subjects.

  • For the captopril study we had dependent observations.

    • Blood pressure measurements before (\(Y_{i,before}\)) and after (\(Y_{i,after}\)) administering captopril for the same subject \(i=1,\ldots,n\).
    • We turned them into n independent measurements by taking the difference \(Y_{i,after}-Y_{i,before}\)

4.1.5 Variance estimator for \(\bar X\)

\[\sigma^2_{\bar X}=\frac{\sigma^2}{n}\]

  • The standard deviation of \(\bar X\) around \(\mu\) is \(\sqrt{n}\) times smaller that the deviation around the original observations \(X\).

  • The more observations we have the more precise \(\bar X\).

Click to see proof

\[\begin{eqnarray*} \text{Var}(\bar X)&=&\text{Var} \left(\frac{X_1+ X_2+ ... + X_n}{n}\right) \\ &= & \frac{\text{Var} (X_1+ X_2+ ... + X_n)}{n^2} \\ &\overset{*}{=} & \frac{\text{Var}(X_1)+ \text{Var}(X_2)+ ... + \text{Var}(X_n)}{n^2} \\ &=& \frac{\sigma^2 + \sigma^2 + ... \sigma^2}{n^2} \\ &= & \frac{\sigma^2}{n}. \end{eqnarray*}\]

  • (*) this is based on the assumption of independence. \[\text{Var}[X_1 + X_2] = \text{Var}[X_1] + \text{Var}[X_2] + 2 \text{Covar}[X_1,X_2]\]

    • With \(Covar[X_1,X_2]=0\) when \(X_1\) and \(X_2\) are independent.

Definition: standard error

The standard deviation of \(\bar{X}\) is \(\sigma/\sqrt{n}\) and is also referred to as the standard error of the mean. Generally one refers to the standard deviation of an estimator for a particular parameter \(\theta\) with the term standard error of the estimator, which is denoted as \(SE\).


4.1.6 Captopril example

  • \(n = 15\) differences in systolic blood pressure

  • Suppose that the standard deviation of the blood pressure differences in the population is \(\sigma = 9.0\) mmHg

  • Then, the standard error (SE) on the average systolic blood pressure differs \(\bar X\) becomes:

\[ SE= \frac{9.0}{\sqrt{15}}=2.32\text{mmHg.} \]

  • Generally \(\sigma\), and thus the SE on the sample mean are unknown.
  • So we also have to estimate the standard deviation of the sample to obtain the standard error
  • Estimator: \(SE=S/\sqrt{n},\)
  • with \(S^2\) the sample variance of \(X_1,...,X_n\) and \(S\) the sample standard deviation

  • For the captopril example we obtain:

n=length(captopril$deltaSBP)
se=sd(captopril$deltaSBP)/sqrt(n)
se
[1] 2.330883

4.1.7 standard deviation vs standard error

4.1.7.1 Illustrate via repeated sampling

  • Different sample sizes: 10, 50, 100
  • Draw 1000 samples per sample size from the NHANES study, for each sample we calculate
    • The mean
    • The sample standard deviation
    • The standard error
  • We make a boxplot of the sample standard deviations and the standard errors for the different sample sizes

  • Instead of using a for loop we will use the sapply function which is more efficient. It takes a vector or a list as input and applies a function on each element of the vector or on each list element.

femSamp10<-sapply(1:1000,function(j,x,size) sample(x,size),size=10,x=fem$DirectChol) 

femSamp50<-sapply(1:1000,function(j,x,size) sample(x,size),size=50,x=fem$DirectChol) 

femSamp100<-sapply(1:1000,function(j,x,size) sample(x,size),size=100,x=fem$DirectChol) 

res<-rbind(
femSamp10 %>% 
  log2%>%
  as.data.frame %>% 
  gather(sample,log2Chol) %>% 
  group_by(sample)%>%
  summarize_at("log2Chol",
               list(median=~median(.,na.rm=TRUE),
                    mean=~mean(.,na.rm=TRUE),
                    sd=~sd(.,na.rm=TRUE),
                    n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
  mutate(se=sd/sqrt(n)) ,

femSamp50 %>% 
  log2 %>%  
  as.data.frame %>%
  gather(sample,log2Chol) %>%
  group_by(sample)%>%
  summarize_at("log2Chol",
               list(median=~median(.,na.rm=TRUE),
                    mean=~mean(.,na.rm=TRUE),
                    sd=~sd(.,na.rm=TRUE),
                    n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
  mutate(se=sd/sqrt(n)),

femSamp100 %>% 
  log2 %>% 
  as.data.frame %>% 
  gather(sample,log2Chol) %>% 
  group_by(sample)%>%
  summarize_at("log2Chol",
               list(median=~median(.,na.rm=TRUE),
                    mean=~mean(.,na.rm=TRUE),
                    sd=~sd(.,na.rm=TRUE),
                    n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
  mutate(se=sd/sqrt(n))
)
4.1.7.1.1 Means

We first illustrate the impact of sample size on the distribution of the means of the different samples

res %>% 
ggplot(aes(x=n%>%as.factor,y=mean)) +
geom_boxplot() +
ylab("Direct cholesterol (log2)") + 
xlab("sample size")

  • Note, that the variation of the sample means indeed reduces as the sample size increases. So the estimation gets more precise with increasing sample size.

4.1.7.1.2 Standard deviation

We now illustrate the impact of sample size on the distribution of the standard deviation of the different samples

res %>% 
ggplot(aes(x=n%>%as.factor,y=sd)) +
geom_boxplot() +
ylab("standard deviation") + 
xlab("sample size")

  • The standard deviation remains similar across sample size. It is centred around the same value: the standard deviation in the population. Indeed increasing the sample size does affect the variability in the population!

  • Again we see that the variability of the standard deviation reduces with increasing sample size. So the standard deviation can also be estimated more precise with increasing sample size.


4.1.7.1.3 Standard error on the mean

Finally, we illustrate the impact of sample size on the distribution of the standard deviation on the mean of the different samples

res %>% 
ggplot(aes(x=n%>%as.factor,y=se)) +
geom_boxplot() +
ylab("standard error") + 
xlab("sample size")

  • The standard error, the estimator for the precision of the sample mean, however, reduces considerably with increasing sample size again confirming that the estimation of the sample mean gets more precise.

4.1.8 Normally distributed data

  • For normally distributed data we have multiple estimators for the population mean \(\mu\) e.g mean and median.

  • But, \(\bar{X}\) is the unbiased estimator of \(\mu\) with the smallest standard error

  • \(\bar{X}\) deviates less from the mean \(\mu\) than the median

  • We illustrate this for repeated sampling with sample size 10

res %>%
  filter(n==10) %>%
  select(mean,median) %>%
  gather(type,estimate) %>%
  ggplot(aes(x=type,y=estimate)) +
  geom_boxplot()+
  geom_hline(yintercept=fem$DirectChol%>%log2%>%mean) +
  ggtitle("10 subjects")

Next, we compare the distribution of mean and median in repeated samples of sample size 50.

res %>%
  filter(n==50) %>%
  select(mean,median) %>%
  gather(type,estimate) %>%
  ggplot(aes(x=type,y=estimate)) +
  geom_boxplot()+
  geom_hline(yintercept=fem$DirectChol%>%log2%>%mean) +
  ggtitle("50 subjects")

4.1.9 Distribution of sample mean

  • How varies \(\bar X\) from sample to sample?
  • Distribution of \(\bar X\)?
  • If \(\bar X\) is normally distributed the standard error has a good interpretation: the s.e. is the standard deviation of the sample mean.
  • If the data \(X_i\) are normally distributed, the sample mean is also normally distributed.

\[X_i \sim N(\mu,\sigma^2) \rightarrow \bar X \sim N(\mu, \sigma^2/n)\]


4.1.9.1 NHANES: cholesterol

We illustrate this again with simulation using the NHANES study. The log2 cholesterol levels were normally distributed.

 fem %>% 
  ggplot(aes(x=DirectChol%>%log2))+
  geom_histogram(aes(y=..density.., fill=..count..)) +
  xlab("Direct cholesterol (log2)") +
  stat_function(fun=dnorm,color="red",args=list(mean=mean(fem$DirectChol%>%log2), sd=sd(fem$DirectChol%>%log2))) +
  ggtitle("All females in Nhanes study")

fem %>% 
  ggplot(aes(sample=DirectChol%>%log2)) +
  stat_qq() +
  stat_qq_line() +
  ggtitle("All females in Nhanes study")


4.1.9.1.1 Evaluate distribution for samples with 5 subjects
femSamp5<-sapply(1:1000,function(j,x,size)
  sample(x,size),size=5,x=fem$DirectChol)

femSamp5[,1] %>% 
  log2 %>% 
  as.data.frame %>%
  ggplot(aes(x=.))+
  geom_histogram(aes(y=..density.., fill=..count..),bins=10) +
  xlab("Direct cholesterol (log2)") +
  stat_function(fun=dnorm,color="red",args=list(mean=femSamp5[,1]%>%log2%>%mean, sd=femSamp5[,1]%>%log2%>%sd)) +
  ggtitle("5 random females") + 
  xlim(fem$DirectChol %>% log2 %>% range)

femSamp5 %>% 
  log2 %>% 
  colMeans %>% 
  as.data.frame %>% 
  ggplot(aes(x=.)) +
  geom_histogram(aes(y=..density.., fill=..count..),bins=15) +
  xlab("Mean cholesterol (log2)") +
  stat_function(fun=dnorm,color="red",args=list(mean=femSamp5%>%log2%>% colMeans %>% mean, sd=femSamp5%>%log2%>% colMeans %>% sd)) +
ggtitle("Means on 5 females") 

femSamp5 %>% 
  log2 %>% 
  colMeans %>% 
  as.data.frame %>%  
  ggplot(aes(sample=.)) +
  stat_qq() +
  stat_qq_line() +
  ggtitle("Means on 5 females")


4.1.9.1.2 Explore the distribution of the mean for samples of size 10

Now we explore the results for the sample size of 10.

We first illustrate the plot for the first sample.

femSamp10[,1] %>% log2 %>% as.data.frame %>%
ggplot(aes(x=.))+
  geom_histogram(aes(y=..density.., fill=..count..),bins=10) +
  xlab("Direct cholesterol (log2)") +
  stat_function(fun=dnorm,color="red",args=list(mean=femSamp10[,1]%>%log2%>%mean, sd=femSamp10[,1]%>%log2%>%sd)) +
ggtitle("10 random females") + 
xlim(fem$DirectChol %>% log2 %>% range)

Next we look at the distribution of the sample mean over 1000 samples of sample size 10.

femSamp10 %>% log2 %>% colMeans %>% as.data.frame %>% ggplot(aes(x=.)) +
  geom_histogram(aes(y=..density.., fill=..count..),bins=15) +
  xlab("Mean cholesterol (log2)") +
  stat_function(fun=dnorm,color="red",args=list(mean=femSamp10%>%log2%>% colMeans %>% mean, sd=femSamp10%>%log2%>% colMeans %>% sd)) +
ggtitle("Means on 10 females") 

femSamp10 %>% log2%>% colMeans %>% as.data.frame %>%  ggplot(aes(sample=.)) +
stat_qq() +
stat_qq_line() +
ggtitle("Means on 10 females")

So we confirmed that the mean is approximately normally distributed for studies with 5 and 10 females when the original data are approximately normally distributed.


4.1.9.2 Captopril study

  • For Captopril study the systolic blood pressure differences are approximatively normally distributed.

  • s.e.= 2.32 mm Hg

  • In 95 out of 100 studies with n = 15 subjects we expect the sample mean of the systolic blood pressure differences (\(\bar X\)) on less then \(2 \times 2.32 = 4.64\)mm Hg of the real population mean of the blood pressure differences (\(\mu\)).


4.1.10 Non-normally distributed data

  • When individual observations do not have a normal distribution, \(\bar X\) is still Normally distributed when the number observations are large enough.

  • How large does the sample needs to be for the Normal approximation to work?

  • This depends on the skewness of the distribution!


4.1.10.1 NHANES: cholesterol

  • When can evaluated this in the NHanes study if we do not log2 transform the data.
fem %>% ggplot(aes(x=DirectChol))+
   geom_histogram(aes(y=..density.., fill=..count..)) +
   xlab("Direct cholesterol") +
   stat_function(fun=dnorm,color="red",args=list(mean=mean(fem$DirectChol), sd=sd(fem$DirectChol))) +
   ggtitle("All females in Nhanes study")

 fem %>% ggplot(aes(sample=DirectChol)) +
 stat_qq() +
 stat_qq_line() +
 ggtitle("All females in Nhanes study")

The cholesterol data is clearly non-Normally distributed.

4.1.10.1.1 Distribution of the sample mean for different sample sizes
femSamp5 %>% colMeans %>% as.data.frame %>% ggplot(aes(x=.)) +
  geom_histogram(aes(y=..density.., fill=..count..),bins=15) +
  xlab("Mean cholesterol") +
  stat_function(fun=dnorm,color="red",args=list(mean=femSamp5%>% colMeans %>% mean, sd=femSamp5%>% colMeans %>% sd)) +
ggtitle("Means on 5 females") 

femSamp5 %>% colMeans %>% as.data.frame %>%  ggplot(aes(sample=.)) +
stat_qq() +
stat_qq_line() +
ggtitle("Means on 5 females")

femSamp10 %>% colMeans %>% as.data.frame %>% ggplot(aes(x=.)) +
  geom_histogram(aes(y=..density.., fill=..count..),bins=15) +
  xlab("Mean cholesterol") +
  stat_function(fun=dnorm,color="red",args=list(mean=femSamp10%>% colMeans %>% mean, sd=femSamp10%>% colMeans %>% sd)) +
ggtitle("Means on 10 females") 

femSamp10 %>% colMeans %>% as.data.frame %>%  ggplot(aes(sample=.)) +
stat_qq() +
stat_qq_line() +
ggtitle("Means on 10 females")

femSamp50 %>% colMeans %>% as.data.frame %>%  ggplot(aes(sample=.)) +
stat_qq() +
stat_qq_line() +
ggtitle("Means on 50 females")

femSamp100 %>% colMeans %>% as.data.frame %>%  ggplot(aes(sample=.)) +
stat_qq() +
stat_qq_line() +
ggtitle("Means on 100 females")

  • We observe that when the data are not normally distributed the distribution of the sample mean is not normally distributed in small samples

  • For large samples, however, the sample mean of non normal data is still approximately normally distributed.


4.1.11 Centrale Limit Theorem

Let \(X_1, \ldots, X_n\) are sequence of random variables that are drawn independently from the same distribution (population). As long as the sample size n is sufficiently large, the sample mean \(\bar X\) is approximately normally distributed, irrespective of the distribution of the observations \(X_i\).

4.1.12 Overview on the distribution of the mean


5 Interval estimators

  • \(\bar X\) varies around \(\mu\)

  • Here we will develop an interval around \(\bar X\) that will contain the value of \(\mu\) with a probability of 95% for a random sample.

  • We first assume \(\sigma^2\) to be known and we will later relax this assumption.


5.1 Normally distributed data with known variance

  • \(X\sim N(\mu,\sigma^2) \rightarrow \bar X\sim N\left(\mu,\frac{\sigma^2}{n}\right)\)

  • 95% reference-interval for sample mean

\[\begin{equation*} \left[\mu - 1.96 \frac{\sigma}{\sqrt{n}},\mu + 1.96 \frac{\sigma}{\sqrt{n}}% \right] \end{equation*}\]
  • The interval contains the sample mean of a random sample with a probability of 95%.

  • We can not calculate it because \(\mu\) is unknown.

  • Estimate \(\mu\) by \(\bar X\).
    \[\begin{equation*} \left[\bar X - 1.96 \frac{\sigma}{\sqrt{n}},\bar X + 1.96 \frac{\sigma}{\sqrt{n}}\right] \end{equation*}\]
  • More useful interpretation:
  • Rewrite \(\mu - 1.96 \ \sigma/\sqrt{n} < \bar{X}\) as \(\mu < \bar{X} + 1.96 \ \sigma/\sqrt{n}\).

So that we can write \[\begin{eqnarray*} 95\% &=& P( \mu - 1.96 \ \sigma/\sqrt{n} < \bar{X} < \mu + 1.96 \ \sigma/\sqrt{n} ) \\ &=&P( \bar{X} - 1.96 \ \sigma/\sqrt{n} < \mu < \bar{X} + 1.96 \ \sigma/\sqrt{n} ) \end{eqnarray*}\]
Definition of 95% confidence interval on mean For a random sample, the interval \[\begin{equation} [\bar{X} - 1.96 \ \sigma/\sqrt{n} , \bar{X} + 1.96 \ \sigma/\sqrt{n} ], \end{equation}\]

contains the population mean \(\mu\) with a probability of 95%.


  • The probability that the CI for a random sample contains the population parameter \(\mu\), i.e. 95%, is also referred to as the confidence level.

  • Note, that the lower and upper limit of the interval are also random variables that vary from sample to sample. Different samples indeed result in different confidence intervals because they are based on different observation.

  • So they are stochastic intervals

  • 95% of the samples will produce a 95% confidence interval that will contain the population mean \(\mu\). The remaining 5% will produce intervals that do not contain the population mean.

  • Based on one interval you cannot conclude that it contains the real population parameter, because its value is unknown.

Generally the standard deviation is unknown and has to be estimated e.g. by \(S\)

  • For large \(n\) \([\bar{X} - 1.96 \ s/\sqrt{n} , \bar{X} + 1.96 \ s/\sqrt{n} ]\) will contain the population mean with a probability of approximately 95%.

5.1.1 NHANES log2 cholesterol example

5.1.1.1 One sample

samp50<-sample(fem$DirectChol,50)

ll<-mean(samp50 %>% log2) - 1.96*sd(samp50 %>% log2)/sqrt(50)
ul<-mean(samp50 %>% log2) + 1.96*sd(samp50 %>% log2)/sqrt(50)
popMean<-mean(fem$DirectChol%>%log2)

c(ll=ll,ul=ul,popMean=popMean)
       ll        ul   popMean 
0.4364753 0.6350546 0.5142563 

5.1.1.2 Repeated sampling

res$ll<-res$mean-1.96*res$se
res$ul<-res$mean+1.96*res$se
mu<-fem$DirectChol%>%log2%>%mean
res$inside<-res$ll<=mu & mu<=res$ul
res$n <- as.factor(res$n)
res %>% 
  group_by(n) %>% 
  summarize(coverage=mean(inside)) %>% 
  spread(n,coverage) 
# A tibble: 1 x 3
   `10`  `50` `100`
  <dbl> <dbl> <dbl>
1 0.928 0.938 0.954
  • Note, that the coverage in the samples with 10 observations is too low because we do not account for the uncertainty in the estimation of the standard deviation.

  • If we look to the first 20 intervals, 2 out of 20 do not contain the population mean.

res %>% 
  filter(n==10) %>% 
  slice(1:20) %>%
  ggplot(aes(x=sample,y=mean,color=inside)) + 
  geom_point() +
  geom_errorbar(aes(ymin=mean-1.96*se,ymax=mean+1.96*se))+
  geom_hline(yintercept = fem$DirectChol%>% log2 %>% mean) + 
  ggtitle("20 CI for N=10") + 
  ylim(range(fem$DirectChol %>% log2))


  • For large sample sizes (100) the coverage is fine because we can estimate the standard deviation with a relative high precision.
res %>% 
  filter(n==50) %>% 
  slice(1:20) %>%
  ggplot(aes(x=sample,y=mean,color=inside)) + 
  geom_point() +
  geom_errorbar(aes(ymin=mean-1.96*se,ymax=mean+1.96*se))+
  geom_hline(yintercept = fem$DirectChol%>% log2 %>% mean) +
  ggtitle("20 CI for N=50") +
  ylim(range(fem$DirectChol %>% log2))

res %>% 
  filter(n==100) %>% 
  slice(1:20) %>%
  ggplot(aes(x=sample,y=mean,color=inside)) + 
  geom_point() +
  geom_errorbar(aes(ymin=mean-1.96*se,ymax=mean+1.96*se))+
  geom_hline(yintercept = fem$DirectChol%>% log2 %>% mean) +
  ggtitle("20 CI for N=100") +
  ylim(range(fem$DirectChol %>% log2))

  • What have you observed for the interval width?

5.1.2 Other confidence levels

  • We can replace the \(z_{2.5\%}=1.96\) by another quantile of the normal distribution $z_{/2} to obtain an interval with another confidence level \(1-\alpha\).

  • Confidence intervals are not only used for the mean but also for other population parameters.


5.2 Unknown variance

In real examples \(\sigma\) is unknown and estimated based on the sample using the sample standard deviation \(S\).

  • The previous intervals were a bit to small because they did not account for the uncertainty on the estimation of \(S\).

  • When \(n\) is large, \(S\) is close to \(\sigma\).

  • Hence, \({(\bar{X} - \mu)}/{(S/\sqrt{n}) }\) is approximately standard normal and \[\begin{equation*} \left[\bar{X} - z_{\alpha/2} \ \frac{S}{\sqrt{n}} , \bar{X} + z_{\alpha/2} \ \frac{S}{\sqrt{n}}\right] \end{equation*}\]

    is an approximate \((1- \alpha)100\%\) CI for \(\mu\).

  • For small samples this no longer holds (e.g. n=10)

The estimation of \(S\) introduces additional uncertainty in the standardized value \({(\bar{X} - \mu)}/{(S/\sqrt{n})}\). Its distribution

  • is still symmetric but has heavier tails that the normal distribution.

  • it depends on \(n\) how much heavier the tails are

  • is a (Student) \(t\)-distribution with \(n-1\) degrees of freedom.


5.2.1 T-distribution

More formally: Let \(X_1, X_2, ..., X_n\) be an independent random sample from a Normal distribution \(N(\mu, \sigma^2)\), then \((\bar{X} - \mu)/(S/\sqrt{n})\) follows a \(t\)-distribution with \(n-1\) degrees of freedom.

The density of a t-distribution can be calculated in R using the function dt. It has arguments x for the quantile and df for the degrees of freedom.

grid <- seq(-5,5,.1)
densDist<-cbind(grid,dnorm(grid), sapply(c(2,5,10),dt,x=grid))
colnames(densDist)<-c("x","normal",paste0("t",c(2,5,10)))

densDist %>% as.data.frame %>% gather(dist,dens,-x) %>%
ggplot(aes(x=x,y=dens,color=dist)) +
geom_line() +
ylab("Density")

t-distributions have heavier tails then the normal distribution \(\rightarrow\) larger quantiles so broader intervals for the same confidence level.

  • This captures the additional uncertainty for estimating \(S\).

  • If \(n \rightarrow \infty\) then \(t(df) \rightarrow N(0,1)\)

  • quantiles of the \(t\)-distribution can be calculated in R using qt. e.g. 95%, 97.5%, 99.5% quantile for a t-distribution with 14 degrees of freedom:

qt(.975,df=14)
[1] 2.144787
qt(c(.95,.975,.995),df=14)
[1] 1.761310 2.144787 2.976843
  • These quantiles can be used to calculate 90%, 95% and 99% CI.

  • 97.5% quantile2.14 of a t-distribution with \(n-1=14\) degrees of freedom is indeed larger than that of a standard Normal distribution 1.96.


5.2.2 Confidence interval based on the t-distribution

The \(100\% (1-\alpha)\) CI for the mean \(\mu\) of a Normal distributed random variable \(X\) with unknown variance is

\[\begin{equation*} \left[\bar{X} - t_{n-1, \alpha/2} \frac{s}{\sqrt{n}} , \bar{X} + t_{n-1, \alpha/2} \frac{s}{\sqrt{n}}\right] \end{equation*}\]
  • We simply replace the \((1-\alpha/2)100\%\) quantile of the Normal distribution by that of the t-distribution with \(n-1\) degrees of freedom.

5.2.2.1 Captopril example

95% CI for the average blood pressure change becomes

mean(captopril$deltaSBP) -  qt(.975,df=14)*sd(captopril$deltaSBP)/sqrt(15)
[1] -23.93258
mean(captopril$deltaSBP) + qt(.975,df=14)*sd(captopril$deltaSBP)/sqrt(15)
[1] -13.93409

The 99% CI is given by

mean(captopril$deltaSBP) -  qt(.995,df=14)*sd(captopril$deltaSBP)/sqrt(15)
[1] -25.87201
mean(captopril$deltaSBP) + qt(.995,df=14)*sd(captopril$deltaSBP)/sqrt(15)
[1] -11.99466

Note, that zero is outside the interval and that the entire interval is negative indicating that there is on average a large effect by administrating captopril on the blood pressure of patients with hypertension.


5.2.3 Interpretation of the confidence interval

  • We will revisit the results for sampling log2 cholesterol levels from the large NHANES study. We first focus on the repeated experiments with sample size 10.
res$n<-as.character(res$n) %>% as.double(res$n)
res$ll<-res$mean-qt(0.975,df=res$n-1)*res$se
res$ul<-res$mean+qt(0.975,df=res$n-1)*res$se
mu<-fem$DirectChol%>%log2%>%mean
res$inside<-res$ll<=mu & mu<=res$ul
res$n <- as.factor(res$n)
res %>% group_by(n) %>% summarize(coverage=mean(inside)) %>% spread(n,coverage) 
# A tibble: 1 x 3
   `10`  `50` `100`
  <dbl> <dbl> <dbl>
1 0.956 0.944 0.957

We observe that all the coverages of the intervals are now controlled at their nominal 95% confidence level.

res %>% 
  filter(n==10) %>% 
  slice(1:20) %>%
  ggplot(aes(x=sample,y=mean,color=inside)) + 
  geom_point() +
  geom_errorbar(aes(ymin=mean-qt(0.975,df=9)*se,ymax=mean+qt(0.975,df=9)*se))+
  geom_hline(yintercept = fem$DirectChol%>% log2 %>% mean) + 
  ggtitle("20 CI for N=10") + 
  ylim(range(fem$DirectChol %>% log2))


5.3 Reporting?

  • Always report the uncertainty on the results!

  • Conclusions based on a point estimate can be very misleading.

  • Upon a statistical analysis we therefore always report confidence intervals

  • They are small enough to be informative but almost never misleading

  • They form a good trade-off between statistical significance and biological relevance.

  • We conclude that the population parameter lays in the interval and know that this statement holds with a probability of 95% for random samples.

5.3.1 Captopril example

We conclude that the blood pressure decreases on average with 18.9mmHg upon administering captopril (95% CI [-23.9,-13.9]mmHg).

Based on these results it is obvious that the treatment causes a strong blood pressure drop for patients with hypertension.

6 Hypothesis tests

6.1 Captopril Example:

Researchers want to assess if the drug captopril decreases the blood pressure for patients with hypertension.

  • Is there no/an effect of administering captopril on the systolic blood pressure?

  • It is not obvious to draw such conclusions based on a small sample

  • It is uncertain if we can generalized the observations in the sample towards the population!

  • Is the apparent beneficial effect systematic or random?

captoprilTidy %>% 
  filter(type%in%c("SBPa","SBPb")) %>%
  mutate(type=factor(type,levels=c("SBPb","SBPa")))%>%
  ggplot(aes(x=type,y=bp)) +
  geom_line(aes(group = id)) +
  geom_point()

captopril$deltaSBP<-captopril$SBPa-captopril$SBPb
captopril%>%
  ggplot(aes(x="Systolic blood pressure",y=deltaSBP)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter")+
  ylab("Difference (mm mercury)") +
  xlab("")

  • The average blood pressure difference \(\bar X\) is a natural basis to base our decision on.

\[\bar x\text{=-18.93 (s=9.03, SE=2.33)}\]

  • It is not enough that \(\bar{x}< 0\) to conclude that the systolic blood pressure is on average lower upon administrating captopril at the level of the entire population.

  • To generalize the effect we observe in the sample to the population it has to be sufficiently large.

  • But, how large?


6.1.1 Hypothesis tests

  • For this purpose statistical hypothesis tests have been developed
  • They give a black/white answer
  • It is almost impossible to read a scientific publication without results of statistical tests.
  • According to the falsification principle of Popper we can never prove a hypothesis based on data.

    • Hence we will introduce two hypotheses: a null hypothesis \(H_0\) and an alternative hypothesis \(H_1\).

    • We will try to falsify the null hypothesis based on the statistical test.

6.1.1.1 Captopril

  • Based on the sample we cannot prove that there is an effect of administering captopril (\(H_1\) , alternative hypothesis).

  • We therefore suppose that there is no effect of captopril.

    • We refer to this as the null hypothesis \(H_0\).

    • Falsify (“try to reject”) the \(H_0\).

    • How likely is it to observe an effect that is at least as large as what we have seen in the sample in a random sample when \(H_0\) is true?


6.1.1.2 Permutation test

  • Under \(H_0\) the blood pressure measurements before and after administering captopril are two base line blood pressure measurements for a patient

  • Under H\(_0\) we can shuffle (permute) the blood pressure measurements for each patient.

captoprilSamp<-captopril
perm<-sample(c(FALSE,TRUE),15,replace=TRUE)
captoprilSamp$SBPa[perm]<-captopril$SBPb[perm]
captoprilSamp$SBPb[perm]<-captopril$SBPa[perm]
captoprilSamp$deltaSBP <- captoprilSamp$SBPa-captoprilSamp$SBPb
captoprilSamp %>% 
  gather(type,bp,-id) %>%
  filter(type%in%c("SBPa","SBPb")) %>%
  mutate(type=factor(type,levels=c("SBPb","SBPa")))%>%
  ggplot(aes(x=type,y=bp)) +
  geom_line(aes(group = id)) +
  geom_point()

data.frame(deltaSBP=c(captopril$deltaSBP,captoprilSamp$deltaSBP),shuffled=rep(c(FALSE,TRUE),each=15)) %>%
  ggplot(aes(x=shuffled,y=deltaSBP)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter")+
  stat_summary(fun.y=mean, geom="point", shape=19, size=3, color="red", fill="red") +
  ylab("Difference (mm mercury)") 

And we permute again

captoprilSamp<-captopril
perm<-sample(c(FALSE,TRUE),15,replace=TRUE)
captoprilSamp$SBPa[perm]<-captopril$SBPb[perm]
captoprilSamp$SBPb[perm]<-captopril$SBPa[perm]
captoprilSamp$deltaSBP <- captoprilSamp$SBPa-captoprilSamp$SBPb

captoprilSamp %>% 
  gather(type,bp,-id) %>%
  filter(type%in%c("SBPa","SBPb")) %>%
  mutate(type=factor(type,levels=c("SBPb","SBPa")))%>%
  ggplot(aes(x=type,y=bp)) +
  geom_line(aes(group = id)) +
  geom_point()

data.frame(deltaSBP=c(captopril$deltaSBP,captoprilSamp$deltaSBP),shuffled=rep(c(FALSE,TRUE),each=15)) %>%
  ggplot(aes(x=shuffled,y=deltaSBP)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter")+
  stat_summary(fun.y=mean, geom="point", shape=19, size=3, color="red", fill="red") +
  ylab("Difference (mm mercury)") 

  • We will do this 10000 times and we will keep track of the mean.
  • We basically only have to swap the signs of the observed blood pressure differences \(x\) when we shuffle.
#generate a matrix with 15 rows and 10000 columns which consist of -1 and 1
permH<-sample(c(-1,1),150000,replace=TRUE)
dim(permH)<-c(15,10000)

#calculate the means for the permuted data
muPerm<-colMeans(permH*captopril$deltaSBP)
muPerm %>% 
  as.data.frame %>% 
  ggplot(aes(x=.)) +
  geom_histogram() +
  geom_vline(xintercept=mean(captopril$deltaSBP),col="blue")

  • We observe that not one of the means that were obtained under \(H_0\) (by permutation) were as extreme as the sample mean we observed in the captopril study.

  • So the probability to observe a blood pressure drop that is larger then the one in the captopril study in a random sample generated under the null hypothesis is smaller then 1 out of 10000.

So we have strong evidence that \(H_0\) is incorrect and we thus we reject it and conclude \(H_1\): There is an effect of administering captopril on the blood pressure of patients with hypertension.


6.1.2 Pivot

  • In practice we always use statistics that balance the effect size (average difference) to the noise (standard error)

  • When we falsify the null hypothesis, we standardize the mean around \(\mu_0=0\) the mean under \(H_0\)

\[t=\frac{\bar X-\mu_0}{se_{\bar X}}\]

  • for the captopril example this becomes: \[\frac{-18.93-0}{2.33}=-8.12\]

We now determine the null distribution of test statistic t with permutation.

deltaPerms<-permH*captopril$deltaSBP
tPerm<-colMeans(deltaPerms)/(apply(deltaPerms,2,sd)/sqrt(15))
tOrig<-mean(captopril$deltaSBP)/sd(captopril$deltaSBP)*sqrt(15)

tPermPlot<- tPerm %>% 
  as.data.frame %>% ggplot(aes(x=.)) +
  geom_histogram(aes(y=..density.., fill=..count..)) + 
  geom_vline(xintercept=tOrig,col="blue")
tPermPlot

  • Again, none of the permutations gives a t-statistic as extreme as the one observed in the captopril study.

When there is no effect of captopril it is nearly impossible to obtain a test statistic as extreme as the one that was observed ( t=-8.12).

  • The probability to observe a larger blood pressure drop then the one we observed in our sample in a random sample under \(H_0\) is smaller 1/10000.

  • We refer to this probability with the p-value.

  • It measures the strength of the evidence against the null: the smaller the p-value the more evidence we have that the null is not true.

  • The distribution has a nice bell shape.


6.1.3 How do we decide?

When is the p-value sufficiently small to conclude that there is strong evidence against the null hypothesis?

  • We typically work at a significance level of \(\alpha=0.05\)

  • We state that we conducted the test at the 5% significance level


6.1.4 Permutation tests are computationally demanding

  • Can we assess how extreme the blood pressure drop was without permutation?

  • We know that the blood pressure differences are approximately Normally distributed, so

\[t=\frac{\bar X - \mu}{se_{\bar X}}\]

follows a t-distribution (with 14 df for the captopril example).

  • Under H\(_0\) \(\mu=0\) and \[t=\frac{\bar X-0}{se_{\bar X}}\sim f_{T,14}\]
tPermPlot + 
  stat_function(fun=dt,color="red",args=list(df=14))

  • Note, the permutation null distribution indeed corresponds to a t-distribution with 14 degrees of freedom.

  • So we can conduct the statistical test using statistical modelling of the data.

  • We need to make assumptions for this, which we verify in the data exploration phase.


6.2 Hypotheses

Click to see more formal details

Translate the research question to a null hypothesis (\(H_0\)) and an alternative hypothesis (\(H_1\))

First the we need to translate the research question to a parameterized statistical model.

  • From the experimental design it follows that \[X_1,...,X_n \text{ i.i.d } f(X),\] with \(f(X)\) the density function of blood pressure differences.

  • Simplify: assume that \(f(X)\) is known except for an finite dimensional set of parameters \(\mathbf{\theta}\) that still has to be estimated (parametric statistic model).

6.2.1 Captopril example

Click to see more formal details

\(X \sim N(\mu,\sigma^2)\) with \(\mathbf{\theta}=(\mu,\sigma^2)\), the mean \(\mu\) and variance \(\sigma^2\).

The research question is now translated in terms of the average blood pressure drop: \(\mu=E_f[X]\).

The alternative hypothesis is formulated in terms of a parameter of \(f(X)\) and has to express what the researchers want to prove with the study.

  • Here: \[H_1: \mu<0.\] On average the blood pressure of patients with hypertension decreases upon administering captopril.

The null hypothesis generally expresses a null condition, i.e. when notting exceptional happens.

  • Researchers typically aim to prove via empirical research that observing the data under the null is highly unlikely so that they can reject the null hypothesis: Falsification principle.

  • The null hypothesis is typically expressed with the same model parameter as the one used for \(H_1\).

  • Here: \[H_0 : \mu=0\] i.e. on average the systolic blood pressure remains unchanged upon administering captopril.


6.3 Test-statistic

Click to see more formal details

Once the population, the parameters, and, \(H_0\) and \(H_1\) are determined the concept of hypothesis testing is as follows:

Construct a test statistic so that it

  1. measures evidence in the sample,
  2. against the null hypothesis, and
  3. in favour of the alternative hypothesis.

A test statistic thus has to be a function of the observations in the sample.

6.3.1 Captopril example

Click to see more formal details

\[T=\frac{\bar{X}-\mu_0}{\text{SE}_{\bar X}}\] With \(\mu_0=0\) under \(H_0\)

Again

  • If \(H_0\) holds there is no effect of captopril on the blood pressure in the population and then we expect test statistic \(T\) close to 0.

  • If \(H_1\) is true we expect \(T<0\).

  • In the captopril example we observe \(t=(-18.93-0)/2.33=-8.12\).

  • Is \(t = -8.12\) large enough in absolute value to conclude that \(\mu < 0\) and with which confidence can we make this conclusion?

  • We known that t follows a t-distribution with 14 d.f. under \(H_0\)


6.4 p-value

The p-value is the probability to balance between \(H_0\) and \(H_1\).

The way how we calculate it is context dependent

  • For the captopril example we have \[ p = P\left[T \leq t \mid H_0\right] = \text{P}_0\left[T\leq t\right], \] with the index “0” in \(\text{P}_0\left[.\right]\) indicates that the probability is calculated under \(H_0\).

It gives the probability to observe a test statistic \(T\) lower or equal to the value observed in the current sample in a random sample under \(H_0\) - i.e. a test statistic \(T\) in the random sample under \(H_0\) with a value that is more extreme, more in the direction of \(H_1\) then the one observed in the current sample.

6.4.1 Captopril example

Click to see more formal details

  • The \(p\)-value for the captopril example is calculated as follows \[p= \text{P}_0\left[T\leq -8.12\right]=F_t(-8.12;14) = 0.6\ 10^{-6}.\]

with \(F_t(;14)\) the cumulative distribution function of a t-distribution with 14 degrees of freedom:

\[F_t(x;14)=\int\limits_{-\infty}^{x} f_t(x;14).\]

and \(f_t(.;14)\) the density function of the t-distribution.

  • We calculate this probability in R with pt(x,df)

    • the value of the observed test statistic x en
    • the number of degrees of freedom of the t-distribution df.
  • pt(x,df) calculates the probability to observe a value smaller or equal to x when we would draw a random sample from a t-distribution with df degrees of freedom.

n <- length(captopril$deltaSBP)
stat<-(mean(captopril$deltaSBP)-0)/(sd(captopril$deltaSBP)/sqrt(n))
stat
[1] -8.122816
pt(stat,n-1)
[1] 5.731936e-07

In practice we will not calculate the test ourself, but we will use the function t.test:

t.test(captopril$deltaSBP, alternative = "less")

    One Sample t-test

data:  captopril$deltaSBP
t = -8.1228, df = 14, p-value = 5.732e-07
alternative hypothesis: true mean is less than 0
95 percent confidence interval:
      -Inf -14.82793
sample estimates:
mean of x 
-18.93333 

Note, that we need to specify the argument alternative="less" so that the p-value would be calculated in the left tail.

The function also gives a one-sided interval because we test in one direction.


6.4.2 Definition of the p-value

The p-value (also referred to as the observed significance level) is the probability to observe a test statistic in a random sample under the null hypothesis that is as or more extreme then the test statistic observed in the current sample.

  • The smaller the probability the more evidence against \(H_0\).

  • Note, that the p-value is not the probability that null hypothesis is true!

  • The word “extreme” indicates on the direction in which the test statistic is more likely under the alternative hypothesis.

  • In the example \(H_1: \mu < 0\) and we thus expect very negative values for \(t\) under \(H_1\).

  • From the definition small \(p\)-values indicate that observed test statistic is unlikely under the assumption that \(H_0\) is correct.

  • Thus a small value of \(p\)-value means that we have to reject \(H_0\) in favour of \(H_1\).

  • The threshold that we use to compare the \(p\)-value with is referred to as the significance level and is denoted with \(\alpha\).

  • A statistical test conducted on the \(\alpha\) significance level is also referred to as a level-\(\alpha\) test.

A test result is statistically significant if \(p<\alpha\)

  • \(\alpha\) is commonly set at 5%.

  • The smaller the p-value the more `significant’ the test result deviates from what can be expected under \(H_0\).

  • It summarizes the evidence against the null.

\[\begin{array}{cl}>0.10 & \text{ non significant (no evidence)}\\0.05-0.10 & \text{ marginal significant, weak evidence (do not use this yourself)}\\0.01-0.05 & \text{ significant}\\0.001-0.01 & \text{strongly significant}\\<0.001 & \text{ extremely significant}\end{array}\]


6.5 Critical value


6.6 Decision Errors

The decision to accept or reject \(H_0\) is made based on a single sample. A wrong decision could have been made.

Reality
Conclusion H0 H1
Accept H0 OK Type II (\(\beta\))
Reject H0 Type I (\(\alpha\)) OK
  • Type I error, \(\alpha\): wrongly reject the null hypothesis (false positive)
  • Type II error, \(\beta\): wrongly accept the null hypothesis

  • Decision is also stochastic! See first chapter of the course

6.6.1 Captopril Example

  • \(H_0\): administering captopril has no effect on the systolic blood pressure

  • \(H_1\): administering captopril an average leads to a decrease in blood pressure

  • Type I error: there is on average no blood pressure drop upon administering captopril, but we conclude that there is an effect of captopril.
  • Type II error: there is on average a blood pressure drop upon administering captopril, but it is not picked up by the statistical test.


6.6.2 Type I error is controlled

The type I error is controlled by the construction of the statistical test.

\[\text{P}\left[\text{type I error}\right]=\text{P}\left[\text{reject }H_0 \mid H_0\right] = \text{P}_0\left[T<t_{n-1;1-\alpha}\right]=\alpha \]

  • The significance-level \(\alpha\) is the probability to make a type I error.

  • The statistical test ensures that the probability on a type I error is controlled at the significance level \(\alpha\).

  • The probability to correctly accept \(H_0\) is \(1-\alpha\).

  • We can show that the p-value under \(H_0\) is uniform distributed.

  • So statistical hypothesis testing leads to a uniform decision strategy.

We will illustrate this in a simulation study

  • n=15
  • \(\mu=0\) mmHg
  • \(\sigma =9\) mmHg
  • number of simulations 1000
nsim <- 10000
n <- 15
sigma <- 9
mu <- 0
mu0 <- 0
alpha=0.05

#simulate nsim samples of size n
deltaSim <- matrix(rnorm(n*nsim,mu,sigma),nrow=n,ncol=nsim)
pSim <- apply(deltaSim,2,function(x,mu,alternative) t.test(x,mu=mu,alternative=alternative)$p.value,mu=mu0,alternative="less")

mean(pSim<alpha)
[1] 0.0565
pSim %>% 
  as.data.frame %>% 
  ggplot(aes(x=.)) +
  geom_histogram() + 
  xlim(0,1)

  • The type I error is indeed about 0.05
  • The p-values are uniform

6.6.3 Type II error

  • Determine the type II error is less evident.
  • We have to reason under \(H_1\)
  • In the captopril voorbeeld is \(H_1: \mu<0\)
  • Many alternatives are possible
  • The distribution under \(H_1\) is not fully specified

  • work-around: choose one specific distribution under \(H_1\).

\[H_1(\delta): \mu=0-\delta \text{ for }\delta>0.\]

  • e.g. a blood pressure difference of 2 mmHg

  • 1-type II is also referred to as the power. It is the probability to pick up the alternative.

  • It is not guaranteed by the design of the test

  • It depends on the experimental design of the study

nsim <- 10000
n <- 15
sigma <- 9
mu <- -2
mu0 <- 0
alpha=0.05

#simulate nsim samples of size n
deltaSim <- matrix(rnorm(n*nsim,mu,sigma),nrow=n,ncol=nsim)
pSim <- apply(deltaSim,2,function(x,mu,alternative) t.test(x,mu=mu,alternative=alternative)$p.value,mu=mu0,alternative="less")

mean(pSim<alpha)
[1] 0.2079
pSim %>% 
  as.data.frame %>% 
  ggplot(aes(x=.)) +
  geom_histogram() + 
  xlim(0,1)

- We observe that a power of 0.2079 or a type II error of 0.7921.


  • When we increase the sample size
nsim <- 10000
n <- 30
sigma <- 9
mu <- -2
mu0 <- 0
alpha=0.05

#simulate nsim samples of size n
deltaSim <- matrix(rnorm(n*nsim,mu,sigma),nrow=n,ncol=nsim)
pSim <- apply(deltaSim,2,function(x,mu,alternative) t.test(x,mu=mu,alternative=alternative)$p.value,mu=mu0,alternative="less")

mean(pSim<alpha)
[1] 0.3264
pSim %>% 
  as.data.frame %>% 
  ggplot(aes(x=.)) +
  geom_histogram() + 
  xlim(0,1)

  • Increasing the sample size leads to a higher power.
  • Still the power to pick up such a small blood pressure drop remains very low.
  • A drop of 2 mmHg is also not relevant for drug companies.

6.6.4 Interpretation

Suppose that given a particular sample \(p<\alpha\), i.e. reject \(H_0\)

  • Two possibilities

    • correct decision,
    • or type I error.
  • We known that the probability on a type error is low, i.e. \(\alpha=0.05\).

On the other hand, when \(p\geq\alpha\) and we do not reject \(H_0\) we also have two options:

  • Correct decision,
  • or we made a type II error.

The probability on a type II error (\(\beta\)) is not controlled at a specific value.

Statistical test is constructed to only control the probability on a type I error at \(\alpha\).

To be scientifically correct we have to take a pessimistic attitude and we have to admit that \(\beta\) can be large (i.e. a small power to detect the alternative).

Hence,

  • \(p < \alpha\) we reject \(H_0\)

    • We conclude that \(H_1\) is probably correct.
    • We refer to this as a strong conclusion.
  • \(p \geq \alpha\) accept \(H_0\)

    • Does not imply that we accept \(H_0\) correctly.
    • We can only conclude that the data do not have enough evidence against the \(H_0\) in favour of \(H_1\).
    • We refer to this as a weak conclusion.
    • We typically conclude that the effect of the treatment is not significant.

6.7 Conclusions captopril example

The test we have performed is referred to as

  • the one sample t-test on the difference or

  • a paired t-test. Indeed we dispose of paired observations for each patient!

  • The test is done one-sided because we test against the alternative of a blood pressure drop.

  • Both tests (one sample t-test on the difference and paired t-test) give the same results:

t.test(captopril$deltaSBP,alternative="less")

    One Sample t-test

data:  captopril$deltaSBP
t = -8.1228, df = 14, p-value = 5.732e-07
alternative hypothesis: true mean is less than 0
95 percent confidence interval:
      -Inf -14.82793
sample estimates:
mean of x 
-18.93333 
t.test(captopril$SBPa,captopril$SBPb,paired=TRUE,alternative="less")

    Paired t-test

data:  captopril$SBPa and captopril$SBPb
t = -8.1228, df = 14, p-value = 5.732e-07
alternative hypothesis: true difference in means is less than 0
95 percent confidence interval:
      -Inf -14.82793
sample estimates:
mean of the differences 
              -18.93333 

6.7.1 Conclusion

There is on average an extremely significant blood pressure drop upon administering captopril to patients with hypertension. The systolic blood pressure decreases on average with 18.9 mmHg upon the treatment with captopril (95% CI [\(-\infty,-14.82\)] mmHg).

Note that

  1. A one-sided interval is reported because we are only interested in a blood pressure drop.

  2. Because of the pre-test/post-test design we cannot distinguish between the effect of the treatment and a placebo effect. There was no good control! The lack of a good control typically occurs in pre-test/post-test designs. How could we have improved the design?


6.8 One-sided or two-side testing?

De test in the captopril example was a one-sided test. We only aim to detect if the captopril treatment on average reduces the blood pressure.

Suppose that we defined the blood pressure difference as \(X_{i}^\prime=Y_{i}^\text{before}-Y_{i}^\text{after}\)

  • Now, a positive value indicates a blood pressure drop

  • The average change in blood pressure is now denote as \(\mu^\prime=\text{E}[X^\prime]\).

  • So now we should use a one-sided test to assess \(H_0: \mu^\prime=0\) against \(H_1: \mu^\prime>0\).

  • p-value now becomes: \[p=\text{P}_0\left[T\geq t\right].\]


Analysis based on \(X^\prime\): Argument alternative="greater" so that we use \(H_1: \mu^\prime>0\):

t.test(captopril$SBPb-captopril$SBPa,alternative="greater")

    One Sample t-test

data:  captopril$SBPb - captopril$SBPa
t = 8.1228, df = 14, p-value = 5.732e-07
alternative hypothesis: true mean is greater than 0
95 percent confidence interval:
 14.82793      Inf
sample estimates:
mean of x 
 18.93333 

Of course we obtain the same results. Only the sign is swapped.


6.8.1 Two-sided test

Suppose that researchers wanted to assess the mode of action of the new drug captopril in the design phase and suppose that healthy subjects were used in an early phase of the drug development.

In this case it would have been interesting to observe blood pressure drops as well as gains.

Then we would require a two-sided test strategy

\[H_0: \mu=0\] against the alternative hypothesis

\[H_1: \mu\neq0,\]

so that the mean under the alternative is different from zero.

It can be positive as well as negative changes and we did not know upfront in which direction the real mean will deviate from \(H_1\).

We can conduct a two-sided test on the \(\alpha=5\%\) significance level by


The argument alternative of the t.test function is by default alternative="two.sided".

t.test(captopril$deltaSBP)

    One Sample t-test

data:  captopril$deltaSBP
t = -8.1228, df = 14, p-value = 1.146e-06
alternative hypothesis: true mean is not equal to 0
95 percent confidence interval:
 -23.93258 -13.93409
sample estimates:
mean of x 
-18.93333 
  • We still obtain an extremely significant result.
  • The p-value is double as large because we test two-sided.

Indeed

\[p=P_0[T \leq -\vert t \vert] + P_0[T \geq \vert t \vert] = P_0[\vert T \vert \geq \vert t \vert] = 2 \times P_0[T \geq \vert t \vert]\]

  • We also obtain a two-sided confidence interval

6.8.2 One-sided or two-sided test?

With a one-sided test we can more easily reject \(H_0\) on condition that \(H_1\) is true than with a two-sided test.

  • All information is used to test into one direction

  • The decision to test one-sided has to be done in the design phase before the experiment is conducted

  • Even if we have strong a priori presumptions, we are not entirely sure otherwise we would have no reason to do the research.

  • If we propose a one-sided test in the design phase and we observe a result in the opposite direction that would be statistically significant we can not draw conclusions from the experiment.

  • In the design phase we have excluded this result because it is so unexpected that it has to be a false positive.

  • Hence, one-sided tests are not recommended.

A two-sided test can always be defended and allows you to detect any deviation of \(H_0\) and is highly recommended.

It is never allowed to change a two-sided test into a one-sided test based on what has been observed in the sample! Otherwise the type I error of the test strategy is not correctly controlled.


We illustrate this in the simulation study below:

  1. correct two-sided test and
  2. one-sided test with its sign based on what was observed in the sample.
mu <- 0
sigma <- 9.0
nSim <- 1000
alpha <- 0.05
n <- 15
pvalsCor <- pvalsInCor<-array(0,nSim)
for (i in 1:nSim)
{
    x <- rnorm(n,mean=mu,sd=sigma)
    pvalsCor[i] <- t.test(x)$p.value
    if (mean(x)<0)
        pvalsInCor[i] <- t.test(x,alternative="less")$p.value else
        pvalsInCor[i] <- t.test(x,alternative="greater")$p.value
}

mean(pvalsCor<0.05)
[1] 0.043
mean(pvalsInCor<0.05)
[1] 0.098
  • Type I error correctly controlled at \(\alpha\) for two-sided test.
  • Type I error not correctly controlled when we test one-sided based on what we observed in the sample.

7 Nature column on testing


LS0tCnRpdGxlOiAiNS4gU3RhdGlzdGljYWwgSW5mZXJlbmNlIiAKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCm91dHB1dDoKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgICAgCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICB0b2M6IHRydWUKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKYGBge3IgaW5jbHVkZT1GQUxTRX0KI0RvIG5vdCBydW4gZHVyaW5nIHRoZSBsZWN0dXJlIHdoZW4gd2Ugd29yayBpbnRlcmFjdGl2ZWx5CnNldC5zZWVkKDEzMTQpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KIyMgUG9wdWxhdGlvbgoKLSBUaGUgYWltIG9mIGEgc2NpZW50aWZpYyBzdHVkeSBpcyB0byBkcmF3IGNvbmNsdXNpb25zIG9uIHRoZSBnZW5lcmFsIHBvcHVsYXRpb24uIAoKLSBIZXJlLCB3ZSBzdHVkeSB0aGUgZWZmZWN0IG9mIGNhcHRvcHJpbCBvbiB0aGUgYmxvb2QgcHJlc3N1cmUgb2YgcGF0aWVudHMgd2l0aCBoeXBlcnRlbnNpb24uIAoKLSBXZSB3aWxsIGNvbGxlY3QgZGF0YSBhbmQgd2Ugd2lsbCBtb2RlbCB0aGUgZGF0YQoKLSBUaGVyZWZvcmUsIHdlIGFsd2F5cyBoYXZlIHRvIHRyYW5zbGF0ZSB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gd2l0aCByZXNwZWN0IHRvIG1vZGVsIHBhcmFtZXRlciBvciBhIGNvbWJpbmF0aW9uIG9mIG1vZGVsIHBhcmFtZXRlcnMuIAoKLSBlLmcuIHRoZSBwb3B1bGF0aW9uIG1lYW4KICAgJCRFKFgpPVxtdSQkCgotIERvZXMgdGhlIGJsb29kIHByZXNzdXJlIGRlY3JlYXNlcyBvbiBhdmVyYWdlIGFmdGVyIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsIHRvIHBhdGllbnRzIHdpdGggaHlwZXJ0ZW5zaW9uPyAgIAoKLS0tCgojIyBPdmVydmlldyAKCi0gRXhwZXJpbWVudGFsIERlc2lnbiAmIERhdGEgRXhwbG9yYXRpb24KLSBQb2ludCBlc3RpbWF0b3JzIChFc3RpbWF0aW9uKQotIEludGVydmFsIGVzdGltYXRvcnMgKFN0YXRpc3RpY2FsIGluZmVyZW5jZSkKLSBIeXBvdGhlc2lzIHRlc3RzIChTdGF0aXN0aWNhbCBpbmZlcmVuY2UpCgotLS0KCiMgRXhwZXJpbWVudGFsIERlc2lnbgoKLSAxNSBwYXRpZW50cyB3ZXJlIGRyYXduIGF0IHJhbmRvbSBmcm9tIHRoZSBwb3B1bGF0aW9uIG9mIHBhdGllbnRzIHdpdGggaHlwZXJ0ZW5zaW9uCi0gcHJlLXRlc3QvcG9zdC10ZXN0IGRlc2lnbjogdGhlIHN5c3RvbGljIGFuZCBkaWFzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBhcmUgbWVhc3VyZWQgYmVmb3JlIGFuZCBhZnRlciBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbAotIEFkdmFudGFnZTogd2UgY2FuIGFzc2VzcyB0aGUgZWZmZWN0IG9mIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsIG9uIHRoZSBibG9vZCBwcmVzc3VyZSBmb3IgZWFjaCBpbmRpdmlkdWFsIHBhdGllbnQuCi0gRGlzYWR2YW50YWdlPyAKCmBgYHtyIHBvcDJTYW1wMlBvcCxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIlaW4lbHMoKSkgcm0oInBpIikKa29wdm9ldGVyPC1mdW5jdGlvbih4LHksYW5nbGU9MCxsPS4yLGNleC5kb3Q9LjUscGNoPTE5LGNvbD0iYmxhY2siKQp7CmFuZ2xlPWFuZ2xlLzE4MCpwaQpwb2ludHMoeCx5LGNleD1jZXguZG90LHBjaD1wY2gsY29sPWNvbCkKbGluZXMoYyh4LHgrbCpjb3MoLXBpLzIrYW5nbGUpKSxjKHkseStsKnNpbigtcGkvMithbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MoYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKGFuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhwaSthbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4ocGkrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzIrcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMitwaS80K2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yLXBpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzItcGkvNCthbmdsZSkpLGNvbD1jb2wpCn0KCnBhcihtYXI9YygwLDAsMCwwKSxtYWk9YygwLDAsMCwwKSkKcGxvdCgwLDAseGxhYj0iIix5bGFiPSIiLHhsaW09YygwLDEwKSx5bGltPWMoMCwxMCksY29sPTAseGF4dD0ibm9uZSIseWF4dD0ibm9uZSIsYXhlcz1GQUxTRSkKcmVjdCgwLDYsMTAsMTAsYm9yZGVyPSJyZWQiLGx3ZD0yKQp0ZXh0KC41LDgsInBvcHVsYXRpb24iLHNydD05MCxjb2w9InJlZCIsY2V4PTIpCnN5bWJvbHMgKDMsIDgsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9InJlZCIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpncmlkPXNlcSgwLDEuMywuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewoJYW5nbGUxPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJYW5nbGUyPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJcmFkaXVzPXNhbXBsZShncmlkLHByb2I9Z3JpZF4yKnBpL3N1bShncmlkXjIqcGkpLHNpemU9MSkKCWtvcHZvZXRlcigzK3JhZGl1cypjb3MoYW5nbGUxLzE4MCpwaSksOCtyYWRpdXMqc2luKGFuZ2xlMS8xODAqcGkpLGFuZ2xlPWFuZ2xlMikKfQp0ZXh0KDcuNSw4LCJFZmZlY3Qgb2YgY2FwdG9wcmlsIGluIHBvcHVsYXRpb24iLGNvbD0icmVkIixjZXg9MS4yKQoKcmVjdCgwLDAsMTAsNCxib3JkZXI9ImJsdWUiLGx3ZD0yKQp0ZXh0KC41LDIsInNhbXBsZSIsc3J0PTkwLGNvbD0iYmx1ZSIsY2V4PTIpCnN5bWJvbHMgKDMsIDIsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9ImJsdWUiLGluY2hlcz1GQUxTRSxsd2Q9MikKZm9yIChpIGluIDA6MikKCWZvciAoaiBpbiAwOjQpCnsKCglrb3B2b2V0ZXIoMi4xK2oqKDMuOS0yLjEpLzQsMS4xK2kpCn0KdGV4dCg3LjUsMiwiRWZmZWN0IG9mIGNhcHRvcHJpbCBpbiBzYW1wbGUiLGNvbD0iYmx1ZSIsY2V4PTEuMikKCmFycm93cygzLDUuOSwzLDQuMSxjb2w9ImJsYWNrIixsd2Q9MykKYXJyb3dzKDcsNC4xLDcsNS45LGNvbD0iYmxhY2siLGx3ZD0zKQp0ZXh0KDEuNSw1LCJFWFAuIERFU0lHTiAoMSkiLGNvbD0iYmxhY2siLGNleD0xLjIpCnRleHQoOC41LDUsIkVTVElNQVRJT04gJlxuSU5GRVJFTkNFICgzKSIsY29sPSJibGFjayIsY2V4PTEuMikKdGV4dCg3LjUsLjUsIkRBVEEgRVhQTE9SQVRJT04gJlxuREVTQ1JJUFRJVkUgU1RBVElTVElDUyAoMikiLGNvbD0iYmxhY2siLGNleD0xLjIpCmBgYAoKLS0tCgojIERhdGEgZXhwbG9yYXRpb24gYW5kIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MgCgpgYGB7cn0KY2FwdG9wcmlsIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvY2FwdG9wcmlsLnR4dCIpCmhlYWQoY2FwdG9wcmlsKQpzdW1tYXJ5KGNhcHRvcHJpbCkKYGBgCgpgYGB7cn0KY2FwdG9wcmlsVGlkeSA8LSBjYXB0b3ByaWwgJT4lIGdhdGhlcih0eXBlLGJwLC1pZCkgCmNhcHRvcHJpbFRpZHkgJT4lIAogIGdyb3VwX2J5KHR5cGUpICU+JQogIHN1bW1hcml6ZV9hdCgiYnAiLGxpc3QobWVhbj1+bWVhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIHNkPX5zZCguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG49ZnVuY3Rpb24oeCkgeCU+JWlzLm5hJT4lYCFgJT4lc3VtKSkgJT4lCiAgbXV0YXRlKHNlPXNkL3NxcnQobikpIAoKY2FwdG9wcmlsVGlkeSAlPiUgCiAgZ3JvdXBfYnkodHlwZSkgJT4lCiAgc3VtbWFyaXplX2F0KCJicCIsbGlzdChtZWFuPX5tZWFuKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgc2Q9fnNkKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgbj1mdW5jdGlvbih4KSB4JT4laXMubmElPiVgIWAlPiVzdW0pKSAlPiUKICBtdXRhdGUoc2U9c2Qvc3FydChuKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXR5cGUseT1tZWFuKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2UsIHltYXg9bWVhbitzZSksd2lkdGg9LjIpICsKICB5bGltKDAsMjEwKSArCiAgeWxhYigiYmxvb2QgcHJlc3N1cmUgKG1tSGcpIikKYGBgCgotIFRoaXMgZmlndXJlIGlzIG5vdCBpbmZvcm1hdGl2ZSEgSXQgZG9lcyBub3Qgc2hvdyB0aGUgcmF3IGRhdGEuIAoKYGBge3J9CmNhcHRvcHJpbFRpZHkgJT4lIAogIGdncGxvdChhZXMoeD10eXBlLHk9YnApKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGU9TkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKSArIAogIHlsaW0oMCwyMTApCmBgYAoKV2Ugc2VlIHRoYXQgYSBsb3Qgb2YgdGhlIHNwYWNlIHRoYXQgd2FzIHRha2VuIGJ5IHRoZSBiYXJwbG90IGRvZXMgbm90IGNvbnRhaW4gZGF0YSEKCmBgYHtyfQpjYXB0b3ByaWxUaWR5ICU+JSAKICBnZ3Bsb3QoYWVzKHg9dHlwZSx5PWJwKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikgCmBgYAoKLSBUaGlzIHBsb3Qgd291bGQgaGF2ZSBiZWVuIGluZm9ybWF0aXZlIGlmIHRoZSBkYXRhIHdhcyBnYXRoZXJlZCBvbiBkaWZmZXJlbnQgaW5kaXZpZHVhbHMuIAoKLSBIb3dldmVyLCB0aGUgYmxvb2QgcHJlc3N1cmVzIGFyZSBtZWFzdXJlZCBvcCB0aGUgc2FtZSBzdWJqZWN0IQoKLSBXZSB3aWxsIG1ha2UgYSBwbG90IGJ5IGZpbHRlcmluZyB0aGUgc3lzdG9saWMgYmxvb2QgcHJlc3N1cmVzCgpgYGB7cn0KY2FwdG9wcmlsVGlkeSAlPiUKICBmaWx0ZXIodHlwZSVpbiVjKCJTQlBhIiwiU0JQYiIpKSAlPiUKICBtdXRhdGUodHlwZT1mYWN0b3IodHlwZSxsZXZlbHM9YygiU0JQYiIsIlNCUGEiKSkpICU+JQogIGdncGxvdChhZXMoeD10eXBlLHk9YnApKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGlkKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCi0gV2UgaGF2ZSBwYWlyZWQgZGF0YS4gU28gd2UgbWlnaHQgZXN0aW1hdGUgdGhlIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50IGRpcmVjdGx5IGJ5IGNvbXBhcmluZyB0aGUgYmxvb2QgcHJlc3N1cmUgYWZ0ZXIgdHJlYXRtZW50IHRvIHRoZSBibG9vZCBwcmVzc3VyZSBiZWZvcmUgdGhlIHRyZWF0bWVudC4gCgpgYGB7cn0KY2FwdG9wcmlsJGRlbHRhU0JQPC1jYXB0b3ByaWwkU0JQYS1jYXB0b3ByaWwkU0JQYgpjYXB0b3ByaWwlPiUKICBnZ3Bsb3QoYWVzKHg9IlN5c3RvbGljIGJsb29kIHByZXNzdXJlIix5PWRlbHRhU0JQKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArIAogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpKwogIHlsYWIoIkRpZmZlcmVuY2UgKG1tIG1lcmN1cnkpIikgKwogIHhsYWIoIiIpCmBgYAoKYGBge3J9CmNhcHRvcHJpbCAlPiUKICBzdW1tYXJpemVfYXQoImRlbHRhU0JQIixsaXN0KG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKQpgYGAKCgotIFByZS10ZXN0L3Bvc3QtdGVzdCBkZXNpZ246IEVmZmVjdCBvZiBjYXB0b3ByaWwgaW4gc2FtcGxlIHVzaW5nICAkWD1cRGVsdGFfXHRleHR7YWZ0ZXItYmVmb3JlfSQhCgotIEhvdyB3aWxsIHdlIG1vZGVsICRYPVxEZWx0YV9cdGV4dHthZnRlci1uYX0kIGFuZCBlc3RpbWF0ZSB0aGUgZWZmZWN0IG9mIGNhcHRvcHJpbD8gCgpgYGB7cn0KY2FwdG9wcmlsJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGU9ZGVsdGFTQlApKSArCiAgc3RhdF9xcSgpICsKICBzdGF0X3FxX2xpbmUoKQpgYGAKClRoZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlcyBhcmUgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4gCgotLS0KCiMgRXN0aW1hdGlvbgoKCi0gTm8gc3Vic3RhbnRpYWwgZGV2aWF0aW9ucyBmcm9tIG5vcm1hbGl0eQoKLSBXZSBjYW4gYXNzdW1lIHRoYXQgdGhlIGRpZmZlcmVuY2VzICAkWCBcc2ltIE4oXG11LCBcc2lnbWFeMikkLgoKLSBFZmZlY3Qgb2YgY2FwdG9wcmlsIGluIHRoZSBwb3B1bGF0aW9uIGlzIGNhcHR1cmVkIGJ5IHRoZSBhdmVyYWdlIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2UgJFxtdSQuCgotIFRoZSBhdmVyYWdlIGJsb29kIHByZXNzdXJlICRcbXUkIGluIHRoZSBwb3B1bGF0aW9uIGNhbiBiZSBlc3RpbWF0ZWQgdXNpbmcgdGhlIHNhbXBsZSBtZWFuICRcYmFyIHgkPWByIHJvdW5kKG1lYW4oY2FwdG9wcmlsJGRlbHRhU0JQKSwyKWAKCi0gVGhlIHN0YW5kYXJkIGRldmlhdGlvbiAkXHNpZ21hJCB3aXRoIHRoZSBzYW1wbGUgc3RhbmRhcmQgZGV2aWF0aW9uICRcdGV4dHtTfSQ9YHIgcm91bmQoc2QoY2FwdG9wcmlsJGRlbHRhU0JQKSwyKWAuCgotIElzIHRoZSBlZmZlY3QgdGhhdCB3ZSBvYnNlcnZlIGluIHRoZSBzYW1wbGUgbGFyZ2UgZW5vdWdoIHRvIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgYW4gZWZmZWN0IG9mIHRoZSBjYXB0b3ByaWwgdHJlYXRtZW50IG9uIHRoZSBibG9vZCBwcmVzc3VyZSBhdCBwb3B1bGF0aW9uIGxldmVsPyAKCi0gT3VyIGVzdGltYXRlcyB3aWxsIGNoYW5nZSBmcm9tIHNhbXBsZSB0byBzYW1wbGUhCgotIEhvdyBhcmUgdGhlIGVzdGltYXRvcnMgJFxiYXIgWCQgYW5kICRTJCBkaXN0cmlidXRlZD8gCgoKIyMgUG9pbnQgZXN0aW1hdG9yIHRoZSBzYW1wbGUgbWVhbgoKLSBTdXBwb3NlIHRoYXQgJFgkIGlzIGEgcmFuZG9tIHNhbXBsZSBmcm9tIHRoZSBwb3B1bGF0aW9uIGFuZCBhc3N1bWUgdGhhdCAkWCBcc2ltIE4oXG11LFxzaWdtYV4yKSQKCi0gRXN0aW1hdGUgJFxtdSQgYmFzZWQgb24gc2FtcGxlICRYXzEsLi4uLFhfbiQsIHVzaW5nIHRoZSBzYW1wbGUgbWVhbiAKICAkJFxiYXIgWCA9IFxmcmFje1hfMSsgWF8yKyAuLi4gKyBYX259e259ID0gXGZyYWN7XHN1bV97aT0xfV57bn0gWF9pfXtufSQkIG9mIHJhbmRvbSB2YXJpYWJsZXMgJFhfMSxYXzIsIC4uLiwgWF9uJC4KCi0gU2FtcGxlIG1lYW4gJFxiYXIgWCQgaXMgYSByYW5kb20gdmFyaWFibGUgdGhhdCB2YXJpZXMgZnJvbSBzYW1wbGUgdG8gc2FtcGxlIAoKLSBTdHVkeSB0aGUgdGhlb3JldGljYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbiB0byBnZXQgaW5zaWdodCAKICAgIAogICAgMS4gaW4gaG93IHRoZSBzYW1wbGUgbWVhbiBjYW4gdmFyeSBpbiBhIG5ldyBzaW1pbGFyIHN0dWR5CiAgICAyLiBob3cgZmFyICRcYmFyIFgkIGNhbiBiZSBmcm9tIHRoZSBwb3B1bGF0aW9uIG1lYW4gJFxtdSQKCi0tLQoKIyMjIE92ZXJ2aWV3CgoxLiBUaGUgc2FtcGxlIG1lYW4gaXMgdW5iaWFzZWQgCjIuIFByZWNpc2lvbiBvZiBzYW1wbGUgbWVhbiAKMy4gRGlzdHJpYnV0aW9uIG9mIHNhbXBsZSBtZWFuCgotLS0KCiMjIyBUaGUgc2FtcGxlIG1lYW4gaXMgdW5iaWFzZWQgCgotIFdlIGNhbiBnZW5lcmFsaXplIG91ciBvYnNlcnZhdGlvbnMgYmFzZWQgb24gdGhlIHNhbXBsZSB0b3dhcmRzIHRoZSBwb3B1bGF0aW9uIGlmIHRoZSBlc3RpbWF0ZSBpcyBnb29kIGFwcHJveGltYXRpb24gb2YgdGhlIHBvcHVsYXRpb24gdmFsdWUuIAoKLSBBIHJlcHJlc2VudGF0aXZlIHNhbXBsZSBpcyByZXF1aXJlZCB0byBnZW5lcmFsaXplIHRoZSByZXN1bHRzIGZyb20gdGhlIHNhbXBsZSB0b3dhcmRzIHRoZSBwb3B1bGF0aW9uCgotIEF2b2lkIGJpYXMgKHNvIHRoYXQgdGhlIHBvcHVsYXRpb24gbWVhbiBpcyBub3Qgc3lzdGVtYXRpY2FsbHkgdW5kZXIgb3Igb3ZlcmVzdGltYXRlZCkgCgotIFJlcG9ydCBob3cgdGhlIHNhbXBsZSBpcyB0YWtlbiEgCgotIFJhbmRvbWlzYXRpb24hCgotIERyYXcgdGhlIHN1YmplY3RzIGF0IHJhbmRvbSBmcm9tIHBvcHVsYXRpb24gc28gZXZlcnkgc3ViamVjdCBoYXMgdGhlIHNhbWUgcHJvYmFiaWxpdHkgdG8gZW5kIHVwIGluIHRoZSBzYW1wbGUuICAKCi0gU3ViamVjdHMgd2l0aCBoeXBlcnRlbnNpb24gYXJlIHNhbXBsZWQgYXQgcmFuZG9tIGZyb20gdGhlIHBvcHVsYXRpb24KCgotIFNpbXBsZSByYW5kb20gc2FtcGxlOiAgJFhfMSwuLi4sWF9uJCBmb3IgY2hhcmFjdGVyaXN0aWMgJFgkCgotICRYXzEsLi4uLFhfbiQgaGF2ZSBzYW1lIGRpc3RyaWJ1dGlvbgotIFRoZXkgaGF2ZSBzYW1lIG1lYW4gJFxtdSQgYW5kIHZhcmlhbmNlICRcc2lnbWFeMiQKCi0gJEUoWF8xKT0uLi49RShYX24pPVxtdSQgYW5kICRcdGV4dHtWYXJ9KFhfMSk9Li4uPVx0ZXh0e1Zhcn0oWF9uKT1cc2lnbWFeMiQKCi0gJFxiYXIgWCQgaXMgYW4gKnVuYmlhc2VkIGVzdGltYXRvciogZm9yICRcbXUkIAoKPGRldGFpbHM+PHN1bW1hcnk+Q2xpY2sgdG8gc2VlIHByb29mPC9zdW1tYXJ5PjxwPgpcYmVnaW57ZXFuYXJyYXkqfQpFKFxiYXIgWCkgJj0mIEUgXGxlZnQoXGZyYWN7WF8xKyBYXzIrIC4uLiArIFhfbn17bn1ccmlnaHQpIFxcCiY9ICYgXGZyYWN7RShYXzEpKyBFKFhfMikrIC4uLiArIEUoWF9uKX17bn0gXFwKJj0mIFxmcmFje1xtdSArIFxtdSArIC4uLiArXG11fXtufSBcXAomPSAmIFxtdQpcZW5ke2VxbmFycmF5Kn0KPC9wPjwvZGV0YWlscz4KCi0tLQoKIyMjIEltcHJlY2lzaW9uL3N0YW5kYXJkIGVycm9yCgotIEFsc28gZm9yIHJlcHJlc2VudGF0aXZlIHNhbXBsZXMgdGhlIHJlc3VsdHMgYXJlIGltcHJlY2lzZS4gClx2c3BhY2V7MTBwdH0KLSBEaWZmZXJlbnQgc2FtcGxlcyBmcm9tIHRoZSBzYW1lIHBvcHVsYXRpb24gZ2l2ZSBkaWZmZXJlbnQgcmVzdWx0cy4KCi0gV2UgaWxsdXN0cmF0ZWQgdGhpcyBieSB1c2luZyB0aGUgTkhBTkVTIAoKICAgIC0gV2Ugd2lsbCBkcmF3IDE1IGZlbWFsZXMgYXQgcmFuZG9tIGZyb20gdGhlIE5IQU5FUyBzdHVkeSBhbmQgd2Ugd2lsbCByZWdpc3RlciB0aGVpciBsb2cyIGRpcmVjdCBjaG9sZXN0ZXJvbCB2YWx1ZXMKICAgIC0gV2UgcmVwZWF0IHRoaXMgNTAgdGltZXMgdG8gYXNzZXNzIHRoZSB2YXJpYXRpb24gZnJvbSBzYW1wbGUgdG8gc2FtcGxlCiAgICAtIFdlIHdpbGwgcGxvdCB0aGUgYm94cGxvdCBmb3IgZWFjaCBzYW1wbGUgYW5kIHdpbGwgaW5kaWNhdGUgdGhlIG1lYW4gCgpgYGB7cn0KbGlicmFyeShOSEFORVMpCgpmZW0gPC0gTkhBTkVTICU+JSAKICBmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIiAmICFpcy5uYShEaXJlY3RDaG9sKSkgJT4lCiAgc2VsZWN0KCJEaXJlY3RDaG9sIikKCm48LTE1ICMgbnVtYmVyIG9mIHN1YmplY3RzIHBlciBzYW1wbGUKblNpbT01MCAjIG51bWJlciBvZiBzaW11bGF0aW9ucwoKZmVtU2FtcDwtbWF0cml4KG5yb3c9bixuY29sPW5TaW0pCmZvciAoaiBpbiAxOm5TaW0pCnsKICBmZW1TYW1wWyxqXTwtc2FtcGxlKGZlbSREaXJlY3RDaG9sLDE1KQogIGlmIChqPDQpIHsKICAgIHAgPC0gZmVtU2FtcCAlPiUgCiAgICAgIGxvZzIgJT4lCiAgICAgIGRhdGEuZnJhbWUgJT4lIAogICAgICBnYXRoZXIoInNhbXBsZSIsImxvZzJjaG9sZXN0ZXJvbCIpICU+JQogICAgICBnZ3Bsb3QoYWVzKHg9c2FtcGxlLHk9bG9nMmNob2xlc3Rlcm9sKSkgKwogICAgICBnZW9tX2JveHBsb3QoKSArIAogICAgICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0xOSwgc2l6ZT0zLCBjb2xvcj0icmVkIiwgZmlsbD0icmVkIikgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKGZlbSREaXJlY3RDaG9sICU+JSBsb2cyKSkgKwogICAgICB5bGFiKCJjaG9sZXN0ZXJvbCAobG9nMikiKSAKICAgIHByaW50KHApCiAgfQp9CgpmZW1TYW1wICU+JSAKICBsb2cyICU+JSAKICBkYXRhLmZyYW1lICU+JSAKICBnYXRoZXIoInNhbXBsZSIsImxvZzJjaG9sZXN0ZXJvbCIpICU+JQogIGdncGxvdChhZXMoeD1zYW1wbGUseT1sb2cyY2hvbGVzdGVyb2wpKSArCiAgZ2VvbV9ib3hwbG90KCkgKyAKICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0xOSwgc2l6ZT0zLCBjb2xvcj0icmVkIiwgZmlsbD0icmVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lYW4oZmVtJERpcmVjdENob2wgJT4lIGxvZzIpKSArCiAgeWxhYigiY2hvbGVzdGVyb2wgKGxvZzIpIikKYGBgCgpXZSBvYnNlcnZlIHRoYXQgdGhlIG1lYW4gbmljZWx5IGZsdWN0dWF0ZXMgYXJvdW5kIHRoZSBwb3B1bGF0aW9uIG1lYW4uIAoKQ29weSB0aGUgY29kZSwgaW5jcmVhc2UgdGhlIHNhbXBsZSBzaXplIHRvIDEwMCBzdWJqZWN0cyBhbmQgb2JzZXJ2ZSB3aGF0IGhhcHBlbnMhCgotLS0KCiMjIyBIb3cgdG8gZG8gdGhpcyBiYXNlZCBvbiBhIHNpbmdsZSBzYW1wbGU/CgotIEluc2lnaHQgaW4gaG93IGNsb3NlIHdlIGNhbiBleHBlY3QgJFxiYXIgWCQgdG8gJFxtdSQ/CgotIEhvdyB2YXJpZXMgJFxiYXIgWCQgZnJvbSBzYW1wbGUgdG8gc2FtcGxlPyAKCi0gVmFyaWFiaWxpdHkgb24gJFxiYXIgWCQKCi0gV2UgaGF2ZSB0byBkZXRlcm1pbmUgdGhpcyBiYXNlZCBvbiBhIHNpbmdsZSBzYW1wbGUhCgotIFdlIG5lZWQgdG8gbWFrZSBhc3N1bXB0aW9ucyAKCi0gV2UgYXNzdW1lIHRoYXQgdGhlIHJhbmRvbSB2YXJpYWJsZXMgJFhfMSwgWF8yLCAuLi4sIFhfbiQgb3JpZ2luYXRlIGZyb20gJG4kICppbmRlcGVuZGVudCogc3ViamVjdHMuIAoKLSBGb3IgdGhlIGNhcHRvcHJpbCBzdHVkeSB3ZSBoYWQgZGVwZW5kZW50IG9ic2VydmF0aW9ucy4gCiAgICAKICAgIC0gQmxvb2QgcHJlc3N1cmUgbWVhc3VyZW1lbnRzIGJlZm9yZSAoJFlfe2ksYmVmb3JlfSQpIGFuZCAgYWZ0ZXIgKCRZX3tpLGFmdGVyfSQpIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsIGZvciB0aGUgc2FtZSBzdWJqZWN0ICRpPTEsXGxkb3RzLG4kLgogICAgLSBXZSB0dXJuZWQgdGhlbSBpbnRvIG4gaW5kZXBlbmRlbnQgbWVhc3VyZW1lbnRzIGJ5IHRha2luZyB0aGUgZGlmZmVyZW5jZSAkWV97aSxhZnRlcn0tWV97aSxiZWZvcmV9JAoKLS0tCgojIyMgVmFyaWFuY2UgZXN0aW1hdG9yIGZvciAkXGJhciBYJAoKJCRcc2lnbWFeMl97XGJhciBYfT1cZnJhY3tcc2lnbWFeMn17bn0kJAoKLSBUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mICRcYmFyIFgkIGFyb3VuZCAkXG11JCBpcyAkXHNxcnR7bn0kIHRpbWVzIHNtYWxsZXIgdGhhdCB0aGUgZGV2aWF0aW9uIGFyb3VuZCB0aGUgb3JpZ2luYWwgb2JzZXJ2YXRpb25zICRYJC4KCi0gVGhlIG1vcmUgb2JzZXJ2YXRpb25zIHdlIGhhdmUgdGhlIG1vcmUgcHJlY2lzZSAkXGJhciBYJC4KCgo8ZGV0YWlscz48c3VtbWFyeT5DbGljayB0byBzZWUgcHJvb2Y8L3N1bW1hcnk+PHA+ClxiZWdpbntlcW5hcnJheSp9Clx0ZXh0e1Zhcn0oXGJhciBYKSY9Jlx0ZXh0e1Zhcn0gXGxlZnQoXGZyYWN7WF8xKyBYXzIrIC4uLiArIFhfbn17bn1ccmlnaHQpIFxcCiY9ICYgXGZyYWN7XHRleHR7VmFyfSAoWF8xKyBYXzIrIC4uLiArIFhfbil9e25eMn0gXFwKJlxvdmVyc2V0eyp9ez19ICYgXGZyYWN7XHRleHR7VmFyfShYXzEpKyBcdGV4dHtWYXJ9KFhfMikrIC4uLiArIFx0ZXh0e1Zhcn0oWF9uKX17bl4yfSBcXAomPSYgXGZyYWN7XHNpZ21hXjIgKyBcc2lnbWFeMiArIC4uLiBcc2lnbWFeMn17bl4yfSBcXAomPSAmIFxmcmFje1xzaWdtYV4yfXtufS4KXGVuZHtlcW5hcnJheSp9CgotICgqKSB0aGlzIGlzIGJhc2VkIG9uIHRoZSBhc3N1bXB0aW9uIG9mIGluZGVwZW5kZW5jZS4gCiQkXHRleHR7VmFyfVtYXzEgKyBYXzJdID0gXHRleHR7VmFyfVtYXzFdICsgXHRleHR7VmFyfVtYXzJdICsgMiBcdGV4dHtDb3Zhcn1bWF8xLFhfMl0kJAoKICAgIC0gV2l0aCAkQ292YXJbWF8xLFhfMl09MCQgd2hlbiAkWF8xJCBhbmQgJFhfMiQgYXJlIGluZGVwZW5kZW50LiAKPC9wPjwvZGV0YWlscz4KCioqRGVmaW5pdGlvbjogc3RhbmRhcmQgZXJyb3IqKgoKVGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAkXGJhcntYfSQgaXMgJFxzaWdtYS9cc3FydHtufSQgYW5kIGlzIGFsc28gcmVmZXJyZWQgdG8gYXMgdGhlICoqc3RhbmRhcmQgZXJyb3IqKiBvZiB0aGUgbWVhbi4gCkdlbmVyYWxseSBvbmUgcmVmZXJzIHRvIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYW4gZXN0aW1hdG9yIGZvciBhIHBhcnRpY3VsYXIgcGFyYW1ldGVyICRcdGhldGEkIHdpdGggdGhlIHRlcm0gKipzdGFuZGFyZCBlcnJvcioqIG9mIHRoZSBlc3RpbWF0b3IsIHdoaWNoIGlzIGRlbm90ZWQgYXMgJFNFJC4KCi0tLQoKIyMjIENhcHRvcHJpbCBleGFtcGxlIAoKCi0gJG4gPSAxNSQgZGlmZmVyZW5jZXMgaW4gc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUKCi0gU3VwcG9zZSB0aGF0IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2VzIGluIHRoZSBwb3B1bGF0aW9uIGlzICRcc2lnbWEgPSA5LjAkIG1tSGcKCi0gVGhlbiwgdGhlIHN0YW5kYXJkIGVycm9yIChTRSkgb24gdGhlIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUgZGlmZmVycyAkXGJhciBYJCBiZWNvbWVzOgoKJCQKU0U9IFxmcmFjezkuMH17XHNxcnR7MTV9fT0yLjMyXHRleHR7bW1IZy59CiQkCgotIEdlbmVyYWxseSAkXHNpZ21hJCwgYW5kIHRodXMgdGhlIFNFIG9uIHRoZSBzYW1wbGUgbWVhbiBhcmUgdW5rbm93bi4gCi0gU28gd2UgYWxzbyBoYXZlIHRvIGVzdGltYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHNhbXBsZSB0byBvYnRhaW4gdGhlIHN0YW5kYXJkIGVycm9yCi0gRXN0aW1hdG9yOiAkU0U9Uy9cc3FydHtufSwkCi0gd2l0aCAkU14yJCB0aGUgc2FtcGxlIHZhcmlhbmNlIG9mICRYXzEsLi4uLFhfbiQgIGFuZCAkUyQgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb24gCgotIEZvciB0aGUgY2FwdG9wcmlsIGV4YW1wbGUgd2Ugb2J0YWluOgoKYGBge3J9Cm49bGVuZ3RoKGNhcHRvcHJpbCRkZWx0YVNCUCkKc2U9c2QoY2FwdG9wcmlsJGRlbHRhU0JQKS9zcXJ0KG4pCnNlCmBgYAoKLS0tCgojIyMgc3RhbmRhcmQgZGV2aWF0aW9uIHZzIHN0YW5kYXJkIGVycm9yCgojIyMjIElsbHVzdHJhdGUgdmlhIHJlcGVhdGVkIHNhbXBsaW5nCgotIERpZmZlcmVudCBzYW1wbGUgc2l6ZXM6IDEwLCA1MCwgMTAwCi0gRHJhdyAxMDAwIHNhbXBsZXMgcGVyIHNhbXBsZSBzaXplIGZyb20gdGhlIE5IQU5FUyBzdHVkeSwgZm9yIGVhY2ggc2FtcGxlIHdlIGNhbGN1bGF0ZQogICAgLSBUaGUgbWVhbgogICAgLSBUaGUgc2FtcGxlIHN0YW5kYXJkIGRldmlhdGlvbiAKICAgIC0gVGhlIHN0YW5kYXJkIGVycm9yCi0gV2UgbWFrZSBhIGJveHBsb3Qgb2YgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb25zIGFuZCB0aGUgc3RhbmRhcmQgZXJyb3JzIGZvciB0aGUgZGlmZmVyZW50IHNhbXBsZSBzaXplcwoKLSBJbnN0ZWFkIG9mIHVzaW5nIGEgZm9yIGxvb3Agd2Ugd2lsbCB1c2UgdGhlIHNhcHBseSBmdW5jdGlvbiB3aGljaCBpcyBtb3JlIGVmZmljaWVudC4gSXQgdGFrZXMgYSB2ZWN0b3Igb3IgYSBsaXN0IGFzIGlucHV0IGFuZCBhcHBsaWVzIGEgZnVuY3Rpb24gb24gZWFjaCBlbGVtZW50IG9mIHRoZSB2ZWN0b3Igb3Igb24gZWFjaCBsaXN0IGVsZW1lbnQuIAoKYGBge3J9CmZlbVNhbXAxMDwtc2FwcGx5KDE6MTAwMCxmdW5jdGlvbihqLHgsc2l6ZSkgc2FtcGxlKHgsc2l6ZSksc2l6ZT0xMCx4PWZlbSREaXJlY3RDaG9sKSAKCmZlbVNhbXA1MDwtc2FwcGx5KDE6MTAwMCxmdW5jdGlvbihqLHgsc2l6ZSkgc2FtcGxlKHgsc2l6ZSksc2l6ZT01MCx4PWZlbSREaXJlY3RDaG9sKSAKCmZlbVNhbXAxMDA8LXNhcHBseSgxOjEwMDAsZnVuY3Rpb24oaix4LHNpemUpIHNhbXBsZSh4LHNpemUpLHNpemU9MTAwLHg9ZmVtJERpcmVjdENob2wpIAoKcmVzPC1yYmluZCgKZmVtU2FtcDEwICU+JSAKICBsb2cyJT4lCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZ2F0aGVyKHNhbXBsZSxsb2cyQ2hvbCkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSklPiUKICBzdW1tYXJpemVfYXQoImxvZzJDaG9sIiwKICAgICAgICAgICAgICAgbGlzdChtZWRpYW49fm1lZGlhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKSAsCgpmZW1TYW1wNTAgJT4lIAogIGxvZzIgJT4lICAKICBhcy5kYXRhLmZyYW1lICU+JQogIGdhdGhlcihzYW1wbGUsbG9nMkNob2wpICU+JQogIGdyb3VwX2J5KHNhbXBsZSklPiUKICBzdW1tYXJpemVfYXQoImxvZzJDaG9sIiwKICAgICAgICAgICAgICAgbGlzdChtZWRpYW49fm1lZGlhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKSwKCmZlbVNhbXAxMDAgJT4lIAogIGxvZzIgJT4lIAogIGFzLmRhdGEuZnJhbWUgJT4lIAogIGdhdGhlcihzYW1wbGUsbG9nMkNob2wpICU+JSAKICBncm91cF9ieShzYW1wbGUpJT4lCiAgc3VtbWFyaXplX2F0KCJsb2cyQ2hvbCIsCiAgICAgICAgICAgICAgIGxpc3QobWVkaWFuPX5tZWRpYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBtZWFuPX5tZWFuKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgc2Q9fnNkKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgbj1mdW5jdGlvbih4KSB4JT4laXMubmElPiVgIWAlPiVzdW0pKSAlPiUKICBtdXRhdGUoc2U9c2Qvc3FydChuKSkKKQpgYGAKCiMjIyMjIE1lYW5zCgpXZSBmaXJzdCBpbGx1c3RyYXRlIHRoZSBpbXBhY3Qgb2Ygc2FtcGxlIHNpemUgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbWVhbnMgb2YgdGhlIGRpZmZlcmVudCBzYW1wbGVzCgpgYGB7cn0KcmVzICU+JSAKZ2dwbG90KGFlcyh4PW4lPiVhcy5mYWN0b3IseT1tZWFuKSkgKwpnZW9tX2JveHBsb3QoKSArCnlsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKSArIAp4bGFiKCJzYW1wbGUgc2l6ZSIpCmBgYAoKLSBOb3RlLCB0aGF0IHRoZSB2YXJpYXRpb24gb2YgdGhlIHNhbXBsZSBtZWFucyBpbmRlZWQgcmVkdWNlcyBhcyB0aGUgc2FtcGxlIHNpemUgaW5jcmVhc2VzLiBTbyB0aGUgZXN0aW1hdGlvbiBnZXRzIG1vcmUgcHJlY2lzZSB3aXRoIGluY3JlYXNpbmcgc2FtcGxlIHNpemUuIAoKLS0tCgojIyMjIyBTdGFuZGFyZCBkZXZpYXRpb24gCgpXZSBub3cgaWxsdXN0cmF0ZSB0aGUgaW1wYWN0IG9mIHNhbXBsZSBzaXplIG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgZGlmZmVyZW50IHNhbXBsZXMKCmBgYHtyfQpyZXMgJT4lIApnZ3Bsb3QoYWVzKHg9biU+JWFzLmZhY3Rvcix5PXNkKSkgKwpnZW9tX2JveHBsb3QoKSArCnlsYWIoInN0YW5kYXJkIGRldmlhdGlvbiIpICsgCnhsYWIoInNhbXBsZSBzaXplIikKYGBgCgoKLSBUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIHJlbWFpbnMgc2ltaWxhciBhY3Jvc3Mgc2FtcGxlIHNpemUuCkl0IGlzIGNlbnRyZWQgYXJvdW5kIHRoZSBzYW1lIHZhbHVlOiB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGluIHRoZSBwb3B1bGF0aW9uLiBJbmRlZWQgaW5jcmVhc2luZyB0aGUgc2FtcGxlIHNpemUgZG9lcyBhZmZlY3QgdGhlIHZhcmlhYmlsaXR5IGluIHRoZSBwb3B1bGF0aW9uIQoKLSBBZ2FpbiB3ZSBzZWUgdGhhdCB0aGUgdmFyaWFiaWxpdHkgb2YgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiByZWR1Y2VzIHdpdGggaW5jcmVhc2luZyBzYW1wbGUgc2l6ZS4gU28gdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBjYW4gYWxzbyBiZSBlc3RpbWF0ZWQgbW9yZSBwcmVjaXNlIHdpdGggaW5jcmVhc2luZyBzYW1wbGUgc2l6ZS4gCgotLS0KCiMjIyMjIFN0YW5kYXJkIGVycm9yIG9uIHRoZSBtZWFuIAoKRmluYWxseSwgd2UgaWxsdXN0cmF0ZSB0aGUgaW1wYWN0IG9mIHNhbXBsZSBzaXplIG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvbiB0aGUgbWVhbiBvZiB0aGUgZGlmZmVyZW50IHNhbXBsZXMKCmBgYHtyfQpyZXMgJT4lIApnZ3Bsb3QoYWVzKHg9biU+JWFzLmZhY3Rvcix5PXNlKSkgKwpnZW9tX2JveHBsb3QoKSArCnlsYWIoInN0YW5kYXJkIGVycm9yIikgKyAKeGxhYigic2FtcGxlIHNpemUiKQpgYGAKCi0gVGhlIHN0YW5kYXJkIGVycm9yLCB0aGUgZXN0aW1hdG9yIGZvciB0aGUgcHJlY2lzaW9uIG9mIHRoZSBzYW1wbGUgbWVhbiwgaG93ZXZlciwgcmVkdWNlcyBjb25zaWRlcmFibHkgd2l0aCBpbmNyZWFzaW5nIHNhbXBsZSBzaXplIGFnYWluIGNvbmZpcm1pbmcgdGhhdCB0aGUgZXN0aW1hdGlvbiBvZiB0aGUgc2FtcGxlIG1lYW4gZ2V0cyBtb3JlIHByZWNpc2UuIAoKLS0tCgojIyMgTm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YQoKLSBGb3Igbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YSB3ZSBoYXZlIG11bHRpcGxlIGVzdGltYXRvcnMgZm9yIHRoZSBwb3B1bGF0aW9uIG1lYW4gJFxtdSQgZS5nIG1lYW4gYW5kIG1lZGlhbi4KCi0gQnV0LCAkXGJhcntYfSQgaXMgdGhlIHVuYmlhc2VkIGVzdGltYXRvciBvZiAkXG11JCB3aXRoIHRoZSBzbWFsbGVzdCBzdGFuZGFyZCBlcnJvciAKCi0gICRcYmFye1h9JCBkZXZpYXRlcyBsZXNzIGZyb20gdGhlIG1lYW4gJFxtdSQgdGhhbiB0aGUgbWVkaWFuCgotIFdlIGlsbHVzdHJhdGUgdGhpcyBmb3IgcmVwZWF0ZWQgc2FtcGxpbmcgd2l0aCBzYW1wbGUgc2l6ZSAxMApgYGB7cn0KcmVzICU+JQogIGZpbHRlcihuPT0xMCkgJT4lCiAgc2VsZWN0KG1lYW4sbWVkaWFuKSAlPiUKICBnYXRoZXIodHlwZSxlc3RpbWF0ZSkgJT4lCiAgZ2dwbG90KGFlcyh4PXR5cGUseT1lc3RpbWF0ZSkpICsKICBnZW9tX2JveHBsb3QoKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9ZmVtJERpcmVjdENob2wlPiVsb2cyJT4lbWVhbikgKwogIGdndGl0bGUoIjEwIHN1YmplY3RzIikKYGBgCgpOZXh0LCB3ZSBjb21wYXJlIHRoZSBkaXN0cmlidXRpb24gb2YgbWVhbiBhbmQgbWVkaWFuIGluIHJlcGVhdGVkIHNhbXBsZXMgb2Ygc2FtcGxlIHNpemUgNTAuCgpgYGB7cn0KcmVzICU+JQogIGZpbHRlcihuPT01MCkgJT4lCiAgc2VsZWN0KG1lYW4sbWVkaWFuKSAlPiUKICBnYXRoZXIodHlwZSxlc3RpbWF0ZSkgJT4lCiAgZ2dwbG90KGFlcyh4PXR5cGUseT1lc3RpbWF0ZSkpICsKICBnZW9tX2JveHBsb3QoKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9ZmVtJERpcmVjdENob2wlPiVsb2cyJT4lbWVhbikgKwogIGdndGl0bGUoIjUwIHN1YmplY3RzIikKYGBgCgojIyMgRGlzdHJpYnV0aW9uIG9mIHNhbXBsZSBtZWFuCgoKLSBIb3cgdmFyaWVzICRcYmFyIFgkIGZyb20gc2FtcGxlIHRvIHNhbXBsZT8gCi0gRGlzdHJpYnV0aW9uIG9mICRcYmFyIFgkPwotIElmICRcYmFyIFgkIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHRoZSBzdGFuZGFyZCBlcnJvciBoYXMgYSBnb29kIGludGVycHJldGF0aW9uOiB0aGUgcy5lLiBpcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbi4KLSBJZiB0aGUgZGF0YSAkWF9pJCBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHRoZSBzYW1wbGUgbWVhbiBpcyBhbHNvIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiAKCiQkWF9pIFxzaW0gTihcbXUsXHNpZ21hXjIpIFxyaWdodGFycm93ICBcYmFyIFggXHNpbSBOKFxtdSwgIFxzaWdtYV4yL24pJCQKCi0tLQoKIyMjIyBOSEFORVM6IGNob2xlc3Rlcm9sCgpXZSBpbGx1c3RyYXRlIHRoaXMgYWdhaW4gd2l0aCBzaW11bGF0aW9uIHVzaW5nIHRoZSBOSEFORVMgc3R1ZHkuIApUaGUgbG9nMiBjaG9sZXN0ZXJvbCBsZXZlbHMgd2VyZSBub3JtYWxseSBkaXN0cmlidXRlZC4gCgpgYGB7cn0KIGZlbSAlPiUgCiAgZ2dwbG90KGFlcyh4PURpcmVjdENob2wlPiVsb2cyKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4sIGZpbGw9Li5jb3VudC4uKSkgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKSArCiAgc3RhdF9mdW5jdGlvbihmdW49ZG5vcm0sY29sb3I9InJlZCIsYXJncz1saXN0KG1lYW49bWVhbihmZW0kRGlyZWN0Q2hvbCU+JWxvZzIpLCBzZD1zZChmZW0kRGlyZWN0Q2hvbCU+JWxvZzIpKSkgKwogIGdndGl0bGUoIkFsbCBmZW1hbGVzIGluIE5oYW5lcyBzdHVkeSIpCiAgCmZlbSAlPiUgCiAgZ2dwbG90KGFlcyhzYW1wbGU9RGlyZWN0Q2hvbCU+JWxvZzIpKSArCiAgc3RhdF9xcSgpICsKICBzdGF0X3FxX2xpbmUoKSArCiAgZ2d0aXRsZSgiQWxsIGZlbWFsZXMgaW4gTmhhbmVzIHN0dWR5IikKYGBgCgotLS0KCiMjIyMjIEV2YWx1YXRlIGRpc3RyaWJ1dGlvbiBmb3Igc2FtcGxlcyB3aXRoIDUgc3ViamVjdHMKCmBgYHtyfQpmZW1TYW1wNTwtc2FwcGx5KDE6MTAwMCxmdW5jdGlvbihqLHgsc2l6ZSkKICBzYW1wbGUoeCxzaXplKSxzaXplPTUseD1mZW0kRGlyZWN0Q2hvbCkKCmZlbVNhbXA1WywxXSAlPiUgCiAgbG9nMiAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUKICBnZ3Bsb3QoYWVzKHg9LikpKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLiksYmlucz0xMCkgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKSArCiAgc3RhdF9mdW5jdGlvbihmdW49ZG5vcm0sY29sb3I9InJlZCIsYXJncz1saXN0KG1lYW49ZmVtU2FtcDVbLDFdJT4lbG9nMiU+JW1lYW4sIHNkPWZlbVNhbXA1WywxXSU+JWxvZzIlPiVzZCkpICsKICBnZ3RpdGxlKCI1IHJhbmRvbSBmZW1hbGVzIikgKyAKICB4bGltKGZlbSREaXJlY3RDaG9sICU+JSBsb2cyICU+JSByYW5nZSkKCiAgCmZlbVNhbXA1ICU+JSAKICBsb2cyICU+JSAKICBjb2xNZWFucyAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZ2dwbG90KGFlcyh4PS4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4sIGZpbGw9Li5jb3VudC4uKSxiaW5zPTE1KSArCiAgeGxhYigiTWVhbiBjaG9sZXN0ZXJvbCAobG9nMikiKSArCiAgc3RhdF9mdW5jdGlvbihmdW49ZG5vcm0sY29sb3I9InJlZCIsYXJncz1saXN0KG1lYW49ZmVtU2FtcDUlPiVsb2cyJT4lIGNvbE1lYW5zICU+JSBtZWFuLCBzZD1mZW1TYW1wNSU+JWxvZzIlPiUgY29sTWVhbnMgJT4lIHNkKSkgKwpnZ3RpdGxlKCJNZWFucyBvbiA1IGZlbWFsZXMiKSAKCmZlbVNhbXA1ICU+JSAKICBsb2cyICU+JSAKICBjb2xNZWFucyAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUgIAogIGdncGxvdChhZXMoc2FtcGxlPS4pKSArCiAgc3RhdF9xcSgpICsKICBzdGF0X3FxX2xpbmUoKSArCiAgZ2d0aXRsZSgiTWVhbnMgb24gNSBmZW1hbGVzIikKYGBgCgotLS0KCiMjIyMjIEV4cGxvcmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbWVhbiBmb3Igc2FtcGxlcyBvZiBzaXplIDEwCgpOb3cgd2UgZXhwbG9yZSB0aGUgcmVzdWx0cyBmb3IgdGhlIHNhbXBsZSBzaXplIG9mIDEwLgoKV2UgZmlyc3QgaWxsdXN0cmF0ZSB0aGUgcGxvdCBmb3IgdGhlIGZpcnN0IHNhbXBsZS4gCgpgYGB7cn0KZmVtU2FtcDEwWywxXSAlPiUgbG9nMiAlPiUgYXMuZGF0YS5mcmFtZSAlPiUKZ2dwbG90KGFlcyh4PS4pKSsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiwgZmlsbD0uLmNvdW50Li4pLGJpbnM9MTApICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKGxvZzIpIikgKwogIHN0YXRfZnVuY3Rpb24oZnVuPWRub3JtLGNvbG9yPSJyZWQiLGFyZ3M9bGlzdChtZWFuPWZlbVNhbXAxMFssMV0lPiVsb2cyJT4lbWVhbiwgc2Q9ZmVtU2FtcDEwWywxXSU+JWxvZzIlPiVzZCkpICsKZ2d0aXRsZSgiMTAgcmFuZG9tIGZlbWFsZXMiKSArIAp4bGltKGZlbSREaXJlY3RDaG9sICU+JSBsb2cyICU+JSByYW5nZSkKYGBgCgpOZXh0IHdlIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxlIG1lYW4gb3ZlciAxMDAwIHNhbXBsZXMgb2Ygc2FtcGxlIHNpemUgMTAuIAoKYGBge3J9CmZlbVNhbXAxMCAlPiUgbG9nMiAlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIGdncGxvdChhZXMoeD0uKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLiksYmlucz0xNSkgKwogIHhsYWIoIk1lYW4gY2hvbGVzdGVyb2wgKGxvZzIpIikgKwogIHN0YXRfZnVuY3Rpb24oZnVuPWRub3JtLGNvbG9yPSJyZWQiLGFyZ3M9bGlzdChtZWFuPWZlbVNhbXAxMCU+JWxvZzIlPiUgY29sTWVhbnMgJT4lIG1lYW4sIHNkPWZlbVNhbXAxMCU+JWxvZzIlPiUgY29sTWVhbnMgJT4lIHNkKSkgKwpnZ3RpdGxlKCJNZWFucyBvbiAxMCBmZW1hbGVzIikgCgpmZW1TYW1wMTAgJT4lIGxvZzIlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lICBnZ3Bsb3QoYWVzKHNhbXBsZT0uKSkgKwpzdGF0X3FxKCkgKwpzdGF0X3FxX2xpbmUoKSArCmdndGl0bGUoIk1lYW5zIG9uIDEwIGZlbWFsZXMiKQpgYGAKCioqU28gd2UgY29uZmlybWVkIHRoYXQgdGhlIG1lYW4gaXMgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZCBmb3Igc3R1ZGllcyB3aXRoIDUgYW5kIDEwIGZlbWFsZXMgd2hlbiB0aGUgb3JpZ2luYWwgZGF0YSBhcmUgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4qKiAKCi0tLQoKIyMjIyBDYXB0b3ByaWwgc3R1ZHkKCi0gRm9yIENhcHRvcHJpbCBzdHVkeSB0aGUgc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUgZGlmZmVyZW5jZXMgYXJlIGFwcHJveGltYXRpdmVseSBub3JtYWxseSBkaXN0cmlidXRlZC4gIAoKLSBzLmUuPSAyLjMyIG1tIEhnCgotIEluIDk1IG91dCBvZiAxMDAgc3R1ZGllcyB3aXRoIG4gPSAxNSBzdWJqZWN0cyB3ZSBleHBlY3QgdGhlIHNhbXBsZSBtZWFuIG9mIHRoZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlcyAoJFxiYXIgWCQpIG9uIGxlc3MgdGhlbiAkMiBcdGltZXMgMi4zMiA9IDQuNjQkbW0gSGcgb2YgdGhlIHJlYWwgcG9wdWxhdGlvbiBtZWFuIG9mIHRoZSBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlcyAoJFxtdSQpLgoKLS0tCgojIyMgTm9uLW5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEKCi0gV2hlbiBpbmRpdmlkdWFsIG9ic2VydmF0aW9ucyBkbyBub3QgaGF2ZSBhIG5vcm1hbCBkaXN0cmlidXRpb24sICAgJFxiYXIgWCQgaXMgc3RpbGwgXHRleHRpdHthcHByb3hpbWF0ZWx5fSBOb3JtYWxseSBkaXN0cmlidXRlZCAKd2hlbiB0aGUgbnVtYmVyIG9ic2VydmF0aW9ucyBhcmUgbGFyZ2UgZW5vdWdoLgoKLSBIb3cgbGFyZ2UgZG9lcyB0aGUgc2FtcGxlIG5lZWRzIHRvIGJlIGZvciB0aGUgTm9ybWFsIGFwcHJveGltYXRpb24gdG8gd29yaz8gIAoKLSBUaGlzIGRlcGVuZHMgb24gdGhlIHNrZXduZXNzIG9mIHRoZSBkaXN0cmlidXRpb24hCgotLS0KCiMjIyMgTkhBTkVTOiBjaG9sZXN0ZXJvbAoKLSBXaGVuIGNhbiBldmFsdWF0ZWQgdGhpcyBpbiB0aGUgTkhhbmVzIHN0dWR5IGlmIHdlIGRvIG5vdCBsb2cyIHRyYW5zZm9ybSB0aGUgZGF0YS4KCmBgYHtyfQpmZW0gJT4lIGdncGxvdChhZXMoeD1EaXJlY3RDaG9sKSkrCiAgIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLikpICsKICAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIikgKwogICBzdGF0X2Z1bmN0aW9uKGZ1bj1kbm9ybSxjb2xvcj0icmVkIixhcmdzPWxpc3QobWVhbj1tZWFuKGZlbSREaXJlY3RDaG9sKSwgc2Q9c2QoZmVtJERpcmVjdENob2wpKSkgKwogICBnZ3RpdGxlKCJBbGwgZmVtYWxlcyBpbiBOaGFuZXMgc3R1ZHkiKQoKIGZlbSAlPiUgZ2dwbG90KGFlcyhzYW1wbGU9RGlyZWN0Q2hvbCkpICsKIHN0YXRfcXEoKSArCiBzdGF0X3FxX2xpbmUoKSArCiBnZ3RpdGxlKCJBbGwgZmVtYWxlcyBpbiBOaGFuZXMgc3R1ZHkiKQpgYGAKClRoZSBjaG9sZXN0ZXJvbCBkYXRhIGlzIGNsZWFybHkgbm9uLU5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMjIyMgRGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbiBmb3IgZGlmZmVyZW50IHNhbXBsZSBzaXplcyAKCmBgYHtyfQpmZW1TYW1wNSAlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIGdncGxvdChhZXMoeD0uKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLiksYmlucz0xNSkgKwogIHhsYWIoIk1lYW4gY2hvbGVzdGVyb2wiKSArCiAgc3RhdF9mdW5jdGlvbihmdW49ZG5vcm0sY29sb3I9InJlZCIsYXJncz1saXN0KG1lYW49ZmVtU2FtcDUlPiUgY29sTWVhbnMgJT4lIG1lYW4sIHNkPWZlbVNhbXA1JT4lIGNvbE1lYW5zICU+JSBzZCkpICsKZ2d0aXRsZSgiTWVhbnMgb24gNSBmZW1hbGVzIikgCgpmZW1TYW1wNSAlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lICBnZ3Bsb3QoYWVzKHNhbXBsZT0uKSkgKwpzdGF0X3FxKCkgKwpzdGF0X3FxX2xpbmUoKSArCmdndGl0bGUoIk1lYW5zIG9uIDUgZmVtYWxlcyIpCgoKZmVtU2FtcDEwICU+JSBjb2xNZWFucyAlPiUgYXMuZGF0YS5mcmFtZSAlPiUgZ2dwbG90KGFlcyh4PS4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4sIGZpbGw9Li5jb3VudC4uKSxiaW5zPTE1KSArCiAgeGxhYigiTWVhbiBjaG9sZXN0ZXJvbCIpICsKICBzdGF0X2Z1bmN0aW9uKGZ1bj1kbm9ybSxjb2xvcj0icmVkIixhcmdzPWxpc3QobWVhbj1mZW1TYW1wMTAlPiUgY29sTWVhbnMgJT4lIG1lYW4sIHNkPWZlbVNhbXAxMCU+JSBjb2xNZWFucyAlPiUgc2QpKSArCmdndGl0bGUoIk1lYW5zIG9uIDEwIGZlbWFsZXMiKSAKCmZlbVNhbXAxMCAlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lICBnZ3Bsb3QoYWVzKHNhbXBsZT0uKSkgKwpzdGF0X3FxKCkgKwpzdGF0X3FxX2xpbmUoKSArCmdndGl0bGUoIk1lYW5zIG9uIDEwIGZlbWFsZXMiKQoKZmVtU2FtcDUwICU+JSBjb2xNZWFucyAlPiUgYXMuZGF0YS5mcmFtZSAlPiUgIGdncGxvdChhZXMoc2FtcGxlPS4pKSArCnN0YXRfcXEoKSArCnN0YXRfcXFfbGluZSgpICsKZ2d0aXRsZSgiTWVhbnMgb24gNTAgZmVtYWxlcyIpCgpmZW1TYW1wMTAwICU+JSBjb2xNZWFucyAlPiUgYXMuZGF0YS5mcmFtZSAlPiUgIGdncGxvdChhZXMoc2FtcGxlPS4pKSArCnN0YXRfcXEoKSArCnN0YXRfcXFfbGluZSgpICsKZ2d0aXRsZSgiTWVhbnMgb24gMTAwIGZlbWFsZXMiKQpgYGAKCi0gKipXZSBvYnNlcnZlIHRoYXQgd2hlbiB0aGUgZGF0YSBhcmUgbm90IG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZSBtZWFuIGlzIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCBpbiBzbWFsbCBzYW1wbGVzKiogCgotICoqRm9yIGxhcmdlIHNhbXBsZXMsIGhvd2V2ZXIsIHRoZSBzYW1wbGUgbWVhbiBvZiBub24gbm9ybWFsIGRhdGEgaXMgc3RpbGwgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4qKgoKLS0tCgojIyMgQ2VudHJhbGUgTGltaXQgVGhlb3JlbQoKTGV0ICRYXzEsIFxsZG90cywgWF9uJCBhcmUgc2VxdWVuY2Ugb2YgcmFuZG9tIHZhcmlhYmxlcyB0aGF0IGFyZSBkcmF3biBpbmRlcGVuZGVudGx5IGZyb20gdGhlIHNhbWUgZGlzdHJpYnV0aW9uIChwb3B1bGF0aW9uKS4KQXMgbG9uZyBhcyB0aGUgc2FtcGxlIHNpemUgbiBpcyBzdWZmaWNpZW50bHkgbGFyZ2UsIHRoZSBzYW1wbGUgbWVhbiAkXGJhciBYJCBpcyBhcHByb3hpbWF0ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBpcnJlc3BlY3RpdmUgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgb2JzZXJ2YXRpb25zICRYX2kkLgoKIyMjIE92ZXJ2aWV3IG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG1lYW4KCiFbXShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL25tZXRoLjI2MTMucGRmKXt3aWR0aD0xMDAlfQoKLS0tCgojSW50ZXJ2YWwgZXN0aW1hdG9ycwoKLSAkXGJhciBYJCB2YXJpZXMgYXJvdW5kICRcbXUkIAoKLSBIZXJlIHdlIHdpbGwgZGV2ZWxvcCBhbiBpbnRlcnZhbCBhcm91bmQgJFxiYXIgWCQgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIHZhbHVlIG9mICRcbXUkIHdpdGggYSBwcm9iYWJpbGl0eSBvZiA5NSUgZm9yIGEgcmFuZG9tIHNhbXBsZS4gCgotIFdlIGZpcnN0IGFzc3VtZSAkXHNpZ21hXjIkIHRvIGJlIGtub3duIGFuZCB3ZSB3aWxsIGxhdGVyIHJlbGF4IHRoaXMgYXNzdW1wdGlvbi4gCgotLS0KCiMjIE5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEgd2l0aCBrbm93biB2YXJpYW5jZQoKLSAkWFxzaW0gTihcbXUsXHNpZ21hXjIpIFxyaWdodGFycm93IFxiYXIgWFxzaW0gTlxsZWZ0KFxtdSxcZnJhY3tcc2lnbWFeMn17bn1ccmlnaHQpJAoKLSA5NSUgcmVmZXJlbmNlLWludGVydmFsIGZvciBzYW1wbGUgbWVhbgoKXGJlZ2lue2VxdWF0aW9uKn0KXGxlZnRbXG11IC0gMS45NiBcZnJhY3tcc2lnbWF9e1xzcXJ0e259fSxcbXUgKyAxLjk2IFxmcmFje1xzaWdtYX17XHNxcnR7bn19JQpccmlnaHRdClxlbmR7ZXF1YXRpb24qfQoKLSBUaGUgaW50ZXJ2YWwgY29udGFpbnMgdGhlIHNhbXBsZSBtZWFuIG9mIGEgcmFuZG9tIHNhbXBsZSB3aXRoIGEgcHJvYmFiaWxpdHkgb2YgOTUlLiAKCi0gV2UgY2FuIG5vdCBjYWxjdWxhdGUgaXQgYmVjYXVzZSAkXG11JCBpcyB1bmtub3duLgoKLSBFc3RpbWF0ZSAkXG11JCBieSAkXGJhciBYJC4gIApcYmVnaW57ZXF1YXRpb24qfQpcbGVmdFtcYmFyIFggLSAxLjk2IFxmcmFje1xzaWdtYX17XHNxcnR7bn19LFxiYXIgWCArIDEuOTYgXGZyYWN7XHNpZ21hfXtcc3FydHtufX1ccmlnaHRdClxlbmR7ZXF1YXRpb24qfQoKCi0gTW9yZSB1c2VmdWwgaW50ZXJwcmV0YXRpb246Clx2c3BhY2V7MTVwdH0KLSBSZXdyaXRlICRcbXUgLSAxLjk2IFwgXHNpZ21hL1xzcXJ0e259IDwgXGJhcntYfSQgYXMgJFxtdSA8IFxiYXJ7WH0gKyAxLjk2IFwgXHNpZ21hL1xzcXJ0e259JC4KClNvIHRoYXQgd2UgY2FuIHdyaXRlClxiZWdpbntlcW5hcnJheSp9Cjk1XCUgJj0mIFAoIFxtdSAtIDEuOTYgXCBcc2lnbWEvXHNxcnR7bn0gPCBcYmFye1h9IDwgXG11ICsgMS45NiBcIFxzaWdtYS9cc3FydHtufSApIFxcCiY9JlAoIFxiYXJ7WH0gLSAxLjk2IFwgXHNpZ21hL1xzcXJ0e259IDwgXG11IDwgXGJhcntYfSArIDEuOTYgXCBcc2lnbWEvXHNxcnR7bn0gKQpcZW5ke2VxbmFycmF5Kn0KCi0tLQoKKipEZWZpbml0aW9uIG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsIG9uIG1lYW4qKgpGb3IgYSByYW5kb20gc2FtcGxlLCB0aGUgaW50ZXJ2YWwKXGJlZ2lue2VxdWF0aW9ufSAgCltcYmFye1h9IC0gMS45NiBcIFxzaWdtYS9cc3FydHtufSAsIFxiYXJ7WH0gKyAxLjk2IFwgXHNpZ21hL1xzcXJ0e259IF0sClxlbmR7ZXF1YXRpb259CmNvbnRhaW5zIHRoZSBwb3B1bGF0aW9uIG1lYW4gJFxtdSQgd2l0aCBhIHByb2JhYmlsaXR5IG9mIDk1JS4KCi0tLQoKLSBUaGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgQ0kgZm9yIGEgcmFuZG9tIHNhbXBsZSBjb250YWlucyB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXIgJFxtdSQsIGkuZS4gOTUlLCBpcyBhbHNvIHJlZmVycmVkIHRvIGFzIHRoZSAqKmNvbmZpZGVuY2UgbGV2ZWwqKi4KCi0gTm90ZSwgdGhhdCB0aGUgbG93ZXIgYW5kIHVwcGVyIGxpbWl0IG9mIHRoZSBpbnRlcnZhbCBhcmUgYWxzbyByYW5kb20gdmFyaWFibGVzIHRoYXQgdmFyeSBmcm9tIHNhbXBsZSB0byBzYW1wbGUuIERpZmZlcmVudCBzYW1wbGVzIGluZGVlZCByZXN1bHQgaW4gZGlmZmVyZW50IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGJlY2F1c2UgdGhleSBhcmUgYmFzZWQgb24gZGlmZmVyZW50IG9ic2VydmF0aW9uLiAKCi0gU28gdGhleSBhcmUgKnN0b2NoYXN0aWMgaW50ZXJ2YWxzKgoKLSA5NSUgb2YgdGhlIHNhbXBsZXMgd2lsbCBwcm9kdWNlIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIHBvcHVsYXRpb24gbWVhbiAkXG11JC4gVGhlIHJlbWFpbmluZyA1JSB3aWxsIHByb2R1Y2UgaW50ZXJ2YWxzIHRoYXQgZG8gbm90IGNvbnRhaW4gdGhlIHBvcHVsYXRpb24gbWVhbi4gCgotIEJhc2VkIG9uIG9uZSBpbnRlcnZhbCB5b3UgY2Fubm90IGNvbmNsdWRlIHRoYXQgaXQgY29udGFpbnMgdGhlIHJlYWwgcG9wdWxhdGlvbiBwYXJhbWV0ZXIsIGJlY2F1c2UgaXRzIHZhbHVlIGlzIHVua25vd24uIAoKR2VuZXJhbGx5IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gaXMgdW5rbm93biBhbmQgaGFzIHRvIGJlIGVzdGltYXRlZCBlLmcuIGJ5ICRTJAoKLSBGb3IgbGFyZ2UgJG4kICRbXGJhcntYfSAtIDEuOTYgXCBzL1xzcXJ0e259ICwgXGJhcntYfSArIDEuOTYgXCBzL1xzcXJ0e259IF0kIHdpbGwgY29udGFpbiB0aGUgcG9wdWxhdGlvbiBtZWFuIHdpdGggYSBwcm9iYWJpbGl0eSBvZiBhcHByb3hpbWF0ZWx5IDk1JS4gCgotLS0KCiMjIyBOSEFORVMgbG9nMiBjaG9sZXN0ZXJvbCBleGFtcGxlCgojIyMjIE9uZSBzYW1wbGUKYGBge3J9CnNhbXA1MDwtc2FtcGxlKGZlbSREaXJlY3RDaG9sLDUwKQoKbGw8LW1lYW4oc2FtcDUwICU+JSBsb2cyKSAtIDEuOTYqc2Qoc2FtcDUwICU+JSBsb2cyKS9zcXJ0KDUwKQp1bDwtbWVhbihzYW1wNTAgJT4lIGxvZzIpICsgMS45NipzZChzYW1wNTAgJT4lIGxvZzIpL3NxcnQoNTApCnBvcE1lYW48LW1lYW4oZmVtJERpcmVjdENob2wlPiVsb2cyKQoKYyhsbD1sbCx1bD11bCxwb3BNZWFuPXBvcE1lYW4pCmBgYAoKIyMjIyBSZXBlYXRlZCBzYW1wbGluZwpgYGB7cn0KcmVzJGxsPC1yZXMkbWVhbi0xLjk2KnJlcyRzZQpyZXMkdWw8LXJlcyRtZWFuKzEuOTYqcmVzJHNlCm11PC1mZW0kRGlyZWN0Q2hvbCU+JWxvZzIlPiVtZWFuCnJlcyRpbnNpZGU8LXJlcyRsbDw9bXUgJiBtdTw9cmVzJHVsCnJlcyRuIDwtIGFzLmZhY3RvcihyZXMkbikKcmVzICU+JSAKICBncm91cF9ieShuKSAlPiUgCiAgc3VtbWFyaXplKGNvdmVyYWdlPW1lYW4oaW5zaWRlKSkgJT4lIAogIHNwcmVhZChuLGNvdmVyYWdlKSAKYGBgCgotIE5vdGUsIHRoYXQgdGhlIGNvdmVyYWdlIGluIHRoZSBzYW1wbGVzIHdpdGggMTAgb2JzZXJ2YXRpb25zIGlzIHRvbyBsb3cgYmVjYXVzZSB3ZSBkbyBub3QgYWNjb3VudCBmb3IgdGhlIHVuY2VydGFpbnR5IGluIHRoZSBlc3RpbWF0aW9uIG9mIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24uIAoKLSBJZiB3ZSBsb29rIHRvIHRoZSBmaXJzdCAyMCBpbnRlcnZhbHMsIGByIHN1bSgoIXJlc1tyZXMkbj09MTAsImluc2lkZSJdKVsxOjIwXSlgICBvdXQgb2YgMjAgZG8gbm90IGNvbnRhaW4gdGhlIHBvcHVsYXRpb24gbWVhbi4KCmBgYHtyfQpyZXMgJT4lIAogIGZpbHRlcihuPT0xMCkgJT4lIAogIHNsaWNlKDE6MjApICU+JQogIGdncGxvdChhZXMoeD1zYW1wbGUseT1tZWFuLGNvbG9yPWluc2lkZSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tMS45NipzZSx5bWF4PW1lYW4rMS45NipzZSkpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGZlbSREaXJlY3RDaG9sJT4lIGxvZzIgJT4lIG1lYW4pICsgCiAgZ2d0aXRsZSgiMjAgQ0kgZm9yIE49MTAiKSArIAogIHlsaW0ocmFuZ2UoZmVtJERpcmVjdENob2wgJT4lIGxvZzIpKQpgYGAKCi0tLQoKLSBGb3IgbGFyZ2Ugc2FtcGxlIHNpemVzICgxMDApIHRoZSBjb3ZlcmFnZSBpcyBmaW5lIGJlY2F1c2Ugd2UgY2FuIGVzdGltYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gd2l0aCBhIHJlbGF0aXZlIGhpZ2ggcHJlY2lzaW9uLiAgCgpgYGB7cn0KcmVzICU+JSAKICBmaWx0ZXIobj09NTApICU+JSAKICBzbGljZSgxOjIwKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2FtcGxlLHk9bWVhbixjb2xvcj1pbnNpZGUpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLTEuOTYqc2UseW1heD1tZWFuKzEuOTYqc2UpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBmZW0kRGlyZWN0Q2hvbCU+JSBsb2cyICU+JSBtZWFuKSArCiAgZ2d0aXRsZSgiMjAgQ0kgZm9yIE49NTAiKSArCiAgeWxpbShyYW5nZShmZW0kRGlyZWN0Q2hvbCAlPiUgbG9nMikpCgpyZXMgJT4lIAogIGZpbHRlcihuPT0xMDApICU+JSAKICBzbGljZSgxOjIwKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2FtcGxlLHk9bWVhbixjb2xvcj1pbnNpZGUpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLTEuOTYqc2UseW1heD1tZWFuKzEuOTYqc2UpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBmZW0kRGlyZWN0Q2hvbCU+JSBsb2cyICU+JSBtZWFuKSArCiAgZ2d0aXRsZSgiMjAgQ0kgZm9yIE49MTAwIikgKwogIHlsaW0ocmFuZ2UoZmVtJERpcmVjdENob2wgJT4lIGxvZzIpKQpgYGAKCi0gV2hhdCBoYXZlIHlvdSBvYnNlcnZlZCBmb3IgdGhlIGludGVydmFsIHdpZHRoPyAKCi0tLQoKIyMjIE90aGVyIGNvbmZpZGVuY2UgbGV2ZWxzIAoKLSBXZSBjYW4gcmVwbGFjZSB0aGUgJHpfezIuNVwlfT0xLjk2JCBieSBhbm90aGVyIHF1YW50aWxlIG9mIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uICR6X3tcYWxwaGEvMn0gdG8gb2J0YWluIGFuIGludGVydmFsIHdpdGggYW5vdGhlciBjb25maWRlbmNlIGxldmVsICQxLVxhbHBoYSQuIAoKLSBDb25maWRlbmNlIGludGVydmFscyBhcmUgbm90IG9ubHkgdXNlZCBmb3IgdGhlIG1lYW4gYnV0IGFsc28gZm9yIG90aGVyIHBvcHVsYXRpb24gcGFyYW1ldGVycy4gCgotLS0KCiMjIFVua25vd24gdmFyaWFuY2UKCkluIHJlYWwgZXhhbXBsZXMgJFxzaWdtYSQgaXMgdW5rbm93biBhbmQgZXN0aW1hdGVkIGJhc2VkIG9uIHRoZSBzYW1wbGUgdXNpbmcgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb24gJFMkLiAKCi0gVGhlIHByZXZpb3VzIGludGVydmFscyB3ZXJlIGEgYml0IHRvIHNtYWxsIGJlY2F1c2UgdGhleSBkaWQgbm90IGFjY291bnQgZm9yIHRoZSB1bmNlcnRhaW50eSBvbiB0aGUgZXN0aW1hdGlvbiBvZiAkUyQuIAoKLSBXaGVuICRuJCBpcyBsYXJnZSwgJFMkIGlzIGNsb3NlIHRvICRcc2lnbWEkLiAKCi0gSGVuY2UsICR7KFxiYXJ7WH0gLSBcbXUpfS97KFMvXHNxcnR7bn0pIH0kIGlzIGFwcHJveGltYXRlbHkgc3RhbmRhcmQgbm9ybWFsIGFuZCAKXGJlZ2lue2VxdWF0aW9uKn0KXGxlZnRbXGJhcntYfSAtIHpfe1xhbHBoYS8yfSBcIFxmcmFje1N9e1xzcXJ0e259fSAsIFxiYXJ7WH0gKyB6X3tcYWxwaGEvMn0gXApcZnJhY3tTfXtcc3FydHtufX1ccmlnaHRdClxlbmR7ZXF1YXRpb24qfQppcyBhbiBhcHByb3hpbWF0ZSAkKDEtIFxhbHBoYSkxMDBcJSQgQ0kgZm9yICRcbXUkLgoKLSBGb3Igc21hbGwgc2FtcGxlcyB0aGlzIG5vIGxvbmdlciBob2xkcyAoZS5nLiBuPTEwKSAKClRoZSBlc3RpbWF0aW9uIG9mICRTJCBpbnRyb2R1Y2VzIGFkZGl0aW9uYWwgdW5jZXJ0YWludHkgaW4gdGhlIHN0YW5kYXJkaXplZCB2YWx1ZSAkeyhcYmFye1h9IC0gXG11KX0veyhTL1xzcXJ0e259KX0kLiBJdHMgZGlzdHJpYnV0aW9uCgotIGlzIHN0aWxsIHN5bW1ldHJpYyBidXQgaGFzIGhlYXZpZXIgdGFpbHMgdGhhdCB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gCgotIGl0IGRlcGVuZHMgb24gJG4kIGhvdyBtdWNoIGhlYXZpZXIgdGhlIHRhaWxzIGFyZSAgCgotIGlzIGEgKFN0dWRlbnQpICR0JC1kaXN0cmlidXRpb24gd2l0aCAkbi0xJCAqZGVncmVlcyBvZiBmcmVlZG9tKi4KCi0tLQoKIyMjIFQtZGlzdHJpYnV0aW9uCgpNb3JlIGZvcm1hbGx5OiBMZXQgJFhfMSwgWF8yLCAuLi4sIFhfbiQgYmUgYW4gaW5kZXBlbmRlbnQgcmFuZG9tIHNhbXBsZSBmcm9tIGEgTm9ybWFsIGRpc3RyaWJ1dGlvbiAkTihcbXUsIFxzaWdtYV4yKSQsIHRoZW4gJChcYmFye1h9IC0gXG11KS8oUy9cc3FydHtufSkkIGZvbGxvd3MgYSAkdCQtZGlzdHJpYnV0aW9uIHdpdGggJG4tMSQgZGVncmVlcyBvZiBmcmVlZG9tLgoKVGhlIGRlbnNpdHkgb2YgYSB0LWRpc3RyaWJ1dGlvbiBjYW4gYmUgY2FsY3VsYXRlZCBpbiBSIHVzaW5nIHRoZSBmdW5jdGlvbiBgZHRgLiBJdCBoYXMgYXJndW1lbnRzIGB4YCBmb3IgdGhlIHF1YW50aWxlIGFuZCBgZGZgIGZvciB0aGUgZGVncmVlcyBvZiBmcmVlZG9tLiAKCmBgYHtyIGV2YWw9RkFMU0V9CmdyaWQgPC0gc2VxKC01LDUsLjEpCmRlbnNEaXN0PC1jYmluZChncmlkLGRub3JtKGdyaWQpLCBzYXBwbHkoYygyLDUsMTApLGR0LHg9Z3JpZCkpCmNvbG5hbWVzKGRlbnNEaXN0KTwtYygieCIsIm5vcm1hbCIscGFzdGUwKCJ0IixjKDIsNSwxMCkpKQoKZGVuc0Rpc3QgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIGdhdGhlcihkaXN0LGRlbnMsLXgpICU+JQpnZ3Bsb3QoYWVzKHg9eCx5PWRlbnMsY29sb3I9ZGlzdCkpICsKZ2VvbV9saW5lKCkgKwp5bGFiKCJEZW5zaXR5IikKYGBgCgoKdC1kaXN0cmlidXRpb25zIGhhdmUgaGVhdmllciB0YWlscyB0aGVuIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uICRccmlnaHRhcnJvdyQgbGFyZ2VyIHF1YW50aWxlcyBzbyBicm9hZGVyIGludGVydmFscyBmb3IgdGhlIHNhbWUgY29uZmlkZW5jZSBsZXZlbC4gCgotIFRoaXMgY2FwdHVyZXMgdGhlIGFkZGl0aW9uYWwgdW5jZXJ0YWludHkgZm9yIGVzdGltYXRpbmcgJFMkLiAKCi0gSWYgJG4gXHJpZ2h0YXJyb3cgXGluZnR5JCB0aGVuICR0KGRmKSBccmlnaHRhcnJvdyBOKDAsMSkkCgoKLSBxdWFudGlsZXMgb2YgdGhlICR0JC1kaXN0cmlidXRpb24gY2FuIGJlIGNhbGN1bGF0ZWQgaW4gUiB1c2luZyBgcXRgLiBlLmcuIDk1JSwgOTcuNSUsIDk5LjUlIHF1YW50aWxlIGZvciBhIHQtZGlzdHJpYnV0aW9uIHdpdGggMTQgZGVncmVlcyBvZiBmcmVlZG9tOiAKYGBge3J9CnF0KC45NzUsZGY9MTQpCnF0KGMoLjk1LC45NzUsLjk5NSksZGY9MTQpCmBgYAoKLSBUaGVzZSBxdWFudGlsZXMgY2FuIGJlIHVzZWQgdG8gY2FsY3VsYXRlIDkwJSwgOTUlIGFuZCA5OSUgQ0kuIAoKLSA5Ny41JSBxdWFudGlsZWByIHJvdW5kKHF0KC45NzUsZGY9MTQpLDIpYCBvZiBhIHQtZGlzdHJpYnV0aW9uIHdpdGggJG4tMT0xNCQgZGVncmVlcyBvZiBmcmVlZG9tIGlzIGluZGVlZCBsYXJnZXIgdGhhbiB0aGF0IG9mIGEgc3RhbmRhcmQgTm9ybWFsIGRpc3RyaWJ1dGlvbiBgciByb3VuZChxbm9ybSguOTc1KSwyKWAuCgotLS0KCiMjIyBDb25maWRlbmNlIGludGVydmFsIGJhc2VkIG9uIHRoZSB0LWRpc3RyaWJ1dGlvbgoKVGhlICQxMDBcJSAoMS1cYWxwaGEpJCBDSSBmb3IgdGhlIG1lYW4gJFxtdSQgb2YgYSAKTm9ybWFsIGRpc3RyaWJ1dGVkIHJhbmRvbSB2YXJpYWJsZSAkWCQgd2l0aCB1bmtub3duIHZhcmlhbmNlIGlzCgpcYmVnaW57ZXF1YXRpb24qfQpcbGVmdFtcYmFye1h9IC0gdF97bi0xLCBcYWxwaGEvMn0gXGZyYWN7c317XHNxcnR7bn19ICwgXGJhcntYfSArIHRfe24tMSwKXGFscGhhLzJ9IFxmcmFje3N9e1xzcXJ0e259fVxyaWdodF0KXGVuZHtlcXVhdGlvbip9CgotIFdlIHNpbXBseSByZXBsYWNlIHRoZSAkKDEtXGFscGhhLzIpMTAwXCUkIHF1YW50aWxlIG9mIHRoZSBOb3JtYWwgZGlzdHJpYnV0aW9uIGJ5IHRoYXQgb2YgdGhlIHQtZGlzdHJpYnV0aW9uIHdpdGggJG4tMSQgZGVncmVlcyBvZiBmcmVlZG9tLgoKIyMjIyBDYXB0b3ByaWwgZXhhbXBsZQoKCjk1JSBDSSBmb3IgdGhlIGF2ZXJhZ2UgYmxvb2QgcHJlc3N1cmUgY2hhbmdlIGJlY29tZXMKCmBgYHtyfQptZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkgLSAgcXQoLjk3NSxkZj0xNCkqc2QoY2FwdG9wcmlsJGRlbHRhU0JQKS9zcXJ0KDE1KQptZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkgKyBxdCguOTc1LGRmPTE0KSpzZChjYXB0b3ByaWwkZGVsdGFTQlApL3NxcnQoMTUpCmBgYAoKVGhlIDk5JSBDSSBpcyBnaXZlbiBieQpgYGB7cn0KbWVhbihjYXB0b3ByaWwkZGVsdGFTQlApIC0gIHF0KC45OTUsZGY9MTQpKnNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydCgxNSkKbWVhbihjYXB0b3ByaWwkZGVsdGFTQlApICsgcXQoLjk5NSxkZj0xNCkqc2QoY2FwdG9wcmlsJGRlbHRhU0JQKS9zcXJ0KDE1KQpgYGAKCk5vdGUsIHRoYXQgemVybyBpcyBvdXRzaWRlIHRoZSBpbnRlcnZhbCBhbmQgdGhhdCB0aGUgZW50aXJlIGludGVydmFsIGlzIG5lZ2F0aXZlIGluZGljYXRpbmcgdGhhdCB0aGVyZSBpcyBvbiBhdmVyYWdlIGEgbGFyZ2UgZWZmZWN0IGJ5IGFkbWluaXN0cmF0aW5nIGNhcHRvcHJpbCBvbiB0aGUgYmxvb2QgcHJlc3N1cmUgb2YgcGF0aWVudHMgd2l0aCBoeXBlcnRlbnNpb24uIAoKLS0tCgojIyMgSW50ZXJwcmV0YXRpb24gb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgCgotIFdlIHdpbGwgcmV2aXNpdCB0aGUgcmVzdWx0cyBmb3Igc2FtcGxpbmcgbG9nMiBjaG9sZXN0ZXJvbCBsZXZlbHMgZnJvbSB0aGUgbGFyZ2UgTkhBTkVTIHN0dWR5LiBXZSBmaXJzdCBmb2N1cyBvbiB0aGUgcmVwZWF0ZWQgZXhwZXJpbWVudHMgd2l0aCBzYW1wbGUgc2l6ZSAxMC4gCgpgYGB7cn0KcmVzJG48LWFzLmNoYXJhY3RlcihyZXMkbikgJT4lIGFzLmRvdWJsZShyZXMkbikKcmVzJGxsPC1yZXMkbWVhbi1xdCgwLjk3NSxkZj1yZXMkbi0xKSpyZXMkc2UKcmVzJHVsPC1yZXMkbWVhbitxdCgwLjk3NSxkZj1yZXMkbi0xKSpyZXMkc2UKbXU8LWZlbSREaXJlY3RDaG9sJT4lbG9nMiU+JW1lYW4KcmVzJGluc2lkZTwtcmVzJGxsPD1tdSAmIG11PD1yZXMkdWwKcmVzJG4gPC0gYXMuZmFjdG9yKHJlcyRuKQpyZXMgJT4lIGdyb3VwX2J5KG4pICU+JSBzdW1tYXJpemUoY292ZXJhZ2U9bWVhbihpbnNpZGUpKSAlPiUgc3ByZWFkKG4sY292ZXJhZ2UpIApgYGAKCldlIG9ic2VydmUgdGhhdCBhbGwgdGhlIGNvdmVyYWdlcyBvZiB0aGUgaW50ZXJ2YWxzIGFyZSBub3cgY29udHJvbGxlZCBhdCB0aGVpciBub21pbmFsIDk1JSBjb25maWRlbmNlIGxldmVsLgoKYGBge3J9CnJlcyAlPiUgCiAgZmlsdGVyKG49PTEwKSAlPiUgCiAgc2xpY2UoMToyMCkgJT4lCiAgZ2dwbG90KGFlcyh4PXNhbXBsZSx5PW1lYW4sY29sb3I9aW5zaWRlKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bWVhbi1xdCgwLjk3NSxkZj05KSpzZSx5bWF4PW1lYW4rcXQoMC45NzUsZGY9OSkqc2UpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBmZW0kRGlyZWN0Q2hvbCU+JSBsb2cyICU+JSBtZWFuKSArIAogIGdndGl0bGUoIjIwIENJIGZvciBOPTEwIikgKyAKICB5bGltKHJhbmdlKGZlbSREaXJlY3RDaG9sICU+JSBsb2cyKSkKYGBgCgohW10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9ubWV0aC4yNjU5LnBkZil7d2lkdGg9MTAwJX0KCi0tLQoKIyMgUmVwb3J0aW5nPwoKLSBBbHdheXMgcmVwb3J0IHRoZSB1bmNlcnRhaW50eSBvbiB0aGUgcmVzdWx0cyEKCi0gQ29uY2x1c2lvbnMgYmFzZWQgb24gYSBwb2ludCBlc3RpbWF0ZSBjYW4gYmUgdmVyeSBtaXNsZWFkaW5nLiAKCi0gVXBvbiBhIHN0YXRpc3RpY2FsIGFuYWx5c2lzIHdlIHRoZXJlZm9yZSBhbHdheXMgcmVwb3J0IGNvbmZpZGVuY2UgaW50ZXJ2YWxzCgotIFRoZXkgYXJlIHNtYWxsIGVub3VnaCB0byBiZSBpbmZvcm1hdGl2ZSBidXQgYWxtb3N0IG5ldmVyIG1pc2xlYWRpbmcKCi0gVGhleSBmb3JtIGEgZ29vZCB0cmFkZS1vZmYgYmV0d2VlbiBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgYW5kIGJpb2xvZ2ljYWwgcmVsZXZhbmNlLiAKCi0gV2UgY29uY2x1ZGUgdGhhdCB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXIgbGF5cyBpbiB0aGUgaW50ZXJ2YWwgYW5kIGtub3cgdGhhdCB0aGlzIHN0YXRlbWVudCBob2xkcyB3aXRoIGEgcHJvYmFiaWxpdHkgb2YgOTUlIGZvciByYW5kb20gc2FtcGxlcy4gCgojIyMgQ2FwdG9wcmlsIGV4YW1wbGUKCldlIGNvbmNsdWRlIHRoYXQgdGhlIGJsb29kIHByZXNzdXJlIGRlY3JlYXNlcyBvbiBhdmVyYWdlIHdpdGggCmByIGFicyhyb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCksMSkpYG1tSGcgdXBvbiBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbCAoOTUlIENJIFtgciBwYXN0ZShyb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkrcXQoYygwLjAyNSwuOTc1KSxuLTEpKnNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydChuKSwxKSxjb2xsYXBzZT0iLCIpYF1tbUhnKS4KCkJhc2VkIG9uIHRoZXNlIHJlc3VsdHMgaXQgaXMgb2J2aW91cyB0aGF0IHRoZSB0cmVhdG1lbnQgY2F1c2VzIGEgc3Ryb25nIGJsb29kIHByZXNzdXJlIGRyb3AgZm9yIHBhdGllbnRzIHdpdGggaHlwZXJ0ZW5zaW9uLiAKCiMgSHlwb3RoZXNpcyB0ZXN0cwoKIyMgQ2FwdG9wcmlsIEV4YW1wbGU6ClJlc2VhcmNoZXJzIHdhbnQgdG8gYXNzZXNzIGlmIHRoZSBkcnVnIGNhcHRvcHJpbCBkZWNyZWFzZXMgdGhlIGJsb29kIHByZXNzdXJlIGZvciBwYXRpZW50cyB3aXRoIGh5cGVydGVuc2lvbi4gIAoKLSBJcyB0aGVyZSBuby9hbiBlZmZlY3Qgb2YgYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwgb24gdGhlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlPyAKCi0gSXQgaXMgbm90IG9idmlvdXMgdG8gZHJhdyBzdWNoIGNvbmNsdXNpb25zIGJhc2VkIG9uIGEgc21hbGwgc2FtcGxlCgotIEl0IGlzIHVuY2VydGFpbiBpZiB3ZSBjYW4gZ2VuZXJhbGl6ZWQgdGhlIG9ic2VydmF0aW9ucyBpbiB0aGUgc2FtcGxlIHRvd2FyZHMgdGhlIHBvcHVsYXRpb24hIAoKLSBJcyB0aGUgYXBwYXJlbnQgYmVuZWZpY2lhbCBlZmZlY3Qgc3lzdGVtYXRpYyBvciByYW5kb20/IAoKYGBge3J9CmNhcHRvcHJpbFRpZHkgJT4lIAogIGZpbHRlcih0eXBlJWluJWMoIlNCUGEiLCJTQlBiIikpICU+JQogIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLGxldmVscz1jKCJTQlBiIiwiU0JQYSIpKSklPiUKICBnZ3Bsb3QoYWVzKHg9dHlwZSx5PWJwKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBpZCkpICsKICBnZW9tX3BvaW50KCkKYGBgCgpgYGB7cn0KY2FwdG9wcmlsJGRlbHRhU0JQPC1jYXB0b3ByaWwkU0JQYS1jYXB0b3ByaWwkU0JQYgpjYXB0b3ByaWwlPiUKICBnZ3Bsb3QoYWVzKHg9IlN5c3RvbGljIGJsb29kIHByZXNzdXJlIix5PWRlbHRhU0JQKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikrCiAgeWxhYigiRGlmZmVyZW5jZSAobW0gbWVyY3VyeSkiKSArCiAgeGxhYigiIikKYGBgCgoKLSBUaGUgYXZlcmFnZSBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlICRcYmFyIFgkIGlzIGEgbmF0dXJhbCBiYXNpcyB0byBiYXNlIG91ciBkZWNpc2lvbiBvbi4gCgokJFxiYXIgeFx0ZXh0ez1gciByb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCksMilgIChzPWByIHJvdW5kKHNkKGNhcHRvcHJpbCRkZWx0YVNCUCksMilgLCBTRT1gciByb3VuZChzZChjYXB0b3ByaWwkZGVsdGFTQlApL3NxcnQoMTUpLDIpYCl9JCQKCi0gSXQgaXMgbm90IGVub3VnaCB0aGF0ICRcYmFye3h9PCAwJCB0byBjb25jbHVkZSB0aGF0IHRoZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBpcyBvbiBhdmVyYWdlIGxvd2VyIHVwb24gYWRtaW5pc3RyYXRpbmcgY2FwdG9wcmlsICphdCB0aGUgbGV2ZWwgb2YgdGhlIGVudGlyZSBwb3B1bGF0aW9uKi4KCi0gVG8gZ2VuZXJhbGl6ZSB0aGUgZWZmZWN0IHdlIG9ic2VydmUgaW4gdGhlIHNhbXBsZSB0byB0aGUgcG9wdWxhdGlvbiBpdCBoYXMgdG8gYmUgc3VmZmljaWVudGx5IGxhcmdlLgoKLSBCdXQsIGhvdyBsYXJnZT8gCgotLS0KCiMjIyBIeXBvdGhlc2lzIHRlc3RzIAoKLSBGb3IgdGhpcyBwdXJwb3NlIHN0YXRpc3RpY2FsIGh5cG90aGVzaXMgdGVzdHMgaGF2ZSBiZWVuIGRldmVsb3BlZAotIFRoZXkgZ2l2ZSBhIGJsYWNrL3doaXRlIGFuc3dlciAKLSBJdCBpcyBhbG1vc3QgaW1wb3NzaWJsZSB0byByZWFkIGEgc2NpZW50aWZpYyBwdWJsaWNhdGlvbiB3aXRob3V0IHJlc3VsdHMgb2Ygc3RhdGlzdGljYWwgdGVzdHMuCi0gQWNjb3JkaW5nIHRvIHRoZSAqZmFsc2lmaWNhdGlvbiBwcmluY2lwbGUqIG9mIFBvcHBlciB3ZSBjYW4gbmV2ZXIgcHJvdmUgYSBoeXBvdGhlc2lzIGJhc2VkIG9uIGRhdGEuIAoKICAgIC0gSGVuY2Ugd2Ugd2lsbCBpbnRyb2R1Y2UgdHdvIGh5cG90aGVzZXM6IGEgbnVsbCBoeXBvdGhlc2lzICRIXzAkIGFuZCBhbiBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzICRIXzEkLgogICAgCiAgICAtIFdlIHdpbGwgdHJ5IHRvIGZhbHNpZnkgdGhlIG51bGwgaHlwb3RoZXNpcyBiYXNlZCBvbiB0aGUgc3RhdGlzdGljYWwgdGVzdC4gCiAgIAojIyMjIENhcHRvcHJpbCAKCi0gQmFzZWQgb24gdGhlIHNhbXBsZSB3ZSBjYW5ub3QgcHJvdmUgdGhhdCB0aGVyZSBpcyBhbiBlZmZlY3Qgb2YgYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwgKCRIXzEkICwgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcykuCgotIFdlIHRoZXJlZm9yZSBzdXBwb3NlIHRoYXQgdGhlcmUgaXMgbm8gZWZmZWN0IG9mIGNhcHRvcHJpbC4KCiAgICAtIFdlIHJlZmVyIHRvIHRoaXMgYXMgdGhlIG51bGwgaHlwb3RoZXNpcyAkSF8wJC4KCiAgICAtIEZhbHNpZnkgKCJ0cnkgdG8gcmVqZWN0IikgdGhlICRIXzAkLiAKICAgIAogICAgLSBIb3cgbGlrZWx5IGlzIGl0IHRvIG9ic2VydmUgYW4gZWZmZWN0IHRoYXQgaXMgYXQgbGVhc3QgYXMgbGFyZ2UgYXMgd2hhdCB3ZSBoYXZlIHNlZW4gaW4gdGhlIHNhbXBsZSBpbiBhIHJhbmRvbSBzYW1wbGUgd2hlbiAgJEhfMCQgaXMgdHJ1ZT8gICAKICAgIAotLS0KCiAgICAKIyMjIyBQZXJtdXRhdGlvbiB0ZXN0IAoKCi0gVW5kZXIgJEhfMCQgdGhlIGJsb29kIHByZXNzdXJlIG1lYXN1cmVtZW50cyBiZWZvcmUgYW5kIGFmdGVyIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsIGFyZSB0d28gYmFzZSBsaW5lIGJsb29kIHByZXNzdXJlIG1lYXN1cmVtZW50cyBmb3IgYSBwYXRpZW50CgotIFVuZGVyIEgkXzAkIHdlIGNhbiBzaHVmZmxlIChwZXJtdXRlKSB0aGUgYmxvb2QgcHJlc3N1cmUgbWVhc3VyZW1lbnRzIGZvciBlYWNoIHBhdGllbnQuIAoKCmBgYHtyfQpjYXB0b3ByaWxTYW1wPC1jYXB0b3ByaWwKcGVybTwtc2FtcGxlKGMoRkFMU0UsVFJVRSksMTUscmVwbGFjZT1UUlVFKQpjYXB0b3ByaWxTYW1wJFNCUGFbcGVybV08LWNhcHRvcHJpbCRTQlBiW3Blcm1dCmNhcHRvcHJpbFNhbXAkU0JQYltwZXJtXTwtY2FwdG9wcmlsJFNCUGFbcGVybV0KY2FwdG9wcmlsU2FtcCRkZWx0YVNCUCA8LSBjYXB0b3ByaWxTYW1wJFNCUGEtY2FwdG9wcmlsU2FtcCRTQlBiCmNhcHRvcHJpbFNhbXAgJT4lIAogIGdhdGhlcih0eXBlLGJwLC1pZCkgJT4lCiAgZmlsdGVyKHR5cGUlaW4lYygiU0JQYSIsIlNCUGIiKSkgJT4lCiAgbXV0YXRlKHR5cGU9ZmFjdG9yKHR5cGUsbGV2ZWxzPWMoIlNCUGIiLCJTQlBhIikpKSU+JQogIGdncGxvdChhZXMoeD10eXBlLHk9YnApKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGlkKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCgoKCmBgYHtyfQpkYXRhLmZyYW1lKGRlbHRhU0JQPWMoY2FwdG9wcmlsJGRlbHRhU0JQLGNhcHRvcHJpbFNhbXAkZGVsdGFTQlApLHNodWZmbGVkPXJlcChjKEZBTFNFLFRSVUUpLGVhY2g9MTUpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2h1ZmZsZWQseT1kZWx0YVNCUCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpKwogIHN0YXRfc3VtbWFyeShmdW4ueT1tZWFuLCBnZW9tPSJwb2ludCIsIHNoYXBlPTE5LCBzaXplPTMsIGNvbG9yPSJyZWQiLCBmaWxsPSJyZWQiKSArCiAgeWxhYigiRGlmZmVyZW5jZSAobW0gbWVyY3VyeSkiKSAKYGBgCgpBbmQgd2UgcGVybXV0ZSBhZ2FpbgoKCmBgYHtyfQpjYXB0b3ByaWxTYW1wPC1jYXB0b3ByaWwKcGVybTwtc2FtcGxlKGMoRkFMU0UsVFJVRSksMTUscmVwbGFjZT1UUlVFKQpjYXB0b3ByaWxTYW1wJFNCUGFbcGVybV08LWNhcHRvcHJpbCRTQlBiW3Blcm1dCmNhcHRvcHJpbFNhbXAkU0JQYltwZXJtXTwtY2FwdG9wcmlsJFNCUGFbcGVybV0KY2FwdG9wcmlsU2FtcCRkZWx0YVNCUCA8LSBjYXB0b3ByaWxTYW1wJFNCUGEtY2FwdG9wcmlsU2FtcCRTQlBiCgpjYXB0b3ByaWxTYW1wICU+JSAKICBnYXRoZXIodHlwZSxicCwtaWQpICU+JQogIGZpbHRlcih0eXBlJWluJWMoIlNCUGEiLCJTQlBiIikpICU+JQogIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLGxldmVscz1jKCJTQlBiIiwiU0JQYSIpKSklPiUKICBnZ3Bsb3QoYWVzKHg9dHlwZSx5PWJwKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBpZCkpICsKICBnZW9tX3BvaW50KCkKCmRhdGEuZnJhbWUoZGVsdGFTQlA9YyhjYXB0b3ByaWwkZGVsdGFTQlAsY2FwdG9wcmlsU2FtcCRkZWx0YVNCUCksc2h1ZmZsZWQ9cmVwKGMoRkFMU0UsVFJVRSksZWFjaD0xNSkpICU+JQogIGdncGxvdChhZXMoeD1zaHVmZmxlZCx5PWRlbHRhU0JQKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55PW1lYW4sIGdlb209InBvaW50Iiwgc2hhcGU9MTksIHNpemU9MywgY29sb3I9InJlZCIsIGZpbGw9InJlZCIpICsKICB5bGFiKCJEaWZmZXJlbmNlIChtbSBtZXJjdXJ5KSIpIApgYGAKCgotIFdlIHdpbGwgZG8gdGhpcyAxMDAwMCB0aW1lcyBhbmQgd2Ugd2lsbCBrZWVwIHRyYWNrIG9mIHRoZSBtZWFuLgotIFdlIGJhc2ljYWxseSBvbmx5IGhhdmUgdG8gc3dhcCB0aGUgc2lnbnMgb2YgdGhlIG9ic2VydmVkIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2VzICR4JCB3aGVuIHdlIHNodWZmbGUuICAKCmBgYHtyfQojZ2VuZXJhdGUgYSBtYXRyaXggd2l0aCAxNSByb3dzIGFuZCAxMDAwMCBjb2x1bW5zIHdoaWNoIGNvbnNpc3Qgb2YgLTEgYW5kIDEKcGVybUg8LXNhbXBsZShjKC0xLDEpLDE1MDAwMCxyZXBsYWNlPVRSVUUpCmRpbShwZXJtSCk8LWMoMTUsMTAwMDApCgojY2FsY3VsYXRlIHRoZSBtZWFucyBmb3IgdGhlIHBlcm11dGVkIGRhdGEKbXVQZXJtPC1jb2xNZWFucyhwZXJtSCpjYXB0b3ByaWwkZGVsdGFTQlApCm11UGVybSAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZ2dwbG90KGFlcyh4PS4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PW1lYW4oY2FwdG9wcmlsJGRlbHRhU0JQKSxjb2w9ImJsdWUiKQpgYGAKCi0gV2Ugb2JzZXJ2ZSB0aGF0IG5vdCBvbmUgb2YgdGhlIG1lYW5zIHRoYXQgd2VyZSBvYnRhaW5lZCB1bmRlciAkSF8wJCAoYnkgcGVybXV0YXRpb24pIHdlcmUgYXMgZXh0cmVtZSBhcyB0aGUgc2FtcGxlIG1lYW4gd2Ugb2JzZXJ2ZWQgaW4gdGhlIGNhcHRvcHJpbCBzdHVkeS4gCgotIFNvIHRoZSBwcm9iYWJpbGl0eSB0byBvYnNlcnZlIGEgYmxvb2QgcHJlc3N1cmUgZHJvcCB0aGF0IGlzIGxhcmdlciB0aGVuIHRoZSBvbmUgaW4gdGhlIGNhcHRvcHJpbCBzdHVkeSBpbiBhIHJhbmRvbSBzYW1wbGUgZ2VuZXJhdGVkIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMgaXMgIHNtYWxsZXIgdGhlbiAxIG91dCBvZiAxMDAwMC4gCgpTbyB3ZSBoYXZlIHN0cm9uZyBldmlkZW5jZSB0aGF0ICRIXzAkIGlzIGluY29ycmVjdCBhbmQgd2UgdGh1cyB3ZSByZWplY3QgaXQgYW5kIGNvbmNsdWRlICRIXzEkOiBUaGVyZSBpcyBhbiBlZmZlY3Qgb2YgYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwgb24gdGhlIGJsb29kIHByZXNzdXJlIG9mIHBhdGllbnRzIHdpdGggaHlwZXJ0ZW5zaW9uLgoKLS0tCgojIyMgUGl2b3QKCi0gSW4gcHJhY3RpY2Ugd2UgYWx3YXlzIHVzZSBzdGF0aXN0aWNzIHRoYXQgYmFsYW5jZSB0aGUgZWZmZWN0IHNpemUgKGF2ZXJhZ2UgZGlmZmVyZW5jZSkgdG8gdGhlIG5vaXNlIChzdGFuZGFyZCBlcnJvcikgCgotIFdoZW4gd2UgZmFsc2lmeSB0aGUgbnVsbCBoeXBvdGhlc2lzLCB3ZSBzdGFuZGFyZGl6ZSB0aGUgbWVhbiBhcm91bmQgJFxtdV8wPTAkIHRoZSBtZWFuIHVuZGVyICRIXzAkICAKCiQkdD1cZnJhY3tcYmFyIFgtXG11XzB9e3NlX3tcYmFyIFh9fSQkCgotIGZvciB0aGUgY2FwdG9wcmlsIGV4YW1wbGUgdGhpcyBiZWNvbWVzOiAKJCRcZnJhY3tgciByb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCksMilgLTB9e2ByIHJvdW5kKHNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydCgxNSksMilgfT1gciByb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvKHNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydCgxNSkpLDIpYCQkCgoKV2Ugbm93IGRldGVybWluZSB0aGUgbnVsbCBkaXN0cmlidXRpb24gb2YgdGVzdCBzdGF0aXN0aWMgdCB3aXRoIHBlcm11dGF0aW9uLgoKYGBge3J9CmRlbHRhUGVybXM8LXBlcm1IKmNhcHRvcHJpbCRkZWx0YVNCUAp0UGVybTwtY29sTWVhbnMoZGVsdGFQZXJtcykvKGFwcGx5KGRlbHRhUGVybXMsMixzZCkvc3FydCgxNSkpCnRPcmlnPC1tZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvc2QoY2FwdG9wcmlsJGRlbHRhU0JQKSpzcXJ0KDE1KQoKdFBlcm1QbG90PC0gdFBlcm0gJT4lIAogIGFzLmRhdGEuZnJhbWUgJT4lIGdncGxvdChhZXMoeD0uKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLikpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PXRPcmlnLGNvbD0iYmx1ZSIpCnRQZXJtUGxvdApgYGAKCi0gQWdhaW4sIG5vbmUgb2YgdGhlIHBlcm11dGF0aW9ucyBnaXZlcyBhIHQtc3RhdGlzdGljIGFzIGV4dHJlbWUgYXMgdGhlIG9uZSBvYnNlcnZlZCBpbiB0aGUgY2FwdG9wcmlsIHN0dWR5LiAKCldoZW4gdGhlcmUgaXMgbm8gZWZmZWN0IG9mIGNhcHRvcHJpbCBpdCBpcyBuZWFybHkgaW1wb3NzaWJsZSB0byBvYnRhaW4gYSB0ZXN0IHN0YXRpc3RpYyBhcyBleHRyZW1lIGFzIHRoZSBvbmUgdGhhdCB3YXMgb2JzZXJ2ZWQgKCAgdD1gciByb3VuZCh0T3JpZywyKWApLgoKLSBUaGUgcHJvYmFiaWxpdHkgdG8gb2JzZXJ2ZSBhIGxhcmdlciBibG9vZCBwcmVzc3VyZSBkcm9wIHRoZW4gdGhlIG9uZSB3ZSBvYnNlcnZlZCBpbiBvdXIgc2FtcGxlIGluIGEgcmFuZG9tIHNhbXBsZSB1bmRlciAkSF8wJCBpcyBzbWFsbGVyIDEvMTAwMDAuCgotIFdlIHJlZmVyIHRvIHRoaXMgcHJvYmFiaWxpdHkgd2l0aCB0aGUgKnAtdmFsdWUqLgoKLSBJdCBtZWFzdXJlcyB0aGUgc3RyZW5ndGggb2YgdGhlIGV2aWRlbmNlIGFnYWluc3QgdGhlIG51bGw6IHRoZSBzbWFsbGVyIHRoZSBwLXZhbHVlIHRoZSBtb3JlIGV2aWRlbmNlIHdlIGhhdmUgdGhhdCB0aGUgbnVsbCBpcyBub3QgdHJ1ZS4gCgotIFRoZSBkaXN0cmlidXRpb24gaGFzIGEgbmljZSBiZWxsIHNoYXBlLgoKLS0tCgojIyMgSG93IGRvIHdlIGRlY2lkZT8KCldoZW4gaXMgdGhlIHAtdmFsdWUgc3VmZmljaWVudGx5IHNtYWxsIHRvIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgc3Ryb25nIGV2aWRlbmNlIGFnYWluc3QgdGhlIG51bGwgaHlwb3RoZXNpcz8gCgotIFdlIHR5cGljYWxseSB3b3JrIGF0IGEgc2lnbmlmaWNhbmNlIGxldmVsIG9mICRcYWxwaGE9MC4wNSQKCi0gV2Ugc3RhdGUgdGhhdCB3ZSBjb25kdWN0ZWQgdGhlIHRlc3QgYXQgdGhlIDUlIHNpZ25pZmljYW5jZSBsZXZlbAoKLS0tCgojIyMgUGVybXV0YXRpb24gdGVzdHMgYXJlIGNvbXB1dGF0aW9uYWxseSBkZW1hbmRpbmcgCgotIENhbiB3ZSBhc3Nlc3MgaG93IGV4dHJlbWUgdGhlIGJsb29kIHByZXNzdXJlIGRyb3Agd2FzIHdpdGhvdXQgcGVybXV0YXRpb24/IAoKLSBXZSBrbm93IHRoYXQgdGhlIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2VzIGFyZSBhcHByb3hpbWF0ZWx5IE5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBzbwoKJCR0PVxmcmFje1xiYXIgWCAtIFxtdX17c2Vfe1xiYXIgWH19JCQKCmZvbGxvd3MgYSB0LWRpc3RyaWJ1dGlvbiAod2l0aCAxNCBkZiBmb3IgdGhlIGNhcHRvcHJpbCBleGFtcGxlKS4gCgoKLSBVbmRlciBIJF8wJCAkXG11PTAkIGFuZCAkJHQ9XGZyYWN7XGJhciBYLTB9e3NlX3tcYmFyIFh9fVxzaW0gZl97VCwxNH0kJAoKYGBge3J9CnRQZXJtUGxvdCArIAogIHN0YXRfZnVuY3Rpb24oZnVuPWR0LGNvbG9yPSJyZWQiLGFyZ3M9bGlzdChkZj0xNCkpCmBgYAoKLSBOb3RlLCB0aGUgcGVybXV0YXRpb24gbnVsbCBkaXN0cmlidXRpb24gaW5kZWVkIGNvcnJlc3BvbmRzIHRvIGEgdC1kaXN0cmlidXRpb24gd2l0aCAxNCBkZWdyZWVzIG9mIGZyZWVkb20uIAoKLSBTbyB3ZSBjYW4gY29uZHVjdCB0aGUgc3RhdGlzdGljYWwgdGVzdCB1c2luZyBzdGF0aXN0aWNhbCBtb2RlbGxpbmcgb2YgdGhlIGRhdGEuIAoKLSBXZSBuZWVkIHRvIG1ha2UgYXNzdW1wdGlvbnMgZm9yIHRoaXMsIHdoaWNoIHdlIHZlcmlmeSBpbiB0aGUgZGF0YSBleHBsb3JhdGlvbiBwaGFzZS4gCgoKLS0tCgoKIyMgSHlwb3RoZXNlcwoKPGRldGFpbHM+PHN1bW1hcnk+Q2xpY2sgdG8gc2VlIG1vcmUgZm9ybWFsIGRldGFpbHMgPC9zdW1tYXJ5PjxwPgoKVHJhbnNsYXRlIHRoZSByZXNlYXJjaCBxdWVzdGlvbiB0byBhIG51bGwgaHlwb3RoZXNpcyAoJEhfMCQpIGFuZCBhbiBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzICgkSF8xJCkKCkZpcnN0IHRoZSB3ZSBuZWVkIHRvIHRyYW5zbGF0ZSB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gdG8gYSBwYXJhbWV0ZXJpemVkIHN0YXRpc3RpY2FsIG1vZGVsLiAgCgotIEZyb20gdGhlIGV4cGVyaW1lbnRhbCBkZXNpZ24gaXQgZm9sbG93cyB0aGF0ICAkJFhfMSwuLi4sWF9uIFx0ZXh0eyBpLmkuZCB9IGYoWCksJCQgd2l0aCAkZihYKSQgdGhlIGRlbnNpdHkgZnVuY3Rpb24gb2YgYmxvb2QgcHJlc3N1cmUgZGlmZmVyZW5jZXMuCgotICoqU2ltcGxpZnkqKjogYXNzdW1lIHRoYXQgJGYoWCkkIGlzIGtub3duIGV4Y2VwdCBmb3IgYW4gZmluaXRlIGRpbWVuc2lvbmFsIHNldCBvZiBwYXJhbWV0ZXJzICRcbWF0aGJme1x0aGV0YX0kIHRoYXQgc3RpbGwgaGFzIHRvIGJlIGVzdGltYXRlZCAocGFyYW1ldHJpYyBzdGF0aXN0aWMgbW9kZWwpLgo8L3A+PC9kZXRhaWxzPgoKIyMjIENhcHRvcHJpbCBleGFtcGxlIAoKPGRldGFpbHM+PHN1bW1hcnk+Q2xpY2sgdG8gc2VlIG1vcmUgZm9ybWFsIGRldGFpbHMgPC9zdW1tYXJ5PjxwPgokWCBcc2ltIE4oXG11LFxzaWdtYV4yKSQgd2l0aCAkXG1hdGhiZntcdGhldGF9PShcbXUsXHNpZ21hXjIpJCwgdGhlIG1lYW4gJFxtdSQgYW5kIHZhcmlhbmNlICRcc2lnbWFeMiQuCgpUaGUgcmVzZWFyY2ggcXVlc3Rpb24gaXMgbm93IHRyYW5zbGF0ZWQgaW4gdGVybXMgb2YgdGhlIGF2ZXJhZ2UgYmxvb2QgcHJlc3N1cmUgZHJvcDogJFxtdT1FX2ZbWF0kLgoKVGhlICoqYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyoqIGlzIGZvcm11bGF0ZWQgaW4gdGVybXMgb2YgYSBwYXJhbWV0ZXIgb2YgJGYoWCkkIGFuZCBoYXMgdG8gZXhwcmVzcyB3aGF0IHRoZSByZXNlYXJjaGVycyB3YW50IHRvIHByb3ZlIHdpdGggdGhlIHN0dWR5LgoKLSBIZXJlOgokJEhfMTogXG11PDAuJCQgT24gYXZlcmFnZSB0aGUgYmxvb2QgcHJlc3N1cmUgb2YgcGF0aWVudHMgd2l0aCBoeXBlcnRlbnNpb24gZGVjcmVhc2VzIHVwb24gYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwuIAoKClRoZSAqKm51bGwgaHlwb3RoZXNpcyoqIGdlbmVyYWxseSBleHByZXNzZXMgYSBudWxsIGNvbmRpdGlvbiwgaS5lLiB3aGVuIG5vdHRpbmcgZXhjZXB0aW9uYWwgaGFwcGVucy4gCgotIFJlc2VhcmNoZXJzIHR5cGljYWxseSBhaW0gdG8gcHJvdmUgdmlhIGVtcGlyaWNhbCByZXNlYXJjaCB0aGF0IG9ic2VydmluZyB0aGUgZGF0YSB1bmRlciB0aGUgbnVsbCBpcyBoaWdobHkgdW5saWtlbHkgc28gdGhhdCB0aGV5IGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpczoKKipGYWxzaWZpY2F0aW9uIHByaW5jaXBsZSoqLgoKLSBUaGUgKipudWxsIGh5cG90aGVzaXMgaXMgdHlwaWNhbGx5IGV4cHJlc3NlZCB3aXRoIHRoZSBzYW1lIG1vZGVsIHBhcmFtZXRlciBhcyB0aGUgb25lIHVzZWQgZm9yICRIXzEkLioqCgotIEhlcmU6CiQkSF8wIDogXG11PTAkJCBpLmUuIG9uIGF2ZXJhZ2UgdGhlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIHJlbWFpbnMgdW5jaGFuZ2VkIHVwb24gYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwuIAoKPC9wPjwvZGV0YWlscz4KCi0tLQoKIyMgVGVzdC1zdGF0aXN0aWMKCjxkZXRhaWxzPjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBtb3JlIGZvcm1hbCBkZXRhaWxzIDwvc3VtbWFyeT48cD4KCk9uY2UgdGhlIHBvcHVsYXRpb24sIHRoZSBwYXJhbWV0ZXJzLCBhbmQsICRIXzAkIGFuZCAkSF8xJCBhcmUgZGV0ZXJtaW5lZCB0aGUgY29uY2VwdCBvZiBoeXBvdGhlc2lzIHRlc3RpbmcgaXMgYXMgZm9sbG93czogCgoKQ29uc3RydWN0IGEgdGVzdCBzdGF0aXN0aWMgc28gdGhhdCBpdAoKMS4gbWVhc3VyZXMgZXZpZGVuY2UgaW4gdGhlIHNhbXBsZSwKXHZzcGFjZXsxMHB0fQoyLiBhZ2FpbnN0IHRoZSBudWxsIGh5cG90aGVzaXMsIGFuZApcdnNwYWNlezEwcHR9CjMuIGluIGZhdm91ciBvZiB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcy4KCkEgdGVzdCBzdGF0aXN0aWMgdGh1cyBoYXMgdG8gYmUgYSBmdW5jdGlvbiBvZiB0aGUgb2JzZXJ2YXRpb25zIGluIHRoZSBzYW1wbGUuIAoKPC9wPjwvZGV0YWlscz4KCiMjIyBDYXB0b3ByaWwgZXhhbXBsZQoKPGRldGFpbHM+PHN1bW1hcnk+Q2xpY2sgdG8gc2VlIG1vcmUgZm9ybWFsIGRldGFpbHMgPC9zdW1tYXJ5PjxwPgoKJCRUPVxmcmFje1xiYXJ7WH0tXG11XzB9e1x0ZXh0e1NFfV97XGJhciBYfX0kJApXaXRoICRcbXVfMD0wJCB1bmRlciAkSF8wJCAKCkFnYWluIAoKLSBJZiAkSF8wJCBob2xkcyB0aGVyZSBpcyBubyBlZmZlY3Qgb2YgY2FwdG9wcmlsIG9uIHRoZSBibG9vZCBwcmVzc3VyZSBpbiB0aGUgcG9wdWxhdGlvbiBhbmQgdGhlbiB3ZSBleHBlY3QgdGVzdCBzdGF0aXN0aWMgJFQkIGNsb3NlIHRvIDAuCgotIElmICRIXzEkIGlzIHRydWUgd2UgZXhwZWN0ICRUPDAkLgoKLSBJbiB0aGUgY2FwdG9wcmlsIGV4YW1wbGUgd2Ugb2JzZXJ2ZSAkdD0oLTE4LjkzLTApLzIuMzM9LTguMTIkLgoKLSBJcyAkdCA9IC04LjEyJCBsYXJnZSBlbm91Z2ggaW4gYWJzb2x1dGUgdmFsdWUgdG8gY29uY2x1ZGUgdGhhdCAgJFxtdSA8IDAkIGFuZCB3aXRoIHdoaWNoIGNvbmZpZGVuY2UgY2FuIHdlIG1ha2UgdGhpcyBjb25jbHVzaW9uPyAKCi0gV2Uga25vd24gdGhhdCB0IGZvbGxvd3MgYSB0LWRpc3RyaWJ1dGlvbiB3aXRoIDE0IGQuZi4gdW5kZXIgJEhfMCQgIAoKPC9wPjwvZGV0YWlscz4KCi0tLQoKIyMgcC12YWx1ZQoKVGhlIHAtdmFsdWUgaXMgdGhlIHByb2JhYmlsaXR5IHRvIGJhbGFuY2UgYmV0d2VlbiAkSF8wJCBhbmQgJEhfMSQuCgpUaGUgd2F5IGhvdyB3ZSBjYWxjdWxhdGUgaXQgaXMgY29udGV4dCBkZXBlbmRlbnQgCgotIEZvciB0aGUgY2FwdG9wcmlsIGV4YW1wbGUgd2UgaGF2ZQogICQkCiAgICBwID0gUFxsZWZ0W1QgXGxlcSB0IFxtaWQgSF8wXHJpZ2h0XSA9IFx0ZXh0e1B9XzBcbGVmdFtUXGxlcSB0XHJpZ2h0XSwKICAkJAp3aXRoIHRoZSBpbmRleCAiMCIgaW4gJFx0ZXh0e1B9XzBcbGVmdFsuXHJpZ2h0XSQgaW5kaWNhdGVzIHRoYXQgdGhlIHByb2JhYmlsaXR5IGlzIGNhbGN1bGF0ZWQgdW5kZXIgJEhfMCQuIAoKSXQgZ2l2ZXMgdGhlIHByb2JhYmlsaXR5IHRvIG9ic2VydmUgYSB0ZXN0IHN0YXRpc3RpYyAkVCQgbG93ZXIgb3IgZXF1YWwgdG8gdGhlIHZhbHVlIG9ic2VydmVkIGluIHRoZSBjdXJyZW50IHNhbXBsZSBpbiBhIHJhbmRvbSBzYW1wbGUgdW5kZXIgJEhfMCQKICAgIC0gaS5lLiBhIHRlc3Qgc3RhdGlzdGljICRUJCBpbiB0aGUgcmFuZG9tIHNhbXBsZSB1bmRlciAkSF8wJCB3aXRoIGEgdmFsdWUgdGhhdCBpcyBtb3JlIGV4dHJlbWUsIG1vcmUgaW4gdGhlIGRpcmVjdGlvbiBvZiAkSF8xJCB0aGVuIHRoZSBvbmUgb2JzZXJ2ZWQgaW4gdGhlIGN1cnJlbnQgc2FtcGxlLiAKICAgIAojIyMgQ2FwdG9wcmlsIGV4YW1wbGUKCjxkZXRhaWxzPjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBtb3JlIGZvcm1hbCBkZXRhaWxzIDwvc3VtbWFyeT48cD4KCi0gVGhlICRwJC12YWx1ZSBmb3IgdGhlIGNhcHRvcHJpbCBleGFtcGxlIGlzIGNhbGN1bGF0ZWQgYXMgZm9sbG93cyAKICAkJHA9IFx0ZXh0e1B9XzBcbGVmdFtUXGxlcSAtOC4xMlxyaWdodF09Rl90KC04LjEyOzE0KSA9IDAuNlwgMTBeey02fS4kJAoKICB3aXRoICRGX3QoOzE0KSQgdGhlIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIG9mIGEgdC1kaXN0cmlidXRpb24gd2l0aCAxNCBkZWdyZWVzIG9mIGZyZWVkb206CiAgCiQkRl90KHg7MTQpPVxpbnRcbGltaXRzX3stXGluZnR5fV57eH0gZl90KHg7MTQpLiQkCgphbmQgJGZfdCguOzE0KSQgdGhlIGRlbnNpdHkgZnVuY3Rpb24gb2YgdGhlIHQtZGlzdHJpYnV0aW9uLiAKCgotIFdlIGNhbGN1bGF0ZSB0aGlzIHByb2JhYmlsaXR5IGluIFIgd2l0aCBgcHQoeCxkZilgCgogICAgLSB0aGUgdmFsdWUgb2YgdGhlIG9ic2VydmVkIHRlc3Qgc3RhdGlzdGljIGB4YCBlbgogICAgLSB0aGUgbnVtYmVyIG9mIGRlZ3JlZXMgb2YgZnJlZWRvbSBvZiB0aGUgdC1kaXN0cmlidXRpb24gYGRmYC4KCi0gYHB0KHgsZGYpYCBjYWxjdWxhdGVzIHRoZSBwcm9iYWJpbGl0eSB0byBvYnNlcnZlIGEgdmFsdWUgc21hbGxlciBvciBlcXVhbCB0byB4IHdoZW4gd2Ugd291bGQgZHJhdyBhIHJhbmRvbSBzYW1wbGUgZnJvbSBhIHQtZGlzdHJpYnV0aW9uIHdpdGggZGYgZGVncmVlcyBvZiBmcmVlZG9tLiAKCmBgYHtyfQpuIDwtIGxlbmd0aChjYXB0b3ByaWwkZGVsdGFTQlApCnN0YXQ8LShtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCktMCkvKHNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydChuKSkKc3RhdApwdChzdGF0LG4tMSkKYGBgCgo8L3A+PC9kZXRhaWxzPgoKSW4gcHJhY3RpY2Ugd2Ugd2lsbCBub3QgY2FsY3VsYXRlIHRoZSB0ZXN0IG91cnNlbGYsIGJ1dCB3ZSB3aWxsIHVzZSB0aGUgZnVuY3Rpb24gdC50ZXN0OiAKCmBgYHtyfQp0LnRlc3QoY2FwdG9wcmlsJGRlbHRhU0JQLCBhbHRlcm5hdGl2ZSA9ICJsZXNzIikKYGBgCgpOb3RlLCB0aGF0IHdlIG5lZWQgdG8gc3BlY2lmeSB0aGUgYXJndW1lbnQgYGFsdGVybmF0aXZlPSJsZXNzImAgc28gdGhhdCB0aGUgcC12YWx1ZSB3b3VsZCBiZSBjYWxjdWxhdGVkIGluIHRoZSBsZWZ0IHRhaWwuIAoKVGhlIGZ1bmN0aW9uIGFsc28gZ2l2ZXMgYSBvbmUtc2lkZWQgaW50ZXJ2YWwgYmVjYXVzZSB3ZSB0ZXN0IGluIG9uZSBkaXJlY3Rpb24uCgotLS0KCiMjIyBEZWZpbml0aW9uIG9mIHRoZSBwLXZhbHVlCgpUaGUgKipwLXZhbHVlKiogKGFsc28gcmVmZXJyZWQgdG8gYXMgdGhlICoqb2JzZXJ2ZWQgc2lnbmlmaWNhbmNlIGxldmVsKiopIGlzIHRoZSBwcm9iYWJpbGl0eSB0byBvYnNlcnZlIGEgdGVzdCBzdGF0aXN0aWMgaW4gYSByYW5kb20gc2FtcGxlIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCBpcyBhcyBvciBtb3JlIGV4dHJlbWUgdGhlbiB0aGUgdGVzdCBzdGF0aXN0aWMgb2JzZXJ2ZWQgaW4gdGhlIGN1cnJlbnQgc2FtcGxlLiAKCi0gVGhlIHNtYWxsZXIgdGhlIHByb2JhYmlsaXR5IHRoZSBtb3JlIGV2aWRlbmNlIGFnYWluc3QgJEhfMCQuIAoKLSBOb3RlLCB0aGF0IHRoZSBwLXZhbHVlIGlzICoqbm90KiogdGhlIHByb2JhYmlsaXR5IHRoYXQgbnVsbCBoeXBvdGhlc2lzIGlzIHRydWUhCgotIFRoZSB3b3JkICJleHRyZW1lIiBpbmRpY2F0ZXMgb24gdGhlIGRpcmVjdGlvbiBpbiB3aGljaCB0aGUgdGVzdCBzdGF0aXN0aWMgaXMgbW9yZSBsaWtlbHkgdW5kZXIgdGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMuIAoKLSBJbiB0aGUgZXhhbXBsZSAkSF8xOiBcbXUgPCAwJCBhbmQgd2UgdGh1cyBleHBlY3QgdmVyeSBuZWdhdGl2ZSB2YWx1ZXMgZm9yICR0JCB1bmRlciAkSF8xJC4KCi0gRnJvbSB0aGUgZGVmaW5pdGlvbiBzbWFsbCAkcCQtdmFsdWVzIGluZGljYXRlIHRoYXQgb2JzZXJ2ZWQgdGVzdCBzdGF0aXN0aWMgaXMgdW5saWtlbHkgdW5kZXIgdGhlIGFzc3VtcHRpb24gdGhhdCAkSF8wJCBpcyBjb3JyZWN0LgoKLSBUaHVzIGEgc21hbGwgdmFsdWUgb2YgJHAkLXZhbHVlIG1lYW5zIHRoYXQgd2UgaGF2ZSB0byAqKnJlamVjdCAgJEhfMCQqKiBpbiBmYXZvdXIgb2YgJEhfMSQuCgotIFRoZSB0aHJlc2hvbGQgdGhhdCB3ZSB1c2UgdG8gY29tcGFyZSB0aGUgJHAkLXZhbHVlIHdpdGggaXMgcmVmZXJyZWQgdG8gYXMgdGhlICoqc2lnbmlmaWNhbmNlIGxldmVsKiogYW5kIGlzIGRlbm90ZWQgd2l0aCAkXGFscGhhJC4gCgotIEEgc3RhdGlzdGljYWwgdGVzdCBjb25kdWN0ZWQgb24gdGhlICRcYWxwaGEkIHNpZ25pZmljYW5jZSBsZXZlbCBpcyBhbHNvIHJlZmVycmVkIHRvIGFzIGEgKipsZXZlbC0kXGFscGhhJCB0ZXN0KiouCgpBIHRlc3QgcmVzdWx0IGlzICpzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50KiBpZiAkcDxcYWxwaGEkCgotICRcYWxwaGEkIGlzIGNvbW1vbmx5IHNldCBhdCA1XCUuCgotIFRoZSBzbWFsbGVyIHRoZSBwLXZhbHVlIHRoZSBtb3JlIGBzaWduaWZpY2FudCcgdGhlIHRlc3QgcmVzdWx0IGRldmlhdGVzIGZyb20gd2hhdCBjYW4gYmUgZXhwZWN0ZWQgdW5kZXIgJEhfMCQuIAoKLSBJdCBzdW1tYXJpemVzIHRoZSBldmlkZW5jZSBhZ2FpbnN0IHRoZSBudWxsLiAgCgokJFxiZWdpbnthcnJheX17Y2x9PjAuMTAgJiBcdGV4dHsgbm9uIHNpZ25pZmljYW50IChubyBldmlkZW5jZSl9XFwwLjA1LTAuMTAgJiBcdGV4dHsgbWFyZ2luYWwgc2lnbmlmaWNhbnQsIHdlYWsgZXZpZGVuY2UgKGRvIG5vdCB1c2UgdGhpcyB5b3Vyc2VsZil9XFwwLjAxLTAuMDUgJiBcdGV4dHsgc2lnbmlmaWNhbnR9XFwwLjAwMS0wLjAxICYgXHRleHR7c3Ryb25nbHkgc2lnbmlmaWNhbnR9XFw8MC4wMDEgJiBcdGV4dHsgZXh0cmVtZWx5IHNpZ25pZmljYW50fVxlbmR7YXJyYXl9JCQKCi0tLQoKIyMgQ3JpdGljYWwgdmFsdWUKCmBgYHtyICBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KcGFyKG1hcj1jKDYsNiw2LDIpKQpncmlkIDwtc2VxKC0xMCwxMCwuMDEpCnRjcml0IDwtIHF0KDAuMDUsbi0xKQpyZWplY3QgPC0gYyhncmlkW2dyaWQ8dGNyaXRdLHRjcml0KQpwbG90KGdyaWQsZHQoZ3JpZCxuLTEpLHR5cGU9ImwiLGx3ZD0yLHhsYWI9InQtc3RhdGlzdGljIix5bGFiPSJkZW5zaXR5IixjZXgubGFiPTIsY2V4LmF4aXM9MixjZXgubWFpbj0yKQphYmxpbmUodj1tZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvc2UsY29sPTIsbHdkPTIsbHR5PTIpCmFibGluZSh2PXF0KGMoLjA1KSxuLTEpLGNvbD0yLGx0eT0xLGx3ZD0yKQp0ZXh0KGMoLTUsLTUsNSw1KSxjKC4yMSwuMTksLjIxLC4xOSksbGFiZWw9YygicmVqZWN0aW9uLSIsInJlZ2lvbiIsImFjY2VwdGlvbi0iLCJyZWdpb24iKSxjb2w9YygyLDIsNCw0KSkKYXJyb3dzKC0xMDAsLjQsbWVhbihjYXB0b3ByaWwkZGVsdGFTQlApL3NlLC40LGx3ZD0yLGNvbD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKdGV4dCgtMTAsLjM1LGxhYmVsPSJwLXZhbHVlIixzcnQ9OTAsY29sPTIpCmFycm93cygtMTAwLC4yLHRjcml0LC4yLGx3ZD0yLGNvbD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKdGV4dChwb3M9NCxtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvc2UsLjAyLGxhYmVsPXBhc3RlKCJ0PSIscm91bmQobWVhbihjYXB0b3ByaWwkZGVsdGFTQlApL3NlLDIpKSxjb2w9MikKYXJyb3dzKDEwMCwuMix0Y3JpdCwuMixsd2Q9Mixjb2w9NCxhbmdsZT0yMCxsZW5ndGg9LjEpCnRleHQocG9zPTQsdGNyaXQsLjAyLGxhYmVsPXBhc3RlKCJ0LWNyaXQ9Iixyb3VuZCh0Y3JpdCwyKSksY29sPTIpCnBvbHlnb24oYyhyZWplY3QsdGNyaXQsLTEwKSxjKGR0KHJlamVjdCxuLTEpLDAsMCksY29sPTIsYm9yZGVyPTIpCnRleHQoLTMuNSwuMDUsbGFiZWw9ZXhwcmVzc2lvbihwYXN0ZShhbHBoYSwiPTAuMDUiKSksY29sPTIpCmFycm93cygtMiwwLjAyLC0zLjUsLjA0LGNvbD0yLGx3ZD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKYGBgCgotLS0KCiMjIERlY2lzaW9uIEVycm9ycwoKVGhlIGRlY2lzaW9uIHRvIGFjY2VwdCBvciByZWplY3QgJEhfMCQgaXMgbWFkZSBiYXNlZCBvbiBhIHNpbmdsZSBzYW1wbGUuIApBIHdyb25nIGRlY2lzaW9uIGNvdWxkIGhhdmUgYmVlbiBtYWRlLiAKCmBgYHtyLGVjaG89RkFMU0V9CmxpYnJhcnkoImthYmxlRXh0cmEiKQpEZWNpc2lvbkVycm9ycz1kYXRhLmZyYW1lKENvbmNsdXNpb249YygiQWNjZXB0IEgwIiwiUmVqZWN0IEgwIiksIkgwIj1jKCJPSyIsIlR5cGUgSSAoJFxcYWxwaGEkKSIpLCJIMSI9YygiVHlwZSBJSSAoJFxcYmV0YSQpIiwiT0siKSkKa25pdHI6OmthYmxlKERlY2lzaW9uRXJyb3JzLCxhbGlnbj0iYyIpJT4lCiAga2FibGVfc3R5bGluZyggcG9zaXRpb24gPSAiY2VudGVyIikgJT4lCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIiA9IDEsICJSZWFsaXR5IiA9IDIpKQpgYGAKIC0gVHlwZSBJIGVycm9yLCAkXGFscGhhJDogd3JvbmdseSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyAoZmFsc2UgcG9zaXRpdmUpCiBcdnNwYWNlezEwcHR9CiAtIFR5cGUgSUkgZXJyb3IsICRcYmV0YSQ6IHdyb25nbHkgYWNjZXB0IHRoZSBudWxsIGh5cG90aGVzaXMgCgogLSBEZWNpc2lvbiBpcyBhbHNvIHN0b2NoYXN0aWMhIFNlZSBmaXJzdCBjaGFwdGVyIG9mIHRoZSBjb3Vyc2UgCiAKIyMjIENhcHRvcHJpbCBFeGFtcGxlCgotICRIXzAkOiBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbCBoYXMgbm8gZWZmZWN0IG9uIHRoZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZQoKLSAkSF8xJDogYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwgYW4gYXZlcmFnZSBsZWFkcyB0byBhIGRlY3JlYXNlIGluIGJsb29kIHByZXNzdXJlCgotICoqVHlwZSBJIGVycm9yKio6IHRoZXJlIGlzIG9uIGF2ZXJhZ2Ugbm8gYmxvb2QgcHJlc3N1cmUgZHJvcCB1cG9uIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsLCBidXQgd2UgY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBhbiBlZmZlY3Qgb2YgY2FwdG9wcmlsLiAKLSAqKlR5cGUgSUkgZXJyb3IqKjogdGhlcmUgaXMgb24gYXZlcmFnZSBhIGJsb29kIHByZXNzdXJlIGRyb3AgdXBvbiBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbCwgYnV0IGl0IGlzIG5vdCBwaWNrZWQgdXAgYnkgdGhlIHN0YXRpc3RpY2FsIHRlc3QuIAoKLS0tCgojIyMgVHlwZSBJIGVycm9yIGlzIGNvbnRyb2xsZWQKClRoZSB0eXBlIEkgZXJyb3IgaXMgY29udHJvbGxlZCBieSB0aGUgY29uc3RydWN0aW9uIG9mIHRoZSBzdGF0aXN0aWNhbCB0ZXN0LiAKCiQkXHRleHR7UH1cbGVmdFtcdGV4dHt0eXBlIEkgZXJyb3J9XHJpZ2h0XT1cdGV4dHtQfVxsZWZ0W1x0ZXh0e3JlamVjdCB9SF8wIFxtaWQgSF8wXHJpZ2h0XSA9IFx0ZXh0e1B9XzBcbGVmdFtUPHRfe24tMTsxLVxhbHBoYX1ccmlnaHRdPVxhbHBoYSAkJAoKCi0gVGhlIHNpZ25pZmljYW5jZS1sZXZlbCAkXGFscGhhJCBpcyB0aGUgcHJvYmFiaWxpdHkgdG8gbWFrZSBhIHR5cGUgSSBlcnJvci4KCi0gVGhlIHN0YXRpc3RpY2FsIHRlc3QgZW5zdXJlcyB0aGF0IHRoZSBwcm9iYWJpbGl0eSBvbiBhIHR5cGUgSSBlcnJvciBpcyBjb250cm9sbGVkIGF0IHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgJFxhbHBoYSQuCgotIFRoZSBwcm9iYWJpbGl0eSB0byBjb3JyZWN0bHkgYWNjZXB0ICRIXzAkIGlzICQxLVxhbHBoYSQuCgotIFdlIGNhbiBzaG93IHRoYXQgdGhlIHAtdmFsdWUgdW5kZXIgJEhfMCQgaXMgdW5pZm9ybSBkaXN0cmlidXRlZC4gCgotIFNvIHN0YXRpc3RpY2FsIGh5cG90aGVzaXMgdGVzdGluZyBsZWFkcyB0byBhIHVuaWZvcm0gZGVjaXNpb24gc3RyYXRlZ3kuIAoKV2Ugd2lsbCBpbGx1c3RyYXRlIHRoaXMgaW4gYSBzaW11bGF0aW9uIHN0dWR5CgotIG49MTUKLSAkXG11PTAkIG1tSGcKLSAkXHNpZ21hID05JCBtbUhnCi0gbnVtYmVyIG9mIHNpbXVsYXRpb25zIDEwMDAKCmBgYHtyfQpuc2ltIDwtIDEwMDAwCm4gPC0gMTUKc2lnbWEgPC0gOQptdSA8LSAwCm11MCA8LSAwCmFscGhhPTAuMDUKCiNzaW11bGF0ZSBuc2ltIHNhbXBsZXMgb2Ygc2l6ZSBuCmRlbHRhU2ltIDwtIG1hdHJpeChybm9ybShuKm5zaW0sbXUsc2lnbWEpLG5yb3c9bixuY29sPW5zaW0pCnBTaW0gPC0gYXBwbHkoZGVsdGFTaW0sMixmdW5jdGlvbih4LG11LGFsdGVybmF0aXZlKSB0LnRlc3QoeCxtdT1tdSxhbHRlcm5hdGl2ZT1hbHRlcm5hdGl2ZSkkcC52YWx1ZSxtdT1tdTAsYWx0ZXJuYXRpdmU9Imxlc3MiKQoKbWVhbihwU2ltPGFscGhhKQpwU2ltICU+JSAKICBhcy5kYXRhLmZyYW1lICU+JSAKICBnZ3Bsb3QoYWVzKHg9LikpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsgCiAgeGxpbSgwLDEpCmBgYAoKLSBUaGUgdHlwZSBJIGVycm9yIGlzIGluZGVlZCBhYm91dCAwLjA1IAotIFRoZSBwLXZhbHVlcyBhcmUgdW5pZm9ybQoKLS0tCgojIyMgVHlwZSBJSSBlcnJvcgoKLSBEZXRlcm1pbmUgdGhlIHR5cGUgSUkgZXJyb3IgaXMgbGVzcyBldmlkZW50LiAKLSBXZSBoYXZlIHRvIHJlYXNvbiB1bmRlciAkSF8xJAotIEluIHRoZSBjYXB0b3ByaWwgdm9vcmJlZWxkIGlzICRIXzE6IFxtdTwwJAotIE1hbnkgYWx0ZXJuYXRpdmVzIGFyZSBwb3NzaWJsZQotIFRoZSBkaXN0cmlidXRpb24gdW5kZXIgJEhfMSQgaXMgbm90IGZ1bGx5IHNwZWNpZmllZAoKLSAqd29yay1hcm91bmQ6KiBjaG9vc2Ugb25lIHNwZWNpZmljIGRpc3RyaWJ1dGlvbiB1bmRlciAkSF8xJC4KCiAkJEhfMShcZGVsdGEpOiBcbXU9MC1cZGVsdGEgXHRleHR7IGZvciB9XGRlbHRhPjAuJCQKIAotIGUuZy4gYSBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlIG9mIDIgbW1IZwoKLSAxLXR5cGUgSUkgaXMgYWxzbyByZWZlcnJlZCB0byBhcyB0aGUgcG93ZXIuIEl0IGlzIHRoZSBwcm9iYWJpbGl0eSB0byBwaWNrIHVwIHRoZSBhbHRlcm5hdGl2ZS4gCgotIEl0IGlzIG5vdCBndWFyYW50ZWVkIGJ5IHRoZSBkZXNpZ24gb2YgdGhlIHRlc3QKCi0gSXQgZGVwZW5kcyBvbiB0aGUgZXhwZXJpbWVudGFsIGRlc2lnbiBvZiB0aGUgc3R1ZHkKCgpgYGB7cn0KbnNpbSA8LSAxMDAwMApuIDwtIDE1CnNpZ21hIDwtIDkKbXUgPC0gLTIKbXUwIDwtIDAKYWxwaGE9MC4wNQoKI3NpbXVsYXRlIG5zaW0gc2FtcGxlcyBvZiBzaXplIG4KZGVsdGFTaW0gPC0gbWF0cml4KHJub3JtKG4qbnNpbSxtdSxzaWdtYSksbnJvdz1uLG5jb2w9bnNpbSkKcFNpbSA8LSBhcHBseShkZWx0YVNpbSwyLGZ1bmN0aW9uKHgsbXUsYWx0ZXJuYXRpdmUpIHQudGVzdCh4LG11PW11LGFsdGVybmF0aXZlPWFsdGVybmF0aXZlKSRwLnZhbHVlLG11PW11MCxhbHRlcm5hdGl2ZT0ibGVzcyIpCgptZWFuKHBTaW08YWxwaGEpCnBTaW0gJT4lIAogIGFzLmRhdGEuZnJhbWUgJT4lIAogIGdncGxvdChhZXMoeD0uKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKyAKICB4bGltKDAsMSkKYGBgCi0gV2Ugb2JzZXJ2ZSB0aGF0IGEgcG93ZXIgb2YgYHIgbWVhbihwU2ltPGFscGhhKWAgb3IgYSB0eXBlIElJIGVycm9yIG9mIGByIDEtbWVhbihwU2ltPGFscGhhKWAuCgotLS0KCi0gV2hlbiB3ZSBpbmNyZWFzZSB0aGUgc2FtcGxlIHNpemUKCmBgYHtyfQpuc2ltIDwtIDEwMDAwCm4gPC0gMzAKc2lnbWEgPC0gOQptdSA8LSAtMgptdTAgPC0gMAphbHBoYT0wLjA1Cgojc2ltdWxhdGUgbnNpbSBzYW1wbGVzIG9mIHNpemUgbgpkZWx0YVNpbSA8LSBtYXRyaXgocm5vcm0obipuc2ltLG11LHNpZ21hKSxucm93PW4sbmNvbD1uc2ltKQpwU2ltIDwtIGFwcGx5KGRlbHRhU2ltLDIsZnVuY3Rpb24oeCxtdSxhbHRlcm5hdGl2ZSkgdC50ZXN0KHgsbXU9bXUsYWx0ZXJuYXRpdmU9YWx0ZXJuYXRpdmUpJHAudmFsdWUsbXU9bXUwLGFsdGVybmF0aXZlPSJsZXNzIikKCm1lYW4ocFNpbTxhbHBoYSkKcFNpbSAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZ2dwbG90KGFlcyh4PS4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArIAogIHhsaW0oMCwxKQpgYGAKCi0gSW5jcmVhc2luZyB0aGUgc2FtcGxlIHNpemUgbGVhZHMgdG8gYSBoaWdoZXIgcG93ZXIuIAotIFN0aWxsIHRoZSBwb3dlciB0byBwaWNrIHVwIHN1Y2ggYSBzbWFsbCBibG9vZCBwcmVzc3VyZSBkcm9wIHJlbWFpbnMgdmVyeSBsb3cuCi0gQSBkcm9wIG9mIDIgbW1IZyBpcyBhbHNvIG5vdCByZWxldmFudCBmb3IgZHJ1ZyBjb21wYW5pZXMuIAoKIVtdKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvbm1ldGguMjczOC5wZGYpe3dpZHRoPTEwMCV9CgotLS0KCiMjIyBJbnRlcnByZXRhdGlvbgoKU3VwcG9zZSB0aGF0IGdpdmVuIGEgcGFydGljdWxhciBzYW1wbGUgJHA8XGFscGhhJCwgaS5lLiByZWplY3QgJEhfMCQgCgotIFR3byBwb3NzaWJpbGl0aWVzCgogICAgLSBjb3JyZWN0IGRlY2lzaW9uLAoJICAtIG9yIHR5cGUgSSBlcnJvci4KCi0gV2Uga25vd24gdGhhdCB0aGUgcHJvYmFiaWxpdHkgb24gYSB0eXBlIGVycm9yIGlzIGxvdywgaS5lLiAkXGFscGhhPTAuMDUkLgoKCk9uIHRoZSBvdGhlciBoYW5kLCB3aGVuICRwXGdlcVxhbHBoYSQgYW5kIHdlIGRvIG5vdCByZWplY3QgJEhfMCQgd2UgYWxzbyBoYXZlIHR3byBvcHRpb25zOgoKICAtIENvcnJlY3QgZGVjaXNpb24sCiAgLSBvciB3ZSBtYWRlIGEgdHlwZSBJSSBlcnJvci4KClRoZSBwcm9iYWJpbGl0eSBvbiBhIHR5cGUgSUkgZXJyb3IgKCRcYmV0YSQpIGlzIG5vdCBjb250cm9sbGVkIGF0IGEgc3BlY2lmaWMgdmFsdWUuIAoKU3RhdGlzdGljYWwgdGVzdCBpcyBjb25zdHJ1Y3RlZCB0byBvbmx5IGNvbnRyb2wgdGhlIHByb2JhYmlsaXR5IG9uIGEgdHlwZSBJIGVycm9yIGF0ICAkXGFscGhhJC4KClRvIGJlIHNjaWVudGlmaWNhbGx5IGNvcnJlY3Qgd2UgaGF2ZSB0byB0YWtlIGEgcGVzc2ltaXN0aWMgYXR0aXR1ZGUgYW5kIHdlIGhhdmUgdG8gYWRtaXQgdGhhdCAkXGJldGEkIGNhbiBiZSBsYXJnZSAoaS5lLiBhIHNtYWxsIHBvd2VyIHRvIGRldGVjdCB0aGUgYWx0ZXJuYXRpdmUpLgoKSGVuY2UsIAoKLSAkcCA8IFxhbHBoYSQgd2UgcmVqZWN0ICRIXzAkCgogICAgLSBXZSBjb25jbHVkZSB0aGF0ICRIXzEkIGlzIHByb2JhYmx5IGNvcnJlY3QuCgkgIC0gV2UgcmVmZXIgdG8gdGhpcyBhcyBhIHN0cm9uZyBjb25jbHVzaW9uLiAKCSAgCi0gJHAgXGdlcSBcYWxwaGEkIGFjY2VwdCAkSF8wJCAgCgoJICAtIERvZXMgbm90IGltcGx5IHRoYXQgd2UgYWNjZXB0ICRIXzAkIGNvcnJlY3RseS4KICAJLSBXZSBjYW4gb25seSBjb25jbHVkZSB0aGF0IHRoZSBkYXRhIGRvIG5vdCBoYXZlIGVub3VnaCBldmlkZW5jZSBhZ2FpbnN0IHRoZSAkSF8wJCBpbiBmYXZvdXIgb2YgJEhfMSQuCiAgICAtIFdlIHJlZmVyIHRvIHRoaXMgYXMgYSB3ZWFrIGNvbmNsdXNpb24uCiAgICAtIFdlIHR5cGljYWxseSBjb25jbHVkZSB0aGF0IHRoZSBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudCBpcyBub3Qgc2lnbmlmaWNhbnQuCgotLS0KICAgIAojIyBDb25jbHVzaW9ucyBjYXB0b3ByaWwgZXhhbXBsZQoKVGhlIHRlc3Qgd2UgaGF2ZSBwZXJmb3JtZWQgaXMgcmVmZXJyZWQgdG8gYXMKCi0gdGhlICoqb25lIHNhbXBsZSB0LXRlc3QqKiBvbiB0aGUgZGlmZmVyZW5jZSBvcgogIAotIGEgKipwYWlyZWQgdC10ZXN0KiouIEluZGVlZCB3ZSBkaXNwb3NlIG9mIHBhaXJlZCBvYnNlcnZhdGlvbnMgZm9yIGVhY2ggcGF0aWVudCEKCi0gVGhlIHRlc3QgaXMgZG9uZSBvbmUtc2lkZWQgYmVjYXVzZSB3ZSB0ZXN0IGFnYWluc3QgdGhlIGFsdGVybmF0aXZlIG9mIGEgYmxvb2QgcHJlc3N1cmUgZHJvcC4gCgotIEJvdGggdGVzdHMgKG9uZSBzYW1wbGUgdC10ZXN0IG9uIHRoZSBkaWZmZXJlbmNlIGFuZCBwYWlyZWQgdC10ZXN0KSBnaXZlIHRoZSBzYW1lIHJlc3VsdHM6IAoKYGBge3J9CnQudGVzdChjYXB0b3ByaWwkZGVsdGFTQlAsYWx0ZXJuYXRpdmU9Imxlc3MiKQpgYGAKCmBgYHtyfQp0LnRlc3QoY2FwdG9wcmlsJFNCUGEsY2FwdG9wcmlsJFNCUGIscGFpcmVkPVRSVUUsYWx0ZXJuYXRpdmU9Imxlc3MiKQpgYGAKCi0tLQoKIyMjIENvbmNsdXNpb24KClRoZXJlIGlzIG9uIGF2ZXJhZ2UgYW4gZXh0cmVtZWx5IHNpZ25pZmljYW50IGJsb29kIHByZXNzdXJlIGRyb3AgdXBvbiBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbCB0byBwYXRpZW50cyB3aXRoIGh5cGVydGVuc2lvbi4gVGhlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIGRlY3JlYXNlcyBvbiBhdmVyYWdlIHdpdGggMTguOSBtbUhnIHVwb24gdGhlIHRyZWF0bWVudCB3aXRoIGNhcHRvcHJpbCAoOTUlIENJIFskLVxpbmZ0eSwtMTQuODIkXSBtbUhnKS4KCk5vdGUgdGhhdAoKMS4gQSBvbmUtc2lkZWQgaW50ZXJ2YWwgaXMgcmVwb3J0ZWQgYmVjYXVzZSB3ZSBhcmUgb25seSBpbnRlcmVzdGVkIGluIGEgYmxvb2QgcHJlc3N1cmUgZHJvcC4gCgoyLiBCZWNhdXNlIG9mIHRoZSBwcmUtdGVzdC9wb3N0LXRlc3QgZGVzaWduIHdlIGNhbm5vdCBkaXN0aW5ndWlzaCBiZXR3ZWVuIHRoZSBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudCBhbmQgYSBwbGFjZWJvIGVmZmVjdC4gVGhlcmUgd2FzIG5vIGdvb2QgY29udHJvbCEgVGhlIGxhY2sgb2YgYSBnb29kIGNvbnRyb2wgdHlwaWNhbGx5IG9jY3VycyBpbiAgcHJlLXRlc3QvcG9zdC10ZXN0IGRlc2lnbnMuIEhvdyBjb3VsZCB3ZSBoYXZlIGltcHJvdmVkIHRoZSBkZXNpZ24/IAoKLS0tCgojIyBPbmUtc2lkZWQgb3IgdHdvLXNpZGUgdGVzdGluZz8gCgpEZSB0ZXN0IGluIHRoZSBjYXB0b3ByaWwgZXhhbXBsZSB3YXMgYSBvbmUtc2lkZWQgdGVzdC4gV2Ugb25seSBhaW0gdG8gZGV0ZWN0IGlmIHRoZSBjYXB0b3ByaWwgdHJlYXRtZW50IG9uIGF2ZXJhZ2UgcmVkdWNlcyB0aGUgYmxvb2QgcHJlc3N1cmUuIAoKU3VwcG9zZSB0aGF0IHdlIGRlZmluZWQgdGhlIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2UgYXMgICRYX3tpfV5ccHJpbWU9WV97aX1eXHRleHR7YmVmb3JlfS1ZX3tpfV5cdGV4dHthZnRlcn0kCgotIE5vdywgYSBwb3NpdGl2ZSB2YWx1ZSBpbmRpY2F0ZXMgYSBibG9vZCBwcmVzc3VyZSBkcm9wIAoKLSBUaGUgYXZlcmFnZSBjaGFuZ2UgaW4gYmxvb2QgcHJlc3N1cmUgaXMgbm93IGRlbm90ZSBhcyAkXG11XlxwcmltZT1cdGV4dHtFfVtYXlxwcmltZV0kLgoKLSBTbyBub3cgd2Ugc2hvdWxkIHVzZSBhIG9uZS1zaWRlZCB0ZXN0IHRvIGFzc2VzcyAkSF8wOiBcbXVeXHByaW1lPTAkIGFnYWluc3QgJEhfMTogXG11XlxwcmltZT4wJC4KCi0gcC12YWx1ZSBub3cgYmVjb21lczogCiQkcD1cdGV4dHtQfV8wXGxlZnRbVFxnZXEgdFxyaWdodF0uJCQKCi0tLQoKQW5hbHlzaXMgYmFzZWQgb24gJFheXHByaW1lJDogQXJndW1lbnQgYGFsdGVybmF0aXZlPSJncmVhdGVyImAgc28gdGhhdCB3ZSB1c2UgJEhfMTogXG11XlxwcmltZT4wJDoKYGBge3J9CnQudGVzdChjYXB0b3ByaWwkU0JQYi1jYXB0b3ByaWwkU0JQYSxhbHRlcm5hdGl2ZT0iZ3JlYXRlciIpCmBgYAoKT2YgY291cnNlIHdlIG9idGFpbiB0aGUgc2FtZSByZXN1bHRzLiBPbmx5IHRoZSBzaWduIGlzIHN3YXBwZWQuIAoKLS0tCgojIyMgVHdvLXNpZGVkIHRlc3QKClN1cHBvc2UgdGhhdCByZXNlYXJjaGVycyB3YW50ZWQgdG8gYXNzZXNzIHRoZSBtb2RlIG9mIGFjdGlvbiBvZiB0aGUgbmV3IGRydWcgY2FwdG9wcmlsIGluIHRoZSBkZXNpZ24gcGhhc2UgYW5kIHN1cHBvc2UgdGhhdCBoZWFsdGh5IHN1YmplY3RzIHdlcmUgdXNlZCBpbiBhbiBlYXJseSBwaGFzZSBvZiB0aGUgZHJ1ZyBkZXZlbG9wbWVudC4gCgpJbiB0aGlzIGNhc2UgaXQgd291bGQgaGF2ZSBiZWVuIGludGVyZXN0aW5nIHRvIG9ic2VydmUgYmxvb2QgcHJlc3N1cmUgZHJvcHMgYXMgd2VsbCBhcyBnYWlucy4KClRoZW4gd2Ugd291bGQgcmVxdWlyZSBhIHR3by1zaWRlZCB0ZXN0IHN0cmF0ZWd5CgokJEhfMDogXG11PTAkJAphZ2FpbnN0IHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzCgokJEhfMTogXG11XG5lcTAsJCQKCnNvIHRoYXQgdGhlIG1lYW4gdW5kZXIgdGhlIGFsdGVybmF0aXZlIGlzIGRpZmZlcmVudCBmcm9tIHplcm8uIAoKSXQgY2FuIGJlIHBvc2l0aXZlIGFzIHdlbGwgYXMgbmVnYXRpdmUgY2hhbmdlcyBhbmQgd2UgZGlkIG5vdCBrbm93IHVwZnJvbnQgaW4gd2hpY2ggZGlyZWN0aW9uIHRoZSByZWFsIG1lYW4gd2lsbCBkZXZpYXRlIGZyb20gJEhfMSQuCgoKV2UgY2FuIGNvbmR1Y3QgYSB0d28tc2lkZWQgdGVzdCBvbiB0aGUgJFxhbHBoYT01XCUkIHNpZ25pZmljYW5jZSBsZXZlbCBieQoKYGBge3Igb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmdyaWQgPC1zZXEoLTEwLDEwLC4wMSkKdGNyaXQgPC0gcXQoMC45NzUsbi0xKQpyZWplY3QxIDwtIGMoZ3JpZFtncmlkPCAtdGNyaXRdLC10Y3JpdCkKcmVqZWN0MiA8LSBjKHRjcml0LGdyaWRbZ3JpZD50Y3JpdF0pCgpwbG90KGdyaWQsZHQoZ3JpZCxuLTEpLHR5cGU9ImwiLGx3ZD0yLHhsYWI9InQtc3RhdGlzdGljIix5bGFiPSJkZW5zaXR5Iix5bGltPWMoLS4wNSwuNCkpCmFibGluZSh2PWMoLTEsMSkqbWVhbihjYXB0b3ByaWwkZGVsdGFTQlApL3NlLGNvbD0yLGx3ZD0yLGx0eT0yKQphYmxpbmUodj1jKC0xLDEpKnRjcml0LGNvbD0yLGx0eT0xLGx3ZD0yKQp0ZXh0KGMoLTUsLTUsNSw1KSxjKC0uMDMsLS4wNSwtLjAzLC0uMDUpLGxhYmVsPWMoInJlamVjdGlvbi0iLCJyZWdpb24iLCJyZWplY3Rpb24tIiwicmVnaW9uIiksY29sPWMoMiwyLDIsMikpCnRleHQoYygwLDApLGMoLS4wMywtLjA1KSxsYWJlbD1jKCJhY2NlcHRpb24tIiwicmVnaW8iKSxjb2w9Yyg0LDQpKQoKYXJyb3dzKC0xMDAsLjQsLWFicyhtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvc2UpLC40LGx3ZD0yLGNvbD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKYXJyb3dzKDEwMCwuNCxhYnMobWVhbihjYXB0b3ByaWwkZGVsdGFTQlApL3NlKSwuNCxsd2Q9Mixjb2w9MixhbmdsZT0yMCxsZW5ndGg9LjEpCnRleHQoLTEwLC4zNSxsYWJlbD0icC12YWx1ZSIsc3J0PTkwLGNvbD0yKQp0ZXh0KDEwLC4zNSxsYWJlbD0icC12YWx1ZSIsc3J0PTkwLGNvbD0yKQoKYXJyb3dzKC0xMDAsLS4wNCwtdGNyaXQsLS4wNCxsd2Q9Mixjb2w9MixhbmdsZT0yMCxsZW5ndGg9LjEpCmFycm93cygxMDAsLS4wNCx0Y3JpdCwtLjA0LGx3ZD0yLGNvbD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKCnBvbHlnb24oYyhyZWplY3QxLC10Y3JpdCwtMTApLGMoZHQocmVqZWN0MSxuLTEpLDAsMCksY29sPTIsYm9yZGVyPTIpCnBvbHlnb24oYyh0Y3JpdCxyZWplY3QyLHRjcml0KSxjKDAsZHQocmVqZWN0MixuLTEpLDApLGNvbD0yLGJvcmRlcj0yKQoKdGV4dCgtMy41LC4wNSxsYWJlbD1leHByZXNzaW9uKHBhc3RlKGFscGhhLCIvMj0yLjUlIikpLGNvbD0yKQp0ZXh0KDMuNiwuMDUsbGFiZWw9ZXhwcmVzc2lvbihwYXN0ZShhbHBoYSwiLzI9Mi41JSIpKSxjb2w9MikKYXJyb3dzKC0zLDAuMDIsLTMuNSwuMDQsY29sPTIsbHdkPTIsYW5nbGU9MjAsbGVuZ3RoPS4xKQphcnJvd3MoMywwLjAyLDMuNSwuMDQsY29sPTIsbHdkPTIsYW5nbGU9MjAsbGVuZ3RoPS4xKQpgYGAKCi0tLQoKVGhlIGFyZ3VtZW50IGBhbHRlcm5hdGl2ZWAgb2YgdGhlIGB0LnRlc3RgIGZ1bmN0aW9uIGlzIGJ5IGRlZmF1bHQgYGFsdGVybmF0aXZlPSJ0d28uc2lkZWQiYC4KCmBgYHtyfQp0LnRlc3QoY2FwdG9wcmlsJGRlbHRhU0JQKQpgYGAKCi0gV2Ugc3RpbGwgb2J0YWluIGFuIGV4dHJlbWVseSBzaWduaWZpY2FudCByZXN1bHQuCi0gVGhlIHAtdmFsdWUgaXMgZG91YmxlIGFzIGxhcmdlIGJlY2F1c2Ugd2UgdGVzdCB0d28tc2lkZWQuIAoKSW5kZWVkIAoKJCRwPVBfMFtUIFxsZXEgLVx2ZXJ0IHQgXHZlcnRdICsgUF8wW1QgXGdlcSBcdmVydCB0IFx2ZXJ0XSA9IFBfMFtcdmVydCBUIFx2ZXJ0IFxnZXEgXHZlcnQgdCBcdmVydF0gPSAyIFx0aW1lcyBQXzBbVCBcZ2VxIFx2ZXJ0IHQgXHZlcnRdJCQKCi0gV2UgYWxzbyBvYnRhaW4gYSAgdHdvLXNpZGVkIGNvbmZpZGVuY2UgaW50ZXJ2YWwgCgotLS0KCiMjIyBPbmUtc2lkZWQgb3IgdHdvLXNpZGVkIHRlc3Q/CgpXaXRoIGEgb25lLXNpZGVkIHRlc3Qgd2UgY2FuIG1vcmUgZWFzaWx5IHJlamVjdCAkSF8wJCBvbiBjb25kaXRpb24gdGhhdCAkSF8xJCBpcyB0cnVlIHRoYW4gd2l0aCBhIHR3by1zaWRlZCB0ZXN0LiAKCi0gQWxsIGluZm9ybWF0aW9uIGlzIHVzZWQgdG8gdGVzdCBpbnRvIG9uZSBkaXJlY3Rpb24KCi0gVGhlIGRlY2lzaW9uIHRvIHRlc3Qgb25lLXNpZGVkIGhhcyB0byBiZSBkb25lIGluIHRoZSBkZXNpZ24gcGhhc2UgYmVmb3JlIHRoZSBleHBlcmltZW50IGlzIGNvbmR1Y3RlZAoKLSBFdmVuIGlmIHdlIGhhdmUgc3Ryb25nIGEgcHJpb3JpIHByZXN1bXB0aW9ucywgd2UgYXJlIG5vdCBlbnRpcmVseSBzdXJlIG90aGVyd2lzZSB3ZSB3b3VsZCBoYXZlIG5vIHJlYXNvbiB0byBkbyB0aGUgcmVzZWFyY2guIAoKLSBJZiB3ZSBwcm9wb3NlIGEgb25lLXNpZGVkIHRlc3QgaW4gdGhlIGRlc2lnbiBwaGFzZSBhbmQgd2Ugb2JzZXJ2ZSBhIHJlc3VsdCBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uIHRoYXQgd291bGQgYmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB3ZSBjYW4gbm90IGRyYXcgY29uY2x1c2lvbnMgZnJvbSB0aGUgZXhwZXJpbWVudC4gCgotIEluIHRoZSBkZXNpZ24gcGhhc2Ugd2UgaGF2ZSBleGNsdWRlZCB0aGlzIHJlc3VsdCBiZWNhdXNlIGl0IGlzIHNvIHVuZXhwZWN0ZWQgdGhhdCBpdCBoYXMgdG8gYmUgYSBmYWxzZSBwb3NpdGl2ZS4gCgotIEhlbmNlLCBvbmUtc2lkZWQgdGVzdHMgYXJlIG5vdCByZWNvbW1lbmRlZC4gCgpBIHR3by1zaWRlZCB0ZXN0IGNhbiBhbHdheXMgYmUgZGVmZW5kZWQgYW5kIGFsbG93cyB5b3UgdG8gZGV0ZWN0IGFueSBkZXZpYXRpb24gb2YgJEhfMCQgYW5kIGlzIGhpZ2hseSByZWNvbW1lbmRlZC4gCgoKSXQgaXMgKipuZXZlciBhbGxvd2VkKiogdG8gY2hhbmdlIGEgdHdvLXNpZGVkIHRlc3QgaW50byBhIG9uZS1zaWRlZCB0ZXN0IGJhc2VkIG9uIHdoYXQgaGFzIGJlZW4gb2JzZXJ2ZWQgaW4gdGhlIHNhbXBsZSEgT3RoZXJ3aXNlIHRoZSB0eXBlIEkgZXJyb3Igb2YgdGhlIHRlc3Qgc3RyYXRlZ3kgaXMgbm90IGNvcnJlY3RseSBjb250cm9sbGVkLiAKCi0tLQoKV2UgaWxsdXN0cmF0ZSB0aGlzIGluIHRoZSBzaW11bGF0aW9uIHN0dWR5IGJlbG93OiAKCjEuIGNvcnJlY3QgdHdvLXNpZGVkIHRlc3QgYW5kCjIuIG9uZS1zaWRlZCB0ZXN0IHdpdGggaXRzIHNpZ24gYmFzZWQgb24gd2hhdCB3YXMgb2JzZXJ2ZWQgaW4gdGhlIHNhbXBsZS4gCgoKYGBge3J9Cm11IDwtIDAKc2lnbWEgPC0gOS4wCm5TaW0gPC0gMTAwMAphbHBoYSA8LSAwLjA1Cm4gPC0gMTUKcHZhbHNDb3IgPC0gcHZhbHNJbkNvcjwtYXJyYXkoMCxuU2ltKQpmb3IgKGkgaW4gMTpuU2ltKQp7Cgl4IDwtIHJub3JtKG4sbWVhbj1tdSxzZD1zaWdtYSkKCXB2YWxzQ29yW2ldIDwtIHQudGVzdCh4KSRwLnZhbHVlCglpZiAobWVhbih4KTwwKQoJCXB2YWxzSW5Db3JbaV0gPC0gdC50ZXN0KHgsYWx0ZXJuYXRpdmU9Imxlc3MiKSRwLnZhbHVlIGVsc2UKCQlwdmFsc0luQ29yW2ldIDwtIHQudGVzdCh4LGFsdGVybmF0aXZlPSJncmVhdGVyIikkcC52YWx1ZQp9CgptZWFuKHB2YWxzQ29yPDAuMDUpCm1lYW4ocHZhbHNJbkNvcjwwLjA1KQpgYGAKCi0gVHlwZSBJIGVycm9yIGNvcnJlY3RseSBjb250cm9sbGVkIGF0ICRcYWxwaGEkIGZvciB0d28tc2lkZWQgdGVzdC4KLSBUeXBlIEkgZXJyb3Igbm90IGNvcnJlY3RseSBjb250cm9sbGVkIHdoZW4gd2UgdGVzdCBvbmUtc2lkZWQgYmFzZWQgb24gd2hhdCB3ZSBvYnNlcnZlZCBpbiB0aGUgc2FtcGxlLiAKCiMgTmF0dXJlIGNvbHVtbiBvbiB0ZXN0aW5nCgohW10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9ubWV0aC4yNjk4LnBkZil7d2lkdGg9MTAwJX0KCgoKLS0tCgojIFtIb21lXShodHRwczovL2d0cGIuZ2l0aHViLmlvL1BTTFMyMC8pIHstfQoK