Link to test summary slide
Background
In this course we will explain the theory behind common statistical
tests to compare two or more groups. We will illustrate this using
biologically-motivated examples and R code that uses the “tidyverse”
techniques of data manipulation and visualization.
To install the entire collection of tidyverse packages (which
includes other useful data-related packages that we will not use today),
you may wish to use the following:-
## May take some time!
install.packages("tidyverse")
Statistics has been a fundamental part of the R language from the
beginning. A vast array of statistical tests and associated
visualizations are supported. However, the functions to perform these
predate the creation of the tidyverse
and are used in a
manner that might be somewhat counter-intuitive to someone that is
familiar with the tidyverse
. Therefore we will use a couple
of add-on packages that have been created to perform statistics in a
manner that is compatible with the tidyverse eco-system.
The specific set of required packages is as follows:-
install.packages(c("dplyr",
"ggplot2",
"readr",
"readxl",
"rstatix",
"ggpubr",
"rmarkdown",
"tidyr",
"vcd"))
Part I - Contingency tables
When working with categorical variables, we are usually interested in
the frequencies of the different categories in our sample. To
display data for two or more categorical variables, cross-tabulations,
or contingency tables, are commonly used - with 2 x 2 tables being the
simplest. We can then test whether there is an association between the
row factor and the column factor by a chi-squared test or a
Fisher’s exact test.
To demonstrate the analysis of contingency tables we will use a
dataset provided with the vcd
package. You will need to
install this package using the install.packages
R
function.
install.packages("vcd")
## Load the packages we will need
library(dplyr)
library(ggplot2)
library(rstatix)
library(ggpubr)
library(vcd)
The data frame Arthritis
should then be accessible which
is described as:-
Data from Koch & Edwards (1988) from a double-blind clinical
trial investigating a new treatment for rheumatoid arthritis.
#let's use the'Arthritis' dataset in the 'vcd' package
Arthritis
The count
function, included in dplyr
can
be used to give a tabulation of the values in any column in the data
frame.
##one way table (count of one variable)
count(Arthritis,Sex)
We can quickly visualise these counts as a barplot with
ggplot2
. The geom_bar
plot type will
automatically count the number of observations that will be plotted on
the y-axis.
ggplot(Arthritis, aes(x = Sex)) + geom_bar()

The function freq_table
from rstatix
is
another way of making the counts and will also add the proportions as an
extra column.
#to get proportion of males and females
freq_table(Arthritis,Sex)
The count
function can also compare two columns from a
data frame if both columns are given as arguments.
count(Arthritis,Sex,Improved)
These can also be plotted, but this time we have to use
geom_col
to specify the values for the y-axis.
count(Arthritis,Sex,Improved) %>%
ggplot(aes(x = Sex, fill = Improved, y = n)) + geom_col()

count(Arthritis,Sex,Improved) %>%
ggplot(aes(x = Sex, fill = Improved, y = n)) + geom_col(position = "dodge")

The freq_table
function can be used to calculate the
proportions. However, we need to pay attention to the order in which the
variables are specified as this will dictate how the proportions are
calculated
Compare the output of:-
freq_table(Arthritis,Sex, Improved)
to:-
freq_table(Arthritis,Improved, Sex)
Having explored our data, we can now perform statistical testing. The
function chisq_test
can be used to assess whether
differences in proportions are significant or not. We actually don’t
need to calculate the proportions; R will do this for us.
However, we need to re-format the data slightly into a wide
table rather than the default long nature of a data frame in
the tidyverse
. We the pivot_wider
function we
create a two-by-two table that is typically used for a contingency
analysis.
Arthritis %>%
count(Improved, Treatment) %>%
tidyr::pivot_wider(values_from = n,names_from = Improved)
##would also work with names_from Treatment
And now remove the Treatment
column as the
chisq_test
function is only expecting numeric data. The
results are presented in a tidyverse
tibble that and we can
interpret the test statistics and p-value from this table
Arthritis %>%
count(Improved, Treatment) %>%
tidyr::pivot_wider(values_from = n,names_from = Improved) %>%
select(-Treatment) %>%
chisq_test()
Note that the only line of code to perform the test is
chisq_test
. The preceding lines are used to manipulate our
data into the correct format. If our data are already in a numeric table
we might be able to use chisq_test
directly.
The chi-squared test works by comparing the frequencies in each cell
of our table to what we would expect by chance (i.e. if there was no
significant association). If we want to see what the expected
frequencies would be we can run expected_freq
after
chisq_test
.
Arthritis %>%
count(Improved, Treatment) %>%
tidyr::pivot_wider(values_from = n,names_from = Improved) %>%
select(-Treatment) %>%
chisq_test() %>% expected_freq()
None Some Marked
[1,] 21.5 7.166667 14.33333
[2,] 20.5 6.833333 13.66667
However, the chisq_test
function is not appropriate in
all circumstances.
Arthritis %>%
count(Improved, Sex) %>%
tidyr::pivot_wider(values_from = n,names_from = Improved) %>%
select(-Sex) %>%
chisq_test
Warning: Chi-squared approximation may be incorrect
The Fisher test is recommended for tables with low numbers of
observations (e.g. when more than 20% of cells have expected
frequencies < 5)
Arthritis %>%
count(Improved, Sex) %>%
tidyr::pivot_wider(values_from = n,names_from = Improved) %>%
select(-Sex) %>%
fisher_test
In this case we had some low expected frequencies so the Fisher test
was more appropriate
Arthritis %>%
count(Improved, Sex) %>%
tidyr::pivot_wider(values_from = n,names_from = Improved) %>%
select(-Sex) %>%
chisq_test %>%
expected_freq()
Warning: Chi-squared approximation may be incorrect
None Some Marked
[1,] 29.5 9.833333 19.666667
[2,] 12.5 4.166667 8.333333
Exercise
1- Read the excel file called Ex Biostat P1.xlsx
into R
(see below for the required code). We recommend using
make_clean_names
function from rstatix
to make
sure the column names are “clean” (i.e. without spaces or other
characters that could cause issues for R).
2- Use the counts
function to make a cross-tabulation of
Tumor grade against Gender
3- Determine the proportion of Grade III tumors within females
4- Use the appropriate test to check if the tumor grade depends on
the gender
## the readxl package is required to read xls and xlsx files into R
## However, csv and tsv files are recommended to store data
tab <- readxl::read_xlsx("data/EX Biostat P1.xlsx") %>%
make_clean_names()
Part II - How to assess normality
We will read some example data to illustrate how one would test for a
normally-distributed variable. This property is important as it
influences which test we should use.
One of the best ways of displaying data is by using a graph. Graphs
can make both simple and complex data easier to understand by making it
easier to spot trends and patterns. We can use plots to view the
distribution of our data (minimum, maximum, mid-point, spread etc) and
to ensure that the values in our dataset seem realistic (e.g. no
outliers). Many statistical tests rely on the assumption that the data
are normally distributed.
The data for this section are to be found in the file
normal_example.csv
in the data
folder. You
will need to specify the file path accordingly.
library(readr)
df1 <- read_csv("data/normal_example.csv")
We can inspect the data in RStudio and discover that it consists of a
tidy dataset with numeric values in a column called Values
and a column Var
to indicate a variable name
(x
)
View(df1)
Various graphical methods are available to assess the distribution.
The first of which is a histogram. In this graph the data are
split into “bins” and the value on the y
axis corresponds
to the number of observations in that bin. The user only has to specify
the variable to be plotted, and function takes care of the binning. From
this plot we can judge what the average value of the data is, and the
spread.
Histograms can be made in ggplot2
by using the
geom_hist
function (or indeed the base hist
function). Here we are going to make use of the gghistogram
function from ggpubr
as it is a bit more convenient.
gghistogram(df1,x="Value")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

When assessing the distribution of a variable, you might be tempted
to plot the histogram and density on the same plot.
gghistogram
has the argument add_density
,
which should do the job.
gghistogram(df1,x="Value",add_density = TRUE)
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

However, this doesn’t work. If you check the y-axis limits on the
histogram and density plots, you’ll notice they are on a different
scale. Conveniently there is an argument in gghistogram
that solves this issue.
gghistogram(df1,x="Value",
add_density = TRUE,
y="..density..")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

We can add the standard normal curve with the following
code. To help distingush the standard normal we can change the colour
this is plotted in.
gghistogram(df1,x="Value",add_density = TRUE,y="..density..") + stat_overlay_normal_density(col="steelblue",lwd=2,lty=2)
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

A box plot is an excellent way of displaying continuous data when you
are interested in the spread of your data. The “box” of the box plot
corresponds to the lower and upper quartiles of the respective
observations and the bar within the box, the median. The whiskers of the
box plot correspond to the distance between the lower/upper quartile and
the smaller of: the smaller/largest measurement OR 1.5 times
the inter quartile range. A disadvantage of the box plot is that you
don’t see the exact data points. However, box plots are very useful in
large datasets where plotting all of the data may give an unclear
picture of the shape of your data.
Again, we use ggboxplot
from ggpubr
for
convenience.
ggboxplot(df1, y = "Value")

A violin plot is sometimes instead of the boxplot to provide
more information about the density.
ggviolin(df1, y = "Value")

Individual points can also be added with the jitter
argument; avoiding over-plotting by adding random noise along the
x-axis.
ggviolin(df1, y = "Value",add = "jitter")

Finally, we have a “qq-plot” which allows to compare the
quantiles of our dataset against a theoretical normal distribution. If
the majority of points lie on a diagonal line then the data are
approximately normal. The ggqqplot
function in
ggpubr
is the most convenient way of creating this
plot.
ggqqplot(df1, x="Value")

These graphical methods are by far the easiest way to assess if a
given dataset is normally-distributed. However, you do not necessarily
need to generate and report all the plots for your data; just as many as
you to inform your decision.
For “real-life” data, the results are unlikely to give a perfect
plot, so some degree of judgement and prior experience with the data
type are required. Indeed, it should be noted that the dataset
visualised in the above plots was sampled from a normal distribution.
Even then, the plots were not 100% convincing!
Tests for normality
Although their usage is contentious amongst statisticians, there are
a few methods for testing whether variables are normally-distributed or
not. If the p-value is sufficiently small from these methods then we
conclude that the data are not normally distributed. However,
some statisticians prefer to use graphical methods and their intuition
about the data or prior knowledge of the data type (e.g. some measures
are generally believed to be normally-distributed)
#shapiro test from rstatix
#p<0.05 ...difference between data and normality..data not normal
#p>0.05 ...no diff between data and normality ..data normally distributed
shapiro_test(df1,Value)
Descriptive Statistics
When performing a statistical analysis it is common practice to
report on the average and variability. Our decision about whether the
data are normally-distributed will influence what measures we report. In
rstatix
there is a function called
get_summary_stats
that can calculate such summaries.
For a dataset that is normally-distributed, appropriate measures of
the average and variability are the mean and standard
deviation.
df1 %>%
get_summary_stats(type="common")
df1 %>%
get_summary_stats(type = "common") %>%
select(mean, sd)
Exercise
1- Read the excel file called Ex Biostat P2.xlsx
into
R
2- Decide if the age and hospitalization days are normally
distributed. Vote for your findings on wooclap
3- Calculate the appropriate descriptive statistics [mean and SD, or
median and IQR] for each variable
Part III - Significance tests for continuous variables
In this part we will show how to perform tests to compare 1, 2 (or
more) continuous variables. The dataset, provided by MASH at The
University of Sheffield, describes individuals that have been following
different diets and their age and gender. The main goal of interest is
to determine which of three competing diet regimes results in the
greatest weight loss. However, we can use the dataset to demonstrate
other types of test.
diet <- read_csv("data/diet.csv")
diet
One-sample test
The first hypothesis we will test is whether the people in the study
are overweight or not. This first involves some manipulation of the
table to calculate an extra variable; the Body Mass Index (BMI). We will
test if people in our study are overweight, where overweight is defined
as having a BMI over 25.
\(BMI = weight / height^2\)
(where the weight is measured in kg, and the height in
metres)
Exercise (short) - Add a new variable to the data
frame for the BMI of each person + you might want to do this in multiple
steps using the %>%
notation
diet <- diet %>%
mutate(BMI =initial.weight / (height/100)^2)
We can now test our new variable for normality using the plots and
tests from earlier, although we will not show all the plots here.
gghistogram(diet, x = "BMI", ,add_density = TRUE,y="..density..")+ stat_overlay_normal_density(col="steelblue")
The one-sample t-test is implemented in the function
t_test
(as are the various types of t-test that we will
see). The variables to be used in the test are defined using R’s formula
~
syntax.
Y ~ X
Where Y
is a numeric variable and
X
is a categorical variable indicating the groups that each
particular value of Y
belongs to.
In the case of a one-sample test we are testing one numeric variable
against a known or population mean (mu
). As we don’t have a
groups to compare, this is written as:-
Y ~ 1
diet %>%
t_test(BMI ~1)
We get a hugely significant result! However, if we look at the
description for t_test
it is testing against a population
mean of \(0\). It is no surprise that
we get a significant result! By changing the mu
argument we
can perform a test to see if the people in the study are overweight to
begin with (using 25 as the population or known mean).
diet %>%
t_test(BMI ~1,mu = 25,alternative = "greater")
## 25 is the cutoff for overweight
Two-sample tests
A two-sample t-test should be used if you want to compare the
measurements of two populations. There are two types of two-sample
t-test: independent (unpaired) and paired (dependent). To make the
correct choice, you need to understand your underlying data.
An independent two-sample t-test is used when the two samples are
independent of each other, e.g. comparing the mean response of two
groups of patients on treatment vs. control in a clinical
trial.
As the name suggests,a paired two-sample t-test is used when the
two samples are paired, e.g. comparing the mean blood pressure of
patients before and after treatment (two measurements per
patient).
Back to our dataset, we might wonder if there is actually any effect
due to diet so we will compare the intial and final weights.
Re-formating the dataset for tidy analysis
The dataset in it’s current form is not suitable for analysis with
tidy methods. Before proceeding we need to re-format the data into two
columns.
- One column containing numeric variables (each value of weight)
- An indicator (or categorical) variable to denote the group each
numeric observation belongs to (initial or final weight)
The pivot_longer
function supports this transformation.
As we want to use all columns in our existing dataset we have to use the
everything()
shortcut to select the columns.
diet_long <- diet %>%
select(contains("weight")) %>%
tidyr::pivot_longer(everything(),names_to = "time_point", values_to = "weight")
diet_long
So now weight
contains all our observations of weight
and time_point
indicates when the weights were measured.
The gghistogram
function we introduced earlier is able to
visualise data in this form, and we can use the facet.by
argument to produce separate plots for each type of weight
measurement.
diet_long %>%
gghistogram(x = "weight", facet.by = "time_point",add_density = TRUE, y = "..density..") + stat_overlay_normal_density(col="red")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

We can run the shapiro test on the two variables:-
diet_long %>%
group_by(time_point) %>%
shapiro_test(weight)
The t_test
function requires us to create a
formula as before. This time we are doing a two-sided test, so
the formula is Y ~ X
where ‘Y’ is the numeric variable and
‘X’ is the categorical/groups variable.
diet_long %>%
t_test(weight ~ time_point)
The p-value is significant and shows that overall the weights of
individuals is different before and after diet. However, this
test is not specifically testing for a decrease after the diet
(which we would really hope to be the case). By adding an extra argument
alternative=less
we get a different result
diet_long %>%
t_test(weight ~ time_point, alternative = "less")
There is also extra information that we could employ; namely that the
measurements of weight are made on the same person
before and after dieting. This is a classic example of when to apply a
paired t-test. Again, we do not need to use a different function to
perform the test; only add an argument paired=TRUE
to
t_test
.
diet_long %>%
t_test(weight ~ time_point, alternative = "less",paired=TRUE)
An intuitive way of comparing the distributions and showing the test
result on the plot is using a boxplot. For this we will revert to
ggplot2
, but we are to include a p-value using the
stat_compare_means
function (from ggpubr
.
diet_long %>%
ggplot(aes(x = time_point, y = weight)) + geom_boxplot() + geom_jitter(width=0.1) +
stat_compare_means(method = "t.test",paired=TRUE, method.args = list(alternative = "less"))

?stat_compare_means
A convenient plot in ggpubr
will allow us to visualise
the paired differences
ggpaired(diet, cond1="initial.weight", cond2="final.weight",line.color = "grey") + stat_compare_means(paired=TRUE,method = "t.test")

The Independent t test, with two independent groups
Lets consider that we want to compare whether males or females lost
more weight during the trial. So, let’s create a new variable called
weight loss
diet <- diet %>%
mutate(wt.loss = initial.weight - final.weight)
Here we have two groups (males and females), and these can be treated
as independent variables as each group has different
participants than the other group.
The null hypothesis for such a test would be that the weight
loss is the same between groups male and female. We seek to evidence to
reject this hypothesis by calculating a test statistic.
Remember, the t-test assumes normal distribution and equal
variance
Firstly, we have to check for normality:-
diet %>%
ggdensity("wt.loss",color = "gender") + stat_overlay_normal_density()

diet %>%
group_by(gender) %>%
shapiro_test(wt.loss)
Then we check for equal variances using the Levene test
diet %>%
levene_test(wt.loss~ gender)
Warning: group coerced to factor.
#if p value is significant --> difference in variance (unequal variance) --> use Welch t-test (R default)
#if p value is not significant --> no difference in variance (equal variance) --> use t-test (add argument var.equal =TRUE)
We conclude that the variances are approximately the same and both
variables are normally-distributed
We can use the t_test
function to perform an
independent test. As before, the formula
argument
to t_test
is the R formula notation for the test
being performed. However, this time we do not need the
pivot_longer
function as we already the
gender
and weight.loss
variables in our data
frame
The t_test
function allows various type of test to be
performed by changing the appropriate arguments (see the help for
t_test
for details (?t_test
)). For instance,
we can tell the test that we believe our variances are equal or not.
diet %>%
t_test(wt.loss ~ gender,var.equal = TRUE)
NA
We can see that the t-statistic we observe is consistent with the
null hypothesis, that the weight loss in males and females is the same.
That is, the probability of observing a t-statistic of 0.2 or more, or
-0.2 or less, is quite high.
This is not a significant result (p>0.05), so there is no
evidence of a difference in weight loss between males and
females
diet %>%
ggplot(aes(x = gender, y=wt.loss)) + geom_boxplot() + stat_compare_means(method="t.test")

Non- Parametric alternatives (e.g. the Wilcoxon test)
Being able to use the t_test
relies on the your data
being normally-distributed. If we do not sufficient confidence in this
assumption, there are different statistical tests that can be applied.
Rather than calculating and comparing the means and
variances of different groups they are rank-based
methods. However, they still come with a set of assumptions and involve
the generation of test statistics and p-values.
Independent samples = Wilcoxon rank sum test (Mann Whitney U
test)
This test has many different names including the Wilcoxon, Wilcoxon
two sample test, Wilcoxon-Mann-Whitney, Wilcoxon rank sum and the
Mann-Whitney-U test. However, this test should not be confused with the
Wilcoxon signed rank test (which is used for paired tests). To avoid
confusion this test is usually referred to as the Mann-Whitney U test,
which is used when the dependent variable to be examined is continuous
but the assumptions for parametric tests are violated.
Fortunately, the rstatix
developers have made the
function to do a Wilcox-test similar to doing a t_test. The
difficulty is in choosing the correct test to apply - which R will not
advise you on.
Let’s go back to our example of comparing weight loss between groups
male and female. The equivalent non-parametric version of the test we
performed before is:-
diet %>%
wilcox_test(wt.loss ~ gender)
The wilcox_test
is flexible in much the same way that
t_test
is. We can switch to applying a paired test by
adding the argument paired=TRUE
.
diet_long %>%
wilcox_test(weight ~ time_point, paired=TRUE)
Compare between more than two groups
Parametric (ANOVA)
The two-sample t-test is useful when we have just two groups of
continuous data to compare. When we want to compare more than two
groups, a one-way ANOVA can be used to simultaneously compare all
groups, rather than carrying out several individual two-sample t-tests.
The main advantage of doing this is that it reduces the number of tests
being carried out, meaning that the type I error rate (the probability
of seeing a significant result just by chance) does not become
inflated.
In order to justify if an ANOVA test is appropriate we have to test
for normality.
#by histogram
diet %>%
gghistogram(x = "wt.loss", facet.by = "diet.type", add_density = TRUE, y = "..density..") + stat_overlay_normal_density(col="red")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

#by Q-Q plot
diet %>%
ggqqplot(x = "wt.loss", facet.by = "diet.type")

#by shapiro test
group_by(diet, diet.type) %>%
shapiro_test(wt.loss)
A one-way ANOVA compares group means by partitioning the variation in
the data into between group variance and within group
variance. Like the other statistical tests we have encountered, the
functions in R do the hard work of calculating the statistics. The
anova_test
function is a tidy version of the ANOVA
test.
diet %>%
anova_test(wt.loss ~ diet.type)
ANOVA Table (type II tests)
Effect DFn DFd F p p<.05 ges
1 diet.type 2 73 5.383 0.007 * 0.129
When the test provides a significant result (like above) it tells us
that there is at least on difference in the groups. However, it does not
tell us which group is different. For this, we can apply a “post-hoc
test” such as the Tukey test. If anova_test
did not produce
a significant p-value, we wouldn’t proceed with this step
diet %>%
tukey_hsd(wt.loss ~ diet.type)
As we have seen previously, a standard method of presenting the
differences between groups is to use the stat_compare_means
function to automatically add p-values to a boxplot or violin plot
ggplot(diet, aes(x = diet.type, y = wt.loss)) + geom_violin() + geom_jitter(width=0.1) + stat_compare_means(method="anova")

However, in the case of more than two groups it will only show a
single p-value from the ANOVA rather than individual comparisons. We can
explicitly list particular contrasts we are interested in.
my_comparisons <- list( c("A", "B"), c("A", "C"), c("B", "C") )
ggplot(diet, aes(x = diet.type, y = wt.loss)) + geom_violin() + geom_jitter(width=0.1) +
stat_compare_means(method = "t.test",comparisons = my_comparisons)

Alternatively, we can manually-compute the p-values and add these to
the plot.
stat_res <- diet %>%
tukey_hsd(wt.loss ~ diet.type)
ggplot(diet, aes(x = diet.type, y = wt.loss)) + geom_violin() + geom_jitter(width=0.1)+
stat_pvalue_manual(stat_res, label = "p.adj",y.position = c(11, 13, 15))

Non-Parametric (Kruskal Wallis)
Data that do not meet the assumptions of ANOVA (e.g. normality) can
be tested using a non-parametric alternative. The
Kruskal-Wallis test is derived from the one-way ANOVA, but uses
ranks rather than actual observations. It is also the extension of the
Mann-Whitney U test to more than two groups.
diet %>%
kruskal_test(wt.loss ~ diet.type)
Like the one-way ANOVA this will only tell us that at least one group
is different and not specifically which group(s). The post-hoc
dunn.test
is recommended which also performs multiple
testing correction.
diet %>%
dunn_test(wt.loss ~ diet.type, p.adjust.method = "bonferroni")
At this point we could be about to recommend diet C to those that
wish to lose weight. However, are there any other factors in the data
that we should be considering? With ggplot2
we can quite
easily visualise the effects of multiple factors on the data. Lets add
both gender and diet type into the plot. It now appears that diet C is
having an effect on males but not females.
ggplot(diet, aes(x = diet.type, y = wt.loss,fill=gender)) + geom_boxplot()

Two-way ANOVA
The formula notation allows us to specify an
interaction between gender and diet type. In other words, we
are looking to see if the effect of diet type is different for males and
females. In R, the formula for an interaction is specified using a
*
between the variables that we are interested in assessing
the interaction for.
diet %>%
anova_test(wt.loss ~ diet.type*gender)
ANOVA Table (type II tests)
Effect DFn DFd F p p<.05 ges
1 diet.type 2 70 5.619 0.005 * 0.138000
2 gender 1 70 0.031 0.860 0.000448
3 diet.type:gender 2 70 3.153 0.049 * 0.083000
This tells us that an effect exists between diet type and gender, but
like before we have to run a post-hoc test to discover more
diet %>%
tukey_hsd(wt.loss ~ diet.type*gender) %>%
filter(p.adj.signif != "ns")
Exercise
The excel file ‘RCC2’ contains data about the expression levels of
some genes in patients with renal cell carcinoma. In your study, you put
the following hypotheses. Please test those alternative hypotheses and
state whether you will accept or reject each one.
- Females have a higher level of E2F3 than males
- ANXA expression levels vary between unilateral and bilateral
tumors
- Individuals with RCC grade II have different levels of E2F3 than
those with grade III or IV
- The mean value of miR499 decreases significantly after
treatment
- DFFA is higher in patients with grade IV tumors
Solutions
To be revealed during the workshop!
Exercise 1
## NEW
tab <- readxl::read_xlsx("data/EX Biostat P1.xlsx") %>% make_clean_names()
##2-Make a cross table showing the gender in the rows and tumor grade in the columns
count(tab, Gender, Tumor.grade)
##3-Define the percentage of Grade III tumors within females
freq_table(tab, Gender, Tumor.grade)
##4-Use the appropriate test to check if the tumor grade depends on the gender
count(tab, Gender, Tumor.grade) %>%
tidyr::pivot_wider(names_from = Gender,values_from = n) %>%
select(-Tumor.grade) %>%
chisq_test()
NA
Exercise 2
##1-Read the excel file called 'EX Biostat P2' into R
Biostat2 <- readxl::read_xlsx("data/EX Biostat P2.xlsx")
gghistogram(Biostat2, x = "Age")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

gghistogram(Biostat2, x = "Age", add_density = TRUE, y = "..density..") + stat_overlay_normal_density(col="blue")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

ggqqplot(Biostat2, x = "Age")

Biostat2 %>%
shapiro_test(vars = "Age")
# Age is normally distributed
gghistogram(Biostat2, x = "hospitalization days")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

gghistogram(Biostat2, x = "hospitalization days", add_density = TRUE, y = "..density..") + stat_overlay_normal_density(col="blue")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

ggqqplot(Biostat2, x = "hospitalization days")

Biostat2 %>%
shapiro_test(vars = "hospitalization days")
# hospitalization days NOT normally distributed
get_summary_stats(Biostat2)
NA
Exercise 3
3.1
RCC2 <- readxl::read_xlsx("data/RCC2.xlsx")
gghistogram(RCC2, x = "E2F3",
y = "..density..",
facet.by = "gender") + stat_overlay_normal_density(col="blue")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

RCC2 %>%
group_by(gender) %>%
shapiro_test(E2F3)
#both groups normally distributed
#parametric * 2 groups --> t-test
RCC2 %>%
group_by(gender) %>%
get_summary_stats("E2F3",type="common")
t_test(RCC2, E2F3 ~ gender,var.equal = TRUE)
#ANSWER=REJECT
ggplot(RCC2, aes(x = gender, y = E2F3)) + geom_violin() + geom_jitter(width = 0.1) + stat_compare_means(method = "t.test")

3.2
gghistogram(RCC2, x = "ANXA", facet.by = "Side")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

RCC2 %>%
group_by(Side) %>%
shapiro_test(ANXA)
#not normal
#non-parametric * 2 groups --> Wilcoxon (Mann Whitney U)
wilcox_test(RCC2, ANXA ~ Side)
#ANSWER=REJECT
ggplot(RCC2, aes(x = Side, y = ANXA)) + geom_violin() + geom_jitter() + stat_compare_means()

3.3
gghistogram(RCC2, x = "E2F3", facet.by = "Grade", y = "..density..") + stat_overlay_normal_density()
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

#3 groups normal
#parametric * > 2 groups --> ANOVA
anova_test(RCC2, E2F3 ~ Grade)
ANOVA Table (type II tests)
Effect DFn DFd F p p<.05 ges
1 Grade 2 111 5.492 0.005 * 0.09
#there is a difference but between which groups? --> post Hoc
tukey_hsd(RCC2, E2F3 ~ Grade)
#ANSWER= ACCEPT
my_comparisons <- list( c("II", "III"), c("II", "IV"), c("III", "IV") )
ggplot(RCC2, aes(x = Grade, y = E2F3)) + geom_violin() + geom_jitter(width=0.1) + stat_compare_means(method="t.test",comparisons = my_comparisons)

NA
NA
3.4
mir499_data <-
RCC2 %>%
select(contains("mir499")) %>%
tidyr::pivot_longer(everything())
gghistogram(mir499_data, x = "value", facet.by = "name")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

mir499_data %>%
group_by(name) %>%
shapiro_test(value)
#not normal
#non-parametric * 2 paired groups --> Wilcoxon signed rank test
mir499_data %>%
wilcox_test(value ~ name, paired = TRUE,alternative = "greater")
mir499_data %>%
group_by(name) %>%
get_summary_stats(value)
#it increases after ttt
#ANSWER = REJECT
3.5
gghistogram(RCC2, x = "DFFA", facet.by = "Grade")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

#not normal
#non-parametric * > 2 groups --> kruskal Wallis
RCC2 %>%
kruskal_test(DFFA ~ Grade)
#ANSWER= REJECT
#No need to perform post-hoc test
Ci0tLQp0aXRsZTogIlN0YXRpc3RpY2FsIEFuYWx5c2lzIG9mIEJpb2xvZ2ljYWwgRGF0YSIKYXV0aG9yOiAiTWFyayBEdW5uaW5nLCBOaWFtaCBFcnJpbmd0b24gYW5kIEF5YSBFbHdhemlyIgpkYXRlOiAnYHIgZm9ybWF0KFN5cy50aW1lKCksICJMYXN0IG1vZGlmaWVkOiAlZCAlYiAlWSIpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgY3NzOiBzdHlsZXNoZWV0cy9zdHlsZXMuY3NzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSxtZXNzYWdlPUZBTFNFKQpgYGAKCiMgTGluayB0byB0ZXN0IHN1bW1hcnkgc2xpZGUKCi0gW1N1bW1hcnkgc2xpZGUgZm9yIHBhcnQgMyBzdGF0XShTdW1tYXJ5X3NsaWRlLnBwdHgpCgojIEJhY2tncm91bmQKCkluIHRoaXMgY291cnNlIHdlIHdpbGwgZXhwbGFpbiB0aGUgdGhlb3J5IGJlaGluZCBjb21tb24gc3RhdGlzdGljYWwgdGVzdHMgdG8gY29tcGFyZSB0d28gb3IgbW9yZSBncm91cHMuIFdlIHdpbGwgaWxsdXN0cmF0ZSB0aGlzIHVzaW5nIGJpb2xvZ2ljYWxseS1tb3RpdmF0ZWQgZXhhbXBsZXMgYW5kIFIgY29kZSB0aGF0IHVzZXMgdGhlICJ0aWR5dmVyc2UiIHRlY2huaXF1ZXMgb2YgZGF0YSBtYW5pcHVsYXRpb24gYW5kIHZpc3VhbGl6YXRpb24uCgpUbyBpbnN0YWxsIHRoZSBlbnRpcmUgY29sbGVjdGlvbiBvZiB0aWR5dmVyc2UgcGFja2FnZXMgKHdoaWNoIGluY2x1ZGVzIG90aGVyIHVzZWZ1bCBkYXRhLXJlbGF0ZWQgcGFja2FnZXMgdGhhdCB3ZSB3aWxsIG5vdCB1c2UgdG9kYXkpLCB5b3UgbWF5IHdpc2ggdG8gdXNlIHRoZSBmb2xsb3dpbmc6LQoKYGBge3IgZXZhbD1GQUxTRX0KIyMgTWF5IHRha2Ugc29tZSB0aW1lIQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQpgYGAKClN0YXRpc3RpY3MgaGFzIGJlZW4gYSBmdW5kYW1lbnRhbCBwYXJ0IG9mIHRoZSBSIGxhbmd1YWdlIGZyb20gdGhlIGJlZ2lubmluZy4gQSB2YXN0IGFycmF5IG9mIHN0YXRpc3RpY2FsIHRlc3RzIGFuZCBhc3NvY2lhdGVkIHZpc3VhbGl6YXRpb25zIGFyZSBzdXBwb3J0ZWQuIEhvd2V2ZXIsIHRoZSBmdW5jdGlvbnMgdG8gcGVyZm9ybSB0aGVzZSBwcmVkYXRlIHRoZSBjcmVhdGlvbiBvZiB0aGUgYHRpZHl2ZXJzZWAgYW5kIGFyZSB1c2VkIGluIGEgbWFubmVyIHRoYXQgbWlnaHQgYmUgc29tZXdoYXQgY291bnRlci1pbnR1aXRpdmUgdG8gc29tZW9uZSB0aGF0IGlzIGZhbWlsaWFyIHdpdGggdGhlIGB0aWR5dmVyc2VgLiBUaGVyZWZvcmUgd2Ugd2lsbCB1c2UgYSBjb3VwbGUgb2YgYWRkLW9uIHBhY2thZ2VzIHRoYXQgaGF2ZSBiZWVuIGNyZWF0ZWQgdG8gcGVyZm9ybSBzdGF0aXN0aWNzIGluIGEgbWFubmVyIHRoYXQgaXMgY29tcGF0aWJsZSB3aXRoIHRoZSB0aWR5dmVyc2UgZWNvLXN5c3RlbS4KCi0gW3JzdGF0aXg6IFN0YXRpc3RpY2FsIHRlc3RpbmcgZm9yIHRoZSB0aWR5dmVyc2VdKGh0dHBzOi8vcnBrZ3MuZGF0YW5vdmlhLmNvbS9yc3RhdGl4LykKLSBbZ2dwdWJyOiDigJhnZ3Bsb3Qy4oCZIEJhc2VkIFB1YmxpY2F0aW9uIFJlYWR5IFBsb3RzXShodHRwczovL3Jwa2dzLmRhdGFub3ZpYS5jb20vZ2dwdWJyLykKCgpUaGUgc3BlY2lmaWMgc2V0IG9mIHJlcXVpcmVkIHBhY2thZ2VzIGlzIGFzIGZvbGxvd3M6LQoKYGBge3IgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcyhjKCJkcGx5ciIsCiAgICAgICAgICAgICAgICAgICAiZ2dwbG90MiIsCiAgICAgICAgICAgICAgICAgICAicmVhZHIiLAogICAgICAgICAgICAgICAgICAgInJlYWR4bCIsCiAgICAgICAgICAgICAgICAgICAicnN0YXRpeCIsCiAgICAgICAgICAgICAgICAgICAiZ2dwdWJyIiwKICAgICAgICAgICAgICAgICAgICJybWFya2Rvd24iLAogICAgICAgICAgICAgICAgICAgInRpZHlyIiwKICAgICAgICAgICAgICAgICAgICJ2Y2QiKSkgCmBgYAoKCgojIFBhcnQgSSAtIENvbnRpbmdlbmN5IHRhYmxlcwoKV2hlbiB3b3JraW5nIHdpdGggY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB3ZSBhcmUgdXN1YWxseSBpbnRlcmVzdGVkIGluIHRoZSAqZnJlcXVlbmNpZXMqIG9mIHRoZSBkaWZmZXJlbnQgY2F0ZWdvcmllcyBpbiBvdXIgc2FtcGxlLiBUbyBkaXNwbGF5IGRhdGEgZm9yIHR3byBvciBtb3JlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgY3Jvc3MtdGFidWxhdGlvbnMsIG9yIGNvbnRpbmdlbmN5IHRhYmxlcywgYXJlIGNvbW1vbmx5IHVzZWQgLSB3aXRoIDIgeCAyIHRhYmxlcyBiZWluZyB0aGUgc2ltcGxlc3QuIFdlIGNhbiB0aGVuIHRlc3Qgd2hldGhlciB0aGVyZSBpcyBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSByb3cgZmFjdG9yIGFuZCB0aGUgY29sdW1uIGZhY3RvciBieSBhICpjaGktc3F1YXJlZCB0ZXN0KiBvciBhICpGaXNoZXLigJlzIGV4YWN0IHRlc3QqLgoKVG8gZGVtb25zdHJhdGUgdGhlIGFuYWx5c2lzIG9mIGNvbnRpbmdlbmN5IHRhYmxlcyB3ZSB3aWxsIHVzZSBhIGRhdGFzZXQgcHJvdmlkZWQgd2l0aCB0aGUgYHZjZGAgcGFja2FnZS4gWW91IHdpbGwgbmVlZCB0byBpbnN0YWxsIHRoaXMgcGFja2FnZSB1c2luZyB0aGUgYGluc3RhbGwucGFja2FnZXNgIFIgZnVuY3Rpb24uCgoKYGBge3IgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygidmNkIikKYGBgCgoKYGBge3J9CiMjIExvYWQgdGhlIHBhY2thZ2VzIHdlIHdpbGwgbmVlZApsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocnN0YXRpeCkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkodmNkKQpgYGAKCgpUaGUgZGF0YSBmcmFtZSBgQXJ0aHJpdGlzYCBzaG91bGQgdGhlbiBiZSBhY2Nlc3NpYmxlIHdoaWNoIGlzIGRlc2NyaWJlZCBhczotIAoKPiBEYXRhIGZyb20gS29jaCAmIEVkd2FyZHMgKDE5ODgpIGZyb20gYSBkb3VibGUtYmxpbmQgY2xpbmljYWwgdHJpYWwgaW52ZXN0aWdhdGluZyBhIG5ldyB0cmVhdG1lbnQgZm9yIHJoZXVtYXRvaWQgYXJ0aHJpdGlzLgoKYGBge3J9CiNsZXQncyB1c2UgdGhlJ0FydGhyaXRpcycgZGF0YXNldCBpbiB0aGUgJ3ZjZCcgcGFja2FnZSAKQXJ0aHJpdGlzCmBgYAoKVGhlIGBjb3VudGAgZnVuY3Rpb24sIGluY2x1ZGVkIGluIGBkcGx5cmAgY2FuIGJlIHVzZWQgdG8gZ2l2ZSBhIHRhYnVsYXRpb24gb2YgdGhlIHZhbHVlcyBpbiBhbnkgY29sdW1uIGluIHRoZSBkYXRhIGZyYW1lLgoKYGBge3IgbWVzc2FnZT1GQUxTRX0KIyNvbmUgd2F5IHRhYmxlIChjb3VudCBvZiBvbmUgdmFyaWFibGUpCmNvdW50KEFydGhyaXRpcyxTZXgpCmBgYAoKV2UgY2FuIHF1aWNrbHkgdmlzdWFsaXNlIHRoZXNlIGNvdW50cyBhcyBhICpiYXJwbG90KiB3aXRoIGBnZ3Bsb3QyYC4gVGhlIGBnZW9tX2JhcmAgcGxvdCB0eXBlIHdpbGwgYXV0b21hdGljYWxseSBjb3VudCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyB0aGF0IHdpbGwgYmUgcGxvdHRlZCBvbiB0aGUgeS1heGlzLgoKYGBge3J9CmdncGxvdChBcnRocml0aXMsIGFlcyh4ID0gU2V4KSkgKyBnZW9tX2JhcigpCmBgYAoKVGhlIGZ1bmN0aW9uIGBmcmVxX3RhYmxlYCBmcm9tIGByc3RhdGl4YCBpcyBhbm90aGVyIHdheSBvZiBtYWtpbmcgdGhlIGNvdW50cyBhbmQgd2lsbCBhbHNvIGFkZCB0aGUgcHJvcG9ydGlvbnMgYXMgYW4gZXh0cmEgY29sdW1uLgoKYGBge3J9CiN0byBnZXQgcHJvcG9ydGlvbiBvZiBtYWxlcyBhbmQgZmVtYWxlcwpmcmVxX3RhYmxlKEFydGhyaXRpcyxTZXgpIApgYGAKClRoZSBgY291bnRgIGZ1bmN0aW9uIGNhbiBhbHNvIGNvbXBhcmUgdHdvIGNvbHVtbnMgZnJvbSBhIGRhdGEgZnJhbWUgaWYgYm90aCBjb2x1bW5zIGFyZSBnaXZlbiBhcyBhcmd1bWVudHMuCgpgYGB7cn0KY291bnQoQXJ0aHJpdGlzLFNleCxJbXByb3ZlZCkKYGBgCgpUaGVzZSBjYW4gYWxzbyBiZSBwbG90dGVkLCBidXQgdGhpcyB0aW1lIHdlIGhhdmUgdG8gdXNlIGBnZW9tX2NvbGAgdG8gc3BlY2lmeSB0aGUgdmFsdWVzIGZvciB0aGUgeS1heGlzLgoKYGBge3J9CmNvdW50KEFydGhyaXRpcyxTZXgsSW1wcm92ZWQpICU+JSAKZ2dwbG90KGFlcyh4ID0gU2V4LCBmaWxsID0gSW1wcm92ZWQsIHkgPSBuKSkgKyBnZW9tX2NvbCgpCmBgYAoKCmBgYHtyfQpjb3VudChBcnRocml0aXMsU2V4LEltcHJvdmVkKSAlPiUgCmdncGxvdChhZXMoeCA9IFNleCwgZmlsbCA9IEltcHJvdmVkLCB5ID0gbikpICsgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKClRoZSBgZnJlcV90YWJsZWAgZnVuY3Rpb24gY2FuIGJlIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBwcm9wb3J0aW9ucy4gSG93ZXZlciwgd2UgbmVlZCB0byBwYXkgYXR0ZW50aW9uIHRvIHRoZSBvcmRlciBpbiB3aGljaCB0aGUgdmFyaWFibGVzIGFyZSBzcGVjaWZpZWQgYXMgdGhpcyB3aWxsIGRpY3RhdGUgaG93IHRoZSBwcm9wb3J0aW9ucyBhcmUgY2FsY3VsYXRlZAoKQ29tcGFyZSB0aGUgb3V0cHV0IG9mOi0KCmBgYHtyfQpmcmVxX3RhYmxlKEFydGhyaXRpcyxTZXgsIEltcHJvdmVkKQpgYGAKCnRvOi0gCgpgYGB7cn0KZnJlcV90YWJsZShBcnRocml0aXMsSW1wcm92ZWQsIFNleCkKYGBgCgoKSGF2aW5nIGV4cGxvcmVkIG91ciBkYXRhLCB3ZSBjYW4gbm93IHBlcmZvcm0gc3RhdGlzdGljYWwgdGVzdGluZy4gVGhlIGZ1bmN0aW9uIGBjaGlzcV90ZXN0YCBjYW4gYmUgdXNlZCB0byBhc3Nlc3Mgd2hldGhlciBkaWZmZXJlbmNlcyBpbiBwcm9wb3J0aW9ucyBhcmUgc2lnbmlmaWNhbnQgb3Igbm90LiBXZSBhY3R1YWxseSBkb24ndCBuZWVkIHRvIGNhbGN1bGF0ZSB0aGUgcHJvcG9ydGlvbnM7IFIgd2lsbCBkbyB0aGlzIGZvciB1cy4KCkhvd2V2ZXIsIHdlIG5lZWQgdG8gcmUtZm9ybWF0IHRoZSBkYXRhIHNsaWdodGx5IGludG8gYSAqd2lkZSogdGFibGUgcmF0aGVyIHRoYW4gdGhlIGRlZmF1bHQgKmxvbmcqIG5hdHVyZSBvZiBhIGRhdGEgZnJhbWUgaW4gdGhlIGB0aWR5dmVyc2VgLiBXZSB0aGUgYHBpdm90X3dpZGVyYCBmdW5jdGlvbiB3ZSBjcmVhdGUgYSB0d28tYnktdHdvIHRhYmxlIHRoYXQgaXMgdHlwaWNhbGx5IHVzZWQgZm9yIGEgY29udGluZ2VuY3kgYW5hbHlzaXMuCgpgYGB7cn0KQXJ0aHJpdGlzICU+JSAKICBjb3VudChJbXByb3ZlZCwgVHJlYXRtZW50KSAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gbixuYW1lc19mcm9tID0gSW1wcm92ZWQpCiMjd291bGQgYWxzbyB3b3JrIHdpdGggbmFtZXNfZnJvbSBUcmVhdG1lbnQKYGBgCgpBbmQgbm93IHJlbW92ZSB0aGUgYFRyZWF0bWVudGAgY29sdW1uIGFzIHRoZSBgY2hpc3FfdGVzdGAgZnVuY3Rpb24gaXMgb25seSBleHBlY3RpbmcgbnVtZXJpYyBkYXRhLiBUaGUgcmVzdWx0cyBhcmUgcHJlc2VudGVkIGluIGEgYHRpZHl2ZXJzZWAgdGliYmxlIHRoYXQgYW5kIHdlIGNhbiBpbnRlcnByZXQgdGhlIHRlc3Qgc3RhdGlzdGljcyBhbmQgcC12YWx1ZSBmcm9tIHRoaXMgdGFibGUKCmBgYHtyfQpBcnRocml0aXMgJT4lIAogIGNvdW50KEltcHJvdmVkLCBUcmVhdG1lbnQpICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIodmFsdWVzX2Zyb20gPSBuLG5hbWVzX2Zyb20gPSBJbXByb3ZlZCkgJT4lIApzZWxlY3QoLVRyZWF0bWVudCkgICU+JSAKICBjaGlzcV90ZXN0KCkKYGBgCgpOb3RlIHRoYXQgdGhlIG9ubHkgbGluZSBvZiBjb2RlIHRvIHBlcmZvcm0gdGhlIHRlc3QgaXMgYGNoaXNxX3Rlc3RgLiBUaGUgcHJlY2VkaW5nIGxpbmVzIGFyZSB1c2VkIHRvIG1hbmlwdWxhdGUgb3VyIGRhdGEgaW50byB0aGUgY29ycmVjdCBmb3JtYXQuIElmIG91ciBkYXRhIGFyZSBhbHJlYWR5IGluIGEgbnVtZXJpYyB0YWJsZSB3ZSBtaWdodCBiZSBhYmxlIHRvIHVzZSBgY2hpc3FfdGVzdGAgZGlyZWN0bHkuCgpUaGUgY2hpLXNxdWFyZWQgdGVzdCB3b3JrcyBieSBjb21wYXJpbmcgdGhlIGZyZXF1ZW5jaWVzIGluIGVhY2ggY2VsbCBvZiBvdXIgdGFibGUgdG8gd2hhdCB3ZSB3b3VsZCBleHBlY3QgYnkgY2hhbmNlIChpLmUuIGlmIHRoZXJlIHdhcyBubyBzaWduaWZpY2FudCBhc3NvY2lhdGlvbikuIElmIHdlIHdhbnQgdG8gc2VlIHdoYXQgdGhlIGV4cGVjdGVkIGZyZXF1ZW5jaWVzIHdvdWxkIGJlIHdlIGNhbiBydW4gYGV4cGVjdGVkX2ZyZXFgIGFmdGVyIGBjaGlzcV90ZXN0YC4KCmBgYHtyfQpBcnRocml0aXMgJT4lIAogIGNvdW50KEltcHJvdmVkLCBUcmVhdG1lbnQpICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIodmFsdWVzX2Zyb20gPSBuLG5hbWVzX2Zyb20gPSBJbXByb3ZlZCkgJT4lCnNlbGVjdCgtVHJlYXRtZW50KSAgJT4lIAogIGNoaXNxX3Rlc3QoKSAlPiUgZXhwZWN0ZWRfZnJlcSgpCmBgYAoKSG93ZXZlciwgdGhlIGBjaGlzcV90ZXN0YCBmdW5jdGlvbiBpcyBub3QgYXBwcm9wcmlhdGUgaW4gYWxsIGNpcmN1bXN0YW5jZXMuCgpgYGB7cn0KQXJ0aHJpdGlzICU+JSAKICBjb3VudChJbXByb3ZlZCwgU2V4KSAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gbixuYW1lc19mcm9tID0gSW1wcm92ZWQpICU+JSAKICBzZWxlY3QoLVNleCkgICU+JSAKICBjaGlzcV90ZXN0IApgYGAKClRoZSBGaXNoZXIgdGVzdCBpcyByZWNvbW1lbmRlZCBmb3IgdGFibGVzIHdpdGggbG93IG51bWJlcnMgb2Ygb2JzZXJ2YXRpb25zIChlLmcuIHdoZW4gbW9yZSB0aGFuIDIwJSBvZiBjZWxscyBoYXZlICpleHBlY3RlZCBmcmVxdWVuY2llcyogPCA1KQoKYGBge3J9CkFydGhyaXRpcyAlPiUgCiAgY291bnQoSW1wcm92ZWQsIFNleCkgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9IG4sbmFtZXNfZnJvbSA9IEltcHJvdmVkKSAlPiUgCiBzZWxlY3QoLVNleCkgICU+JSAKICBmaXNoZXJfdGVzdApgYGAKCkluIHRoaXMgY2FzZSB3ZSBoYWQgc29tZSBsb3cgZXhwZWN0ZWQgZnJlcXVlbmNpZXMgc28gdGhlIEZpc2hlciB0ZXN0IHdhcyBtb3JlIGFwcHJvcHJpYXRlCgpgYGB7cn0KQXJ0aHJpdGlzICU+JSAKICBjb3VudChJbXByb3ZlZCwgU2V4KSAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gbixuYW1lc19mcm9tID0gSW1wcm92ZWQpICU+JSAKICBzZWxlY3QoLVNleCkgICU+JSAKICBjaGlzcV90ZXN0ICU+JSAKICBleHBlY3RlZF9mcmVxKCkKYGBgCgoKPGRpdiBjbGFzcz0iZXhlcmNpc2UiPgoKKipFeGVyY2lzZSoqCgoxLSBSZWFkIHRoZSBleGNlbCBmaWxlIGNhbGxlZCBgRXggQmlvc3RhdCBQMS54bHN4YCBpbnRvIFIgKHNlZSBiZWxvdyBmb3IgdGhlIHJlcXVpcmVkIGNvZGUpLiBXZSByZWNvbW1lbmQgdXNpbmcgYG1ha2VfY2xlYW5fbmFtZXNgIGZ1bmN0aW9uIGZyb20gYHJzdGF0aXhgIHRvIG1ha2Ugc3VyZSB0aGUgY29sdW1uIG5hbWVzIGFyZSAiY2xlYW4iIChpLmUuIHdpdGhvdXQgc3BhY2VzIG9yIG90aGVyIGNoYXJhY3RlcnMgdGhhdCBjb3VsZCBjYXVzZSBpc3N1ZXMgZm9yIFIpLgoKMi0gVXNlIHRoZSBgY291bnRzYCBmdW5jdGlvbiB0byBtYWtlIGEgY3Jvc3MtdGFidWxhdGlvbiBvZiBUdW1vciBncmFkZSBhZ2FpbnN0IEdlbmRlcgoKMy0gRGV0ZXJtaW5lIHRoZSBwcm9wb3J0aW9uIG9mIEdyYWRlIElJSSB0dW1vcnMgd2l0aGluIGZlbWFsZXMgCgo0LSBVc2UgdGhlIGFwcHJvcHJpYXRlIHRlc3QgdG8gY2hlY2sgaWYgdGhlIHR1bW9yIGdyYWRlIGRlcGVuZHMgb24gdGhlIGdlbmRlciAKCmBgYHtyIGV2YWw9RkFMU0V9CiMjIHRoZSByZWFkeGwgcGFja2FnZSBpcyByZXF1aXJlZCB0byByZWFkIHhscyBhbmQgeGxzeCBmaWxlcyBpbnRvIFIKIyMgSG93ZXZlciwgY3N2IGFuZCB0c3YgZmlsZXMgYXJlIHJlY29tbWVuZGVkIHRvIHN0b3JlIGRhdGEKdGFiIDwtIHJlYWR4bDo6cmVhZF94bHN4KCJkYXRhL0VYIEJpb3N0YXQgUDEueGxzeCIpICU+JSAKICBtYWtlX2NsZWFuX25hbWVzKCkKYGBgCgo8L2Rpdj4KCiMgUGFydCBJSSAtIEhvdyB0byBhc3Nlc3Mgbm9ybWFsaXR5CgpXZSB3aWxsIHJlYWQgc29tZSBleGFtcGxlIGRhdGEgdG8gaWxsdXN0cmF0ZSBob3cgb25lIHdvdWxkIHRlc3QgZm9yIGEgbm9ybWFsbHktZGlzdHJpYnV0ZWQgdmFyaWFibGUuIFRoaXMgcHJvcGVydHkgaXMgaW1wb3J0YW50IGFzIGl0IGluZmx1ZW5jZXMgd2hpY2ggdGVzdCB3ZSBzaG91bGQgdXNlLgoKT25lIG9mIHRoZSBiZXN0IHdheXMgb2YgZGlzcGxheWluZyBkYXRhIGlzIGJ5IHVzaW5nIGEgZ3JhcGguIEdyYXBocyBjYW4gbWFrZSBib3RoIHNpbXBsZSBhbmQgY29tcGxleCBkYXRhIGVhc2llciB0byB1bmRlcnN0YW5kIGJ5IG1ha2luZyBpdCBlYXNpZXIgdG8gc3BvdCB0cmVuZHMgYW5kIHBhdHRlcm5zLiBXZSBjYW4gdXNlIHBsb3RzIHRvIHZpZXcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBvdXIgZGF0YSAobWluaW11bSwgbWF4aW11bSwgbWlkLXBvaW50LCBzcHJlYWQgZXRjKSBhbmQgdG8gZW5zdXJlIHRoYXQgdGhlIHZhbHVlcyBpbiBvdXIgZGF0YXNldCBzZWVtIHJlYWxpc3RpYyAoZS5nLiBubyBvdXRsaWVycykuIE1hbnkgc3RhdGlzdGljYWwgdGVzdHMgcmVseSBvbiB0aGUgYXNzdW1wdGlvbiB0aGF0IHRoZSBkYXRhIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZC4KClRoZSBkYXRhIGZvciB0aGlzIHNlY3Rpb24gYXJlIHRvIGJlIGZvdW5kIGluIHRoZSBmaWxlIGBub3JtYWxfZXhhbXBsZS5jc3ZgIGluIHRoZSBgZGF0YWAgZm9sZGVyLiBZb3Ugd2lsbCBuZWVkIHRvIHNwZWNpZnkgdGhlIGZpbGUgcGF0aCBhY2NvcmRpbmdseS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkocmVhZHIpCmRmMSA8LSByZWFkX2NzdigiZGF0YS9ub3JtYWxfZXhhbXBsZS5jc3YiKQpgYGAKCldlIGNhbiBpbnNwZWN0IHRoZSBkYXRhIGluIFJTdHVkaW8gYW5kIGRpc2NvdmVyIHRoYXQgaXQgY29uc2lzdHMgb2YgYSB0aWR5IGRhdGFzZXQgd2l0aCBudW1lcmljIHZhbHVlcyBpbiBhIGNvbHVtbiBjYWxsZWQgYFZhbHVlc2AgYW5kIGEgY29sdW1uIGBWYXJgIHRvIGluZGljYXRlIGEgdmFyaWFibGUgbmFtZSAoYHhgKQoKYGBge3J9ClZpZXcoZGYxKQpgYGAKClZhcmlvdXMgZ3JhcGhpY2FsIG1ldGhvZHMgYXJlIGF2YWlsYWJsZSB0byBhc3Nlc3MgdGhlIGRpc3RyaWJ1dGlvbi4gVGhlIGZpcnN0IG9mIHdoaWNoIGlzIGEgKmhpc3RvZ3JhbSouIEluIHRoaXMgZ3JhcGggdGhlIGRhdGEgYXJlIHNwbGl0IGludG8gImJpbnMiIGFuZCB0aGUgdmFsdWUgb24gdGhlIGB5YCBheGlzIGNvcnJlc3BvbmRzIHRvIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGluIHRoYXQgYmluLiBUaGUgdXNlciBvbmx5IGhhcyB0byBzcGVjaWZ5IHRoZSB2YXJpYWJsZSB0byBiZSBwbG90dGVkLCBhbmQgZnVuY3Rpb24gdGFrZXMgY2FyZSBvZiB0aGUgYmlubmluZy4gRnJvbSB0aGlzIHBsb3Qgd2UgY2FuIGp1ZGdlIHdoYXQgdGhlIGF2ZXJhZ2UgdmFsdWUgb2YgdGhlIGRhdGEgaXMsIGFuZCB0aGUgc3ByZWFkLgoKSGlzdG9ncmFtcyBjYW4gYmUgbWFkZSBpbiBgZ2dwbG90MmAgYnkgdXNpbmcgdGhlIGBnZW9tX2hpc3RgIGZ1bmN0aW9uIChvciBpbmRlZWQgdGhlIGJhc2UgYGhpc3RgIGZ1bmN0aW9uKS4gSGVyZSB3ZSBhcmUgZ29pbmcgdG8gbWFrZSB1c2Ugb2YgdGhlIGBnZ2hpc3RvZ3JhbWAgZnVuY3Rpb24gZnJvbSBgZ2dwdWJyYCBhcyBpdCBpcyBhIGJpdCBtb3JlIGNvbnZlbmllbnQuCgpgYGB7cn0KZ2doaXN0b2dyYW0oZGYxLHg9IlZhbHVlIikKYGBgCgoKV2hlbiBhc3Nlc3NpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIHZhcmlhYmxlLCB5b3UgbWlnaHQgYmUgdGVtcHRlZCB0byBwbG90IHRoZSBoaXN0b2dyYW0gYW5kICpkZW5zaXR5KiBvbiB0aGUgc2FtZSBwbG90LiBgZ2doaXN0b2dyYW1gIGhhcyB0aGUgYXJndW1lbnQgYGFkZF9kZW5zaXR5YCwgd2hpY2ggc2hvdWxkIGRvIHRoZSBqb2IuCgpgYGB7cn0KZ2doaXN0b2dyYW0oZGYxLHg9IlZhbHVlIixhZGRfZGVuc2l0eSA9IFRSVUUpCmBgYAoKSG93ZXZlciwgdGhpcyBkb2Vzbid0IHdvcmsuIElmIHlvdSBjaGVjayB0aGUgeS1heGlzIGxpbWl0cyBvbiB0aGUgaGlzdG9ncmFtIGFuZCBkZW5zaXR5IHBsb3RzLCB5b3UnbGwgbm90aWNlIHRoZXkgYXJlIG9uIGEgZGlmZmVyZW50IHNjYWxlLiBDb252ZW5pZW50bHkgdGhlcmUgaXMgYW4gYXJndW1lbnQgaW4gYGdnaGlzdG9ncmFtYCB0aGF0IHNvbHZlcyB0aGlzIGlzc3VlLgoKCmBgYHtyfQpnZ2hpc3RvZ3JhbShkZjEseD0iVmFsdWUiLAogICAgICAgICAgICBhZGRfZGVuc2l0eSA9IFRSVUUsCiAgICAgICAgICAgIHk9Ii4uZGVuc2l0eS4uIikKYGBgCgpXZSBjYW4gYWRkIHRoZSAqc3RhbmRhcmQqIG5vcm1hbCBjdXJ2ZSB3aXRoIHRoZSBmb2xsb3dpbmcgY29kZS4gVG8gaGVscCBkaXN0aW5ndXNoIHRoZSBzdGFuZGFyZCBub3JtYWwgd2UgY2FuIGNoYW5nZSB0aGUgY29sb3VyIHRoaXMgaXMgcGxvdHRlZCBpbi4KCmBgYHtyfQpnZ2hpc3RvZ3JhbShkZjEseD0iVmFsdWUiLGFkZF9kZW5zaXR5ID0gVFJVRSx5PSIuLmRlbnNpdHkuLiIpICsgc3RhdF9vdmVybGF5X25vcm1hbF9kZW5zaXR5KGNvbD0ic3RlZWxibHVlIixsd2Q9MixsdHk9MikKYGBgCgoKQSBib3ggcGxvdCBpcyBhbiBleGNlbGxlbnQgd2F5IG9mIGRpc3BsYXlpbmcgY29udGludW91cyBkYXRhIHdoZW4geW91IGFyZSBpbnRlcmVzdGVkIGluIHRoZSBzcHJlYWQgb2YgeW91ciBkYXRhLiBUaGUgImJveCIgb2YgdGhlIGJveCBwbG90IGNvcnJlc3BvbmRzIHRvIHRoZSBsb3dlciBhbmQgdXBwZXIgcXVhcnRpbGVzIG9mIHRoZSByZXNwZWN0aXZlIG9ic2VydmF0aW9ucyBhbmQgdGhlIGJhciB3aXRoaW4gdGhlIGJveCwgdGhlIG1lZGlhbi4gVGhlIHdoaXNrZXJzIG9mIHRoZSBib3ggcGxvdCBjb3JyZXNwb25kIHRvIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHRoZSBsb3dlci91cHBlciBxdWFydGlsZSBhbmQgdGhlIHNtYWxsZXIgb2Y6IHRoZSBzbWFsbGVyL2xhcmdlc3QgbWVhc3VyZW1lbnQgKk9SKiAxLjUgdGltZXMgdGhlIGludGVyIHF1YXJ0aWxlIHJhbmdlLiBBIGRpc2FkdmFudGFnZSBvZiB0aGUgYm94IHBsb3QgaXMgdGhhdCB5b3UgZG9u4oCZdCBzZWUgdGhlIGV4YWN0IGRhdGEgcG9pbnRzLiBIb3dldmVyLCBib3ggcGxvdHMgYXJlIHZlcnkgdXNlZnVsIGluIGxhcmdlIGRhdGFzZXRzIHdoZXJlIHBsb3R0aW5nIGFsbCBvZiB0aGUgZGF0YSBtYXkgZ2l2ZSBhbiB1bmNsZWFyIHBpY3R1cmUgb2YgdGhlIHNoYXBlIG9mIHlvdXIgZGF0YS4KCkFnYWluLCB3ZSB1c2UgYGdnYm94cGxvdGAgZnJvbSBgZ2dwdWJyYCBmb3IgY29udmVuaWVuY2UuCgpgYGB7cn0KZ2dib3hwbG90KGRmMSwgeSA9ICJWYWx1ZSIpCmBgYAoKQSAqdmlvbGluIHBsb3QqIGlzIHNvbWV0aW1lcyBpbnN0ZWFkIG9mIHRoZSBib3hwbG90IHRvIHByb3ZpZGUgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZGVuc2l0eS4KCmBgYHtyfQpnZ3Zpb2xpbihkZjEsIHkgPSAiVmFsdWUiKQpgYGAKCkluZGl2aWR1YWwgcG9pbnRzIGNhbiBhbHNvIGJlIGFkZGVkIHdpdGggdGhlIGBqaXR0ZXJgIGFyZ3VtZW50OyBhdm9pZGluZyBvdmVyLXBsb3R0aW5nIGJ5IGFkZGluZyByYW5kb20gbm9pc2UgYWxvbmcgdGhlIHgtYXhpcy4KCmBgYHtyfQpnZ3Zpb2xpbihkZjEsIHkgPSAiVmFsdWUiLGFkZCA9ICJqaXR0ZXIiKQpgYGAKCgpGaW5hbGx5LCB3ZSBoYXZlIGEgIipxcS1wbG90KiIgd2hpY2ggYWxsb3dzIHRvIGNvbXBhcmUgdGhlIHF1YW50aWxlcyBvZiBvdXIgZGF0YXNldCBhZ2FpbnN0IGEgdGhlb3JldGljYWwgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gSWYgdGhlIG1ham9yaXR5IG9mIHBvaW50cyBsaWUgb24gYSBkaWFnb25hbCBsaW5lIHRoZW4gdGhlIGRhdGEgYXJlIGFwcHJveGltYXRlbHkgbm9ybWFsLiBUaGUgYGdncXFwbG90YCBmdW5jdGlvbiBpbiBgZ2dwdWJyYCBpcyB0aGUgbW9zdCBjb252ZW5pZW50IHdheSBvZiBjcmVhdGluZyB0aGlzIHBsb3QuCgpgYGB7cn0KZ2dxcXBsb3QoZGYxLCB4PSJWYWx1ZSIpCmBgYAoKVGhlc2UgZ3JhcGhpY2FsIG1ldGhvZHMgYXJlIGJ5IGZhciB0aGUgZWFzaWVzdCB3YXkgdG8gYXNzZXNzIGlmIGEgZ2l2ZW4gZGF0YXNldCBpcyBub3JtYWxseS1kaXN0cmlidXRlZC4gSG93ZXZlciwgeW91IGRvIG5vdCBuZWNlc3NhcmlseSBuZWVkIHRvIGdlbmVyYXRlIGFuZCByZXBvcnQgYWxsIHRoZSBwbG90cyBmb3IgeW91ciBkYXRhOyBqdXN0IGFzIG1hbnkgYXMgeW91IHRvIGluZm9ybSB5b3VyIGRlY2lzaW9uLgoKRm9yICJyZWFsLWxpZmUiIGRhdGEsIHRoZSByZXN1bHRzIGFyZSB1bmxpa2VseSB0byBnaXZlIGEgcGVyZmVjdCBwbG90LCBzbyBzb21lIGRlZ3JlZSBvZiBqdWRnZW1lbnQgYW5kIHByaW9yIGV4cGVyaWVuY2Ugd2l0aCB0aGUgZGF0YSB0eXBlIGFyZSByZXF1aXJlZC4gIEluZGVlZCwgaXQgc2hvdWxkIGJlIG5vdGVkIHRoYXQgdGhlIGRhdGFzZXQgdmlzdWFsaXNlZCBpbiB0aGUgYWJvdmUgcGxvdHMgd2FzIHNhbXBsZWQgZnJvbSBhIG5vcm1hbCBkaXN0cmlidXRpb24uIEV2ZW4gdGhlbiwgdGhlIHBsb3RzIHdlcmUgbm90IDEwMCUgY29udmluY2luZyEKCiMjIFRlc3RzIGZvciBub3JtYWxpdHkKCkFsdGhvdWdoIHRoZWlyIHVzYWdlIGlzIGNvbnRlbnRpb3VzIGFtb25nc3Qgc3RhdGlzdGljaWFucywgdGhlcmUgYXJlIGEgZmV3IG1ldGhvZHMgZm9yIHRlc3Rpbmcgd2hldGhlciB2YXJpYWJsZXMgYXJlIG5vcm1hbGx5LWRpc3RyaWJ1dGVkIG9yIG5vdC4gSWYgdGhlIHAtdmFsdWUgaXMgc3VmZmljaWVudGx5IHNtYWxsIGZyb20gdGhlc2UgbWV0aG9kcyB0aGVuIHdlIGNvbmNsdWRlIHRoYXQgdGhlIGRhdGEgYXJlICpub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQqLiBIb3dldmVyLCBzb21lIHN0YXRpc3RpY2lhbnMgcHJlZmVyIHRvIHVzZSBncmFwaGljYWwgbWV0aG9kcyBhbmQgdGhlaXIgaW50dWl0aW9uIGFib3V0IHRoZSBkYXRhIG9yIHByaW9yIGtub3dsZWRnZSBvZiB0aGUgZGF0YSB0eXBlIChlLmcuIHNvbWUgbWVhc3VyZXMgYXJlIGdlbmVyYWxseSBiZWxpZXZlZCB0byBiZSBub3JtYWxseS1kaXN0cmlidXRlZCkKCmBgYHtyfQojc2hhcGlybyB0ZXN0IGZyb20gcnN0YXRpeAojcDwwLjA1IC4uLmRpZmZlcmVuY2UgYmV0d2VlbiBkYXRhIGFuZCBub3JtYWxpdHkuLmRhdGEgbm90IG5vcm1hbAojcD4wLjA1IC4uLm5vIGRpZmYgYmV0d2VlbiBkYXRhIGFuZCBub3JtYWxpdHkgLi5kYXRhIG5vcm1hbGx5IGRpc3RyaWJ1dGVkCnNoYXBpcm9fdGVzdChkZjEsVmFsdWUpIApgYGAKCiMjIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MKCldoZW4gcGVyZm9ybWluZyBhIHN0YXRpc3RpY2FsIGFuYWx5c2lzIGl0IGlzIGNvbW1vbiBwcmFjdGljZSB0byByZXBvcnQgb24gdGhlIGF2ZXJhZ2UgYW5kIHZhcmlhYmlsaXR5LiBPdXIgZGVjaXNpb24gYWJvdXQgd2hldGhlciB0aGUgZGF0YSBhcmUgbm9ybWFsbHktZGlzdHJpYnV0ZWQgd2lsbCBpbmZsdWVuY2Ugd2hhdCBtZWFzdXJlcyB3ZSByZXBvcnQuIEluIGByc3RhdGl4YCB0aGVyZSBpcyBhIGZ1bmN0aW9uIGNhbGxlZCBgZ2V0X3N1bW1hcnlfc3RhdHNgIHRoYXQgY2FuIGNhbGN1bGF0ZSBzdWNoIHN1bW1hcmllcy4KCkZvciBhIGRhdGFzZXQgdGhhdCBpcyBub3JtYWxseS1kaXN0cmlidXRlZCwgYXBwcm9wcmlhdGUgbWVhc3VyZXMgb2YgdGhlIGF2ZXJhZ2UgYW5kIHZhcmlhYmlsaXR5IGFyZSB0aGUgKm1lYW4qIGFuZCAqc3RhbmRhcmQgZGV2aWF0aW9uKi4gCgoKYGBge3J9CmRmMSAlPiUgCiAgZ2V0X3N1bW1hcnlfc3RhdHModHlwZT0iY29tbW9uIikgCmBgYAoKYGBge3J9CmRmMSAlPiUgCiAgZ2V0X3N1bW1hcnlfc3RhdHModHlwZSA9ICJjb21tb24iKSAlPiUgCiAgc2VsZWN0KG1lYW4sIHNkKQpgYGAKCgo8ZGl2IGNsYXNzPSJleGVyY2lzZSI+CioqRXhlcmNpc2UqKgoKMS0gUmVhZCB0aGUgZXhjZWwgZmlsZSBjYWxsZWQgYEV4IEJpb3N0YXQgUDIueGxzeGAgaW50byBSIAoKMi0gRGVjaWRlIGlmIHRoZSBhZ2UgYW5kIGhvc3BpdGFsaXphdGlvbiBkYXlzIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZC4gVm90ZSBmb3IgeW91ciBmaW5kaW5ncyBvbiAqKndvb2NsYXAqKgoKMy0gQ2FsY3VsYXRlIHRoZSBhcHByb3ByaWF0ZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIFttZWFuIGFuZCBTRCwgIG9yIG1lZGlhbiBhbmQgSVFSXSBmb3IgZWFjaCB2YXJpYWJsZQoKPC9kaXY+CgoKCiMgUGFydCBJSUkgLSBTaWduaWZpY2FuY2UgdGVzdHMgZm9yIGNvbnRpbnVvdXMgdmFyaWFibGVzCgpJbiB0aGlzIHBhcnQgd2Ugd2lsbCBzaG93IGhvdyB0byBwZXJmb3JtIHRlc3RzIHRvIGNvbXBhcmUgMSwgMiAob3IgbW9yZSkgY29udGludW91cyB2YXJpYWJsZXMuIFRoZSBkYXRhc2V0LCBwcm92aWRlZCBieSBNQVNIIGF0IFRoZSBVbml2ZXJzaXR5IG9mIFNoZWZmaWVsZCwgZGVzY3JpYmVzIGluZGl2aWR1YWxzIHRoYXQgaGF2ZSBiZWVuIGZvbGxvd2luZyBkaWZmZXJlbnQgZGlldHMgYW5kIHRoZWlyIGFnZSBhbmQgZ2VuZGVyLiBUaGUgbWFpbiBnb2FsIG9mIGludGVyZXN0IGlzIHRvIGRldGVybWluZSB3aGljaCBvZiB0aHJlZSBjb21wZXRpbmcgZGlldCByZWdpbWVzIHJlc3VsdHMgaW4gdGhlIGdyZWF0ZXN0IHdlaWdodCBsb3NzLiBIb3dldmVyLCB3ZSBjYW4gdXNlIHRoZSBkYXRhc2V0IHRvIGRlbW9uc3RyYXRlIG90aGVyIHR5cGVzIG9mIHRlc3QuCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpkaWV0IDwtIHJlYWRfY3N2KCJkYXRhL2RpZXQuY3N2IikKZGlldApgYGAKCgoKIyMgT25lLXNhbXBsZSB0ZXN0CgpUaGUgZmlyc3QgaHlwb3RoZXNpcyB3ZSB3aWxsIHRlc3QgaXMgd2hldGhlciB0aGUgcGVvcGxlIGluIHRoZSBzdHVkeSBhcmUgb3ZlcndlaWdodCBvciBub3QuIFRoaXMgZmlyc3QgaW52b2x2ZXMgc29tZSBtYW5pcHVsYXRpb24gb2YgdGhlIHRhYmxlIHRvIGNhbGN1bGF0ZSBhbiBleHRyYSB2YXJpYWJsZTsgdGhlIEJvZHkgTWFzcyBJbmRleCAoQk1JKS4gV2Ugd2lsbCB0ZXN0IGlmIHBlb3BsZSBpbiBvdXIgc3R1ZHkgYXJlIG92ZXJ3ZWlnaHQsIHdoZXJlIG92ZXJ3ZWlnaHQgaXMgZGVmaW5lZCBhcyBoYXZpbmcgYSBCTUkgb3ZlciAyNS4KCiRCTUkgPSB3ZWlnaHQgIC8gaGVpZ2h0XjIkCgooKndoZXJlIHRoZSB3ZWlnaHQgaXMgbWVhc3VyZWQgaW4ga2csIGFuZCB0aGUgaGVpZ2h0IGluIG1ldHJlcyopCgo8ZGl2IGNsYXNzPSJleGVyY2lzZSI+CioqRXhlcmNpc2UgKHNob3J0KSoqCi0gQWRkIGEgbmV3IHZhcmlhYmxlIHRvIHRoZSBkYXRhIGZyYW1lIGZvciB0aGUgQk1JIG9mIGVhY2ggcGVyc29uIAogICAgKyB5b3UgbWlnaHQgd2FudCB0byBkbyB0aGlzIGluIG11bHRpcGxlIHN0ZXBzIHVzaW5nIHRoZSBgJT4lYCBub3RhdGlvbgo8L2Rpdj4KCmBgYHtyfQpkaWV0IDwtIGRpZXQgJT4lIAogIG11dGF0ZShCTUkgPWluaXRpYWwud2VpZ2h0IC8gKGhlaWdodC8xMDApXjIpCgpgYGAKCldlIGNhbiBub3cgdGVzdCBvdXIgbmV3IHZhcmlhYmxlIGZvciBub3JtYWxpdHkgdXNpbmcgdGhlIHBsb3RzIGFuZCB0ZXN0cyBmcm9tIGVhcmxpZXIsIGFsdGhvdWdoIHdlIHdpbGwgbm90IHNob3cgYWxsIHRoZSBwbG90cyBoZXJlLgoKYGBge3IgZXZhbD1GQUxTRX0KZ2doaXN0b2dyYW0oZGlldCwgeCA9ICJCTUkiLCAsYWRkX2RlbnNpdHkgPSBUUlVFLHk9Ii4uZGVuc2l0eS4uIikrIHN0YXRfb3ZlcmxheV9ub3JtYWxfZGVuc2l0eShjb2w9InN0ZWVsYmx1ZSIpCmBgYAoKVGhlIG9uZS1zYW1wbGUgdC10ZXN0IGlzIGltcGxlbWVudGVkIGluIHRoZSBmdW5jdGlvbiBgdF90ZXN0YCAoYXMgYXJlIHRoZSB2YXJpb3VzIHR5cGVzIG9mIHQtdGVzdCB0aGF0IHdlIHdpbGwgc2VlKS4gVGhlIHZhcmlhYmxlcyB0byBiZSB1c2VkIGluIHRoZSB0ZXN0IGFyZSBkZWZpbmVkIHVzaW5nIFIncyBmb3JtdWxhIGB+YCBzeW50YXguIAoKYFkgfiBYYAoKV2hlcmUgYFlgIGlzIGEgKm51bWVyaWMqIHZhcmlhYmxlIGFuZCBgWGAgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBpbmRpY2F0aW5nIHRoZSBncm91cHMgdGhhdCBlYWNoIHBhcnRpY3VsYXIgdmFsdWUgb2YgYFlgIGJlbG9uZ3MgdG8uCgpJbiB0aGUgY2FzZSBvZiBhIG9uZS1zYW1wbGUgdGVzdCB3ZSBhcmUgdGVzdGluZyBvbmUgbnVtZXJpYyB2YXJpYWJsZSBhZ2FpbnN0IGEga25vd24gb3IgcG9wdWxhdGlvbiBtZWFuIChgbXVgKS4gQXMgd2UgZG9uJ3QgaGF2ZSBhIGdyb3VwcyB0byBjb21wYXJlLCB0aGlzIGlzIHdyaXR0ZW4gYXM6LQoKYFkgfiAxYAoKCmBgYHtyfQpkaWV0ICU+JSAKICB0X3Rlc3QoQk1JIH4xKQpgYGAKPGRpdiBjbGFzcz0iaW5mb3JtYXRpb24iPgpUaGUgdmFyaW91cyBzdGF0aXN0aWNhbCB0ZXN0cyBpbiBgcnN0YXRpeGAgYWxsIGhhdmUgdGhlIGBfdGVzdGAgc3VmZml4IChlLmcuIGB0X3Rlc3RgLCBgY2hpc3FfdGVzdGAsIGBzaGFwaXJvX3Rlc3RgKS4gVGhlIG5hbWluZyBvZiB0aGVzZSBmdW5jdGlvbnMgaXMgcHJlc3VtYWJseSBjaG9zZW4gdG8gYmUgY29uc2lzZW50IHdpdGggdGhlICpiYXNlKiBSIGltcGxlbWVudGF0aW9ucyB3aGljaCBhcmUgY2FsbGVkIGB0LnRlc3RgIGBjaGlzcS50ZXN0YCBldGMuIEhvd2V2ZXIsIHRoZSBgLnRlc3RgIGZ1bmN0aW9ucyBhcmUgb2xkZXIgYW5kIGRvIG5vdCB3b3JrIHdlbGwgd2l0aCB0aWR5IGRhdGEuIE1ha2Ugc3VyZSB5b3UgYXJlIHVzaW5nIHRoZSBjb3JyZWN0IGZ1bmN0aW9uLgo8L2Rpdj4KCldlIGdldCBhIGh1Z2VseSBzaWduaWZpY2FudCByZXN1bHQhIEhvd2V2ZXIsIGlmIHdlIGxvb2sgYXQgdGhlIGRlc2NyaXB0aW9uIGZvciBgdF90ZXN0YCBpdCBpcyB0ZXN0aW5nIGFnYWluc3QgYSBwb3B1bGF0aW9uIG1lYW4gb2YgJDAkLiBJdCBpcyBubyBzdXJwcmlzZSB0aGF0IHdlIGdldCBhIHNpZ25pZmljYW50IHJlc3VsdCEgQnkgY2hhbmdpbmcgdGhlIGBtdWAgYXJndW1lbnQgd2UgY2FuIHBlcmZvcm0gYSB0ZXN0IHRvIHNlZSBpZiB0aGUgcGVvcGxlIGluIHRoZSBzdHVkeSBhcmUgb3ZlcndlaWdodCB0byBiZWdpbiB3aXRoICh1c2luZyAyNSBhcyB0aGUgcG9wdWxhdGlvbiBvciBrbm93biBtZWFuKS4KCmBgYHtyfQpkaWV0ICU+JSAKICB0X3Rlc3QoQk1JIH4xLG11ID0gMjUsYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpCiMjIDI1IGlzIHRoZSBjdXRvZmYgZm9yIG92ZXJ3ZWlnaHQKYGBgCgoKIyMgIFR3by1zYW1wbGUgdGVzdHMKCkEgdHdvLXNhbXBsZSB0LXRlc3Qgc2hvdWxkIGJlIHVzZWQgaWYgeW91IHdhbnQgdG8gY29tcGFyZSB0aGUgbWVhc3VyZW1lbnRzIG9mIHR3byBwb3B1bGF0aW9ucy4gVGhlcmUgYXJlIHR3byB0eXBlcyBvZiB0d28tc2FtcGxlIHQtdGVzdDogaW5kZXBlbmRlbnQgKHVucGFpcmVkKSBhbmQgcGFpcmVkIChkZXBlbmRlbnQpLiBUbyBtYWtlIHRoZSBjb3JyZWN0IGNob2ljZSwgeW91IG5lZWQgdG8gdW5kZXJzdGFuZCB5b3VyIHVuZGVybHlpbmcgZGF0YS4gCgotIEFuIGluZGVwZW5kZW50IHR3by1zYW1wbGUgdC10ZXN0IGlzIHVzZWQgd2hlbiB0aGUgdHdvIHNhbXBsZXMgYXJlIGluZGVwZW5kZW50IG9mIGVhY2ggb3RoZXIsIGUuZy4gKmNvbXBhcmluZyB0aGUgbWVhbiByZXNwb25zZSBvZiB0d28gZ3JvdXBzIG9mIHBhdGllbnRzIG9uIHRyZWF0bWVudCB2cy4gY29udHJvbCBpbiBhIGNsaW5pY2FsIHRyaWFsKi4gCgotIEFzIHRoZSBuYW1lIHN1Z2dlc3RzLGEgcGFpcmVkIHR3by1zYW1wbGUgdC10ZXN0IGlzIHVzZWQgd2hlbiB0aGUgdHdvIHNhbXBsZXMgYXJlIHBhaXJlZCwgZS5nLiAqY29tcGFyaW5nIHRoZSBtZWFuIGJsb29kIHByZXNzdXJlIG9mIHBhdGllbnRzIGJlZm9yZSBhbmQgYWZ0ZXIgdHJlYXRtZW50KiAodHdvIG1lYXN1cmVtZW50cyBwZXIgcGF0aWVudCkuCgpCYWNrIHRvIG91ciBkYXRhc2V0LCB3ZSBtaWdodCB3b25kZXIgaWYgdGhlcmUgaXMgYWN0dWFsbHkgYW55IGVmZmVjdCBkdWUgdG8gZGlldCBzbyB3ZSB3aWxsIGNvbXBhcmUgdGhlIGludGlhbCBhbmQgZmluYWwgd2VpZ2h0cy4KCiMjIFJlLWZvcm1hdGluZyB0aGUgZGF0YXNldCBmb3IgdGlkeSBhbmFseXNpcwoKVGhlIGRhdGFzZXQgaW4gaXQncyBjdXJyZW50IGZvcm0gaXMgbm90IHN1aXRhYmxlIGZvciBhbmFseXNpcyB3aXRoIHRpZHkgbWV0aG9kcy4gQmVmb3JlIHByb2NlZWRpbmcgd2UgbmVlZCB0byByZS1mb3JtYXQgdGhlIGRhdGEgaW50byB0d28gY29sdW1ucy4gCgotIE9uZSBjb2x1bW4gY29udGFpbmluZyBudW1lcmljIHZhcmlhYmxlcyAoZWFjaCB2YWx1ZSBvZiB3ZWlnaHQpCi0gQW4gaW5kaWNhdG9yIChvciBjYXRlZ29yaWNhbCkgdmFyaWFibGUgdG8gZGVub3RlIHRoZSBncm91cCBlYWNoIG51bWVyaWMgb2JzZXJ2YXRpb24gYmVsb25ncyB0byAoaW5pdGlhbCBvciBmaW5hbCB3ZWlnaHQpCgpUaGUgYHBpdm90X2xvbmdlcmAgZnVuY3Rpb24gc3VwcG9ydHMgdGhpcyB0cmFuc2Zvcm1hdGlvbi4gQXMgd2Ugd2FudCB0byB1c2UgYWxsIGNvbHVtbnMgaW4gb3VyIGV4aXN0aW5nIGRhdGFzZXQgd2UgaGF2ZSB0byB1c2UgdGhlIGBldmVyeXRoaW5nKClgIHNob3J0Y3V0IHRvIHNlbGVjdCB0aGUgY29sdW1ucy4gCgpgYGB7cn0KZGlldF9sb25nIDwtIGRpZXQgJT4lIAogIHNlbGVjdChjb250YWlucygid2VpZ2h0IikpICU+JSAKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSxuYW1lc190byA9ICJ0aW1lX3BvaW50IiwgdmFsdWVzX3RvID0gIndlaWdodCIpIAoKZGlldF9sb25nCmBgYAoKU28gbm93IGB3ZWlnaHRgIGNvbnRhaW5zIGFsbCBvdXIgb2JzZXJ2YXRpb25zIG9mIHdlaWdodCBhbmQgYHRpbWVfcG9pbnRgIGluZGljYXRlcyB3aGVuIHRoZSB3ZWlnaHRzIHdlcmUgbWVhc3VyZWQuIFRoZSBgZ2doaXN0b2dyYW1gIGZ1bmN0aW9uIHdlIGludHJvZHVjZWQgZWFybGllciBpcyBhYmxlIHRvIHZpc3VhbGlzZSBkYXRhIGluIHRoaXMgZm9ybSwgYW5kIHdlIGNhbiB1c2UgdGhlIGBmYWNldC5ieWAgYXJndW1lbnQgdG8gcHJvZHVjZSBzZXBhcmF0ZSBwbG90cyBmb3IgZWFjaCB0eXBlIG9mIHdlaWdodCBtZWFzdXJlbWVudC4KCmBgYHtyfQpkaWV0X2xvbmcgJT4lIAogIGdnaGlzdG9ncmFtKHggPSAid2VpZ2h0IiwgZmFjZXQuYnkgPSAidGltZV9wb2ludCIsYWRkX2RlbnNpdHkgPSBUUlVFLCB5ID0gIi4uZGVuc2l0eS4uIikgKyBzdGF0X292ZXJsYXlfbm9ybWFsX2RlbnNpdHkoY29sPSJyZWQiKQpgYGAKCldlIGNhbiBydW4gdGhlIHNoYXBpcm8gdGVzdCBvbiB0aGUgdHdvIHZhcmlhYmxlczotIAoKYGBge3J9CmRpZXRfbG9uZyAlPiUKICBncm91cF9ieSh0aW1lX3BvaW50KSAlPiUgCiAgc2hhcGlyb190ZXN0KHdlaWdodCkKYGBgClRoZSBgdF90ZXN0YCBmdW5jdGlvbiByZXF1aXJlcyB1cyB0byBjcmVhdGUgYSAqZm9ybXVsYSogYXMgYmVmb3JlLiBUaGlzIHRpbWUgd2UgYXJlIGRvaW5nIGEgdHdvLXNpZGVkIHRlc3QsIHNvIHRoZSBmb3JtdWxhIGlzIGBZIH4gWGAgd2hlcmUgJ1knIGlzIHRoZSBudW1lcmljIHZhcmlhYmxlIGFuZCAnWCcgaXMgdGhlIGNhdGVnb3JpY2FsL2dyb3VwcyB2YXJpYWJsZS4KCmBgYHtyfQpkaWV0X2xvbmcgJT4lCiAgdF90ZXN0KHdlaWdodCB+IHRpbWVfcG9pbnQpCmBgYAoKVGhlIHAtdmFsdWUgaXMgc2lnbmlmaWNhbnQgYW5kIHNob3dzIHRoYXQgb3ZlcmFsbCB0aGUgd2VpZ2h0cyBvZiBpbmRpdmlkdWFscyBpcyAqZGlmZmVyZW50KiBiZWZvcmUgYW5kIGFmdGVyIGRpZXQuIEhvd2V2ZXIsIHRoaXMgdGVzdCBpcyBub3Qgc3BlY2lmaWNhbGx5IHRlc3RpbmcgZm9yIGEgKmRlY3JlYXNlKiBhZnRlciB0aGUgZGlldCAod2hpY2ggd2Ugd291bGQgcmVhbGx5IGhvcGUgdG8gYmUgdGhlIGNhc2UpLiBCeSBhZGRpbmcgYW4gZXh0cmEgYXJndW1lbnQgYGFsdGVybmF0aXZlPWxlc3NgIHdlIGdldCBhIGRpZmZlcmVudCByZXN1bHQKCmBgYHtyfQpkaWV0X2xvbmcgJT4lCiAgdF90ZXN0KHdlaWdodCB+IHRpbWVfcG9pbnQsIGFsdGVybmF0aXZlID0gImxlc3MiKQpgYGAKVGhlcmUgaXMgYWxzbyBleHRyYSBpbmZvcm1hdGlvbiB0aGF0IHdlIGNvdWxkIGVtcGxveTsgbmFtZWx5IHRoYXQgdGhlIG1lYXN1cmVtZW50cyBvZiB3ZWlnaHQgYXJlIG1hZGUgKipvbiB0aGUgc2FtZSBwZXJzb24qKiBiZWZvcmUgYW5kIGFmdGVyIGRpZXRpbmcuIFRoaXMgaXMgYSBjbGFzc2ljIGV4YW1wbGUgb2Ygd2hlbiB0byBhcHBseSBhIHBhaXJlZCB0LXRlc3QuIEFnYWluLCB3ZSBkbyBub3QgbmVlZCB0byB1c2UgYSBkaWZmZXJlbnQgZnVuY3Rpb24gdG8gcGVyZm9ybSB0aGUgdGVzdDsgb25seSBhZGQgYW4gYXJndW1lbnQgYHBhaXJlZD1UUlVFYCB0byBgdF90ZXN0YC4KCmBgYHtyfQpkaWV0X2xvbmcgJT4lCiAgdF90ZXN0KHdlaWdodCB+IHRpbWVfcG9pbnQsIGFsdGVybmF0aXZlID0gImxlc3MiLHBhaXJlZD1UUlVFKQpgYGAKCkFuIGludHVpdGl2ZSB3YXkgb2YgY29tcGFyaW5nIHRoZSBkaXN0cmlidXRpb25zIGFuZCBzaG93aW5nIHRoZSB0ZXN0IHJlc3VsdCBvbiB0aGUgcGxvdCBpcyB1c2luZyBhIGJveHBsb3QuIEZvciB0aGlzIHdlIHdpbGwgcmV2ZXJ0IHRvIGBnZ3Bsb3QyYCwgYnV0IHdlIGFyZSB0byBpbmNsdWRlIGEgcC12YWx1ZSB1c2luZyB0aGUgYHN0YXRfY29tcGFyZV9tZWFuc2AgZnVuY3Rpb24gKGZyb20gYGdncHVicmAuCgoKYGBge3J9CmRpZXRfbG9uZyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gdGltZV9wb2ludCwgeSA9IHdlaWdodCkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX2ppdHRlcih3aWR0aD0wLjEpICsgCiAgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLHBhaXJlZD1UUlVFLCBtZXRob2QuYXJncyA9IGxpc3QoYWx0ZXJuYXRpdmUgPSAibGVzcyIpKQoKP3N0YXRfY29tcGFyZV9tZWFucwpgYGAKCgoKCkEgY29udmVuaWVudCBwbG90IGluIGBnZ3B1YnJgIHdpbGwgYWxsb3cgdXMgdG8gdmlzdWFsaXNlIHRoZSBwYWlyZWQgZGlmZmVyZW5jZXMKCmBgYHtyfQpnZ3BhaXJlZChkaWV0LCBjb25kMT0iaW5pdGlhbC53ZWlnaHQiLCBjb25kMj0iZmluYWwud2VpZ2h0IixsaW5lLmNvbG9yID0gImdyZXkiKSArIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQ9VFJVRSxtZXRob2QgPSAidC50ZXN0IikKYGBgCgoKIyMgVGhlIEluZGVwZW5kZW50IHQgdGVzdCwgd2l0aCB0d28gaW5kZXBlbmRlbnQgZ3JvdXBzIAoKTGV0cyBjb25zaWRlciB0aGF0IHdlIHdhbnQgdG8gY29tcGFyZSB3aGV0aGVyIG1hbGVzIG9yIGZlbWFsZXMgbG9zdCBtb3JlIHdlaWdodCBkdXJpbmcgdGhlIHRyaWFsLiBTbywgbGV0J3MgY3JlYXRlIGEgKm5ldyB2YXJpYWJsZSBjYWxsZWQgd2VpZ2h0IGxvc3MqCgpgYGB7cn0KZGlldCA8LSBkaWV0ICU+JSAKbXV0YXRlKHd0Lmxvc3MgPSBpbml0aWFsLndlaWdodCAtIGZpbmFsLndlaWdodCkKCmBgYAoKCkhlcmUgd2UgaGF2ZSB0d28gZ3JvdXBzIChtYWxlcyBhbmQgZmVtYWxlcyksIGFuZCB0aGVzZSBjYW4gYmUgdHJlYXRlZCBhcyAqaW5kZXBlbmRlbnQqIHZhcmlhYmxlcyBhcyBlYWNoIGdyb3VwIGhhcyBkaWZmZXJlbnQgcGFydGljaXBhbnRzIHRoYW4gdGhlIG90aGVyIGdyb3VwLiAKClRoZSAqbnVsbCBoeXBvdGhlc2lzKiBmb3Igc3VjaCBhIHRlc3Qgd291bGQgYmUgdGhhdCB0aGUgd2VpZ2h0IGxvc3MgaXMgdGhlIHNhbWUgYmV0d2VlbiBncm91cHMgbWFsZSBhbmQgZmVtYWxlLiBXZSBzZWVrIHRvIGV2aWRlbmNlIHRvIHJlamVjdCB0aGlzIGh5cG90aGVzaXMgYnkgY2FsY3VsYXRpbmcgYSB0ZXN0IHN0YXRpc3RpYy4gCgpSZW1lbWJlciwgdGhlIHQtdGVzdCBhc3N1bWVzIG5vcm1hbCBkaXN0cmlidXRpb24gYW5kIGVxdWFsIHZhcmlhbmNlCgpGaXJzdGx5LCB3ZSBoYXZlIHRvIGNoZWNrIGZvciBub3JtYWxpdHk6LQoKYGBge3J9CmRpZXQgJT4lIApnZ2RlbnNpdHkoInd0Lmxvc3MiLGNvbG9yID0gImdlbmRlciIpICsgc3RhdF9vdmVybGF5X25vcm1hbF9kZW5zaXR5KCkKCmRpZXQgJT4lICAKICBncm91cF9ieShnZW5kZXIpICU+JSAKICBzaGFwaXJvX3Rlc3Qod3QubG9zcykKYGBgClRoZW4gd2UgY2hlY2sgZm9yIGVxdWFsIHZhcmlhbmNlcyB1c2luZyB0aGUgTGV2ZW5lIHRlc3QKCgpgYGB7cn0KCmRpZXQgJT4lCiAgbGV2ZW5lX3Rlc3Qod3QubG9zc34gZ2VuZGVyKQoKI2lmIHAgdmFsdWUgaXMgc2lnbmlmaWNhbnQgLS0+IGRpZmZlcmVuY2UgaW4gdmFyaWFuY2UgKHVuZXF1YWwgdmFyaWFuY2UpIC0tPiAgdXNlIFdlbGNoIHQtdGVzdCAoUiBkZWZhdWx0KSAKI2lmIHAgdmFsdWUgaXMgbm90IHNpZ25pZmljYW50IC0tPiBubyBkaWZmZXJlbmNlIGluIHZhcmlhbmNlIChlcXVhbCB2YXJpYW5jZSkgLS0+IHVzZSB0LXRlc3QgKGFkZCBhcmd1bWVudCB2YXIuZXF1YWwgPVRSVUUpCgpgYGAKCldlIGNvbmNsdWRlIHRoYXQgdGhlIHZhcmlhbmNlcyBhcmUgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBhbmQgYm90aCB2YXJpYWJsZXMgYXJlIG5vcm1hbGx5LWRpc3RyaWJ1dGVkCgpXZSBjYW4gdXNlIHRoZSBgdF90ZXN0YCBmdW5jdGlvbiB0byBwZXJmb3JtIGFuICppbmRlcGVuZGVudCogdGVzdC4gQXMgYmVmb3JlLCB0aGUgYGZvcm11bGFgIGFyZ3VtZW50IHRvIGB0X3Rlc3RgIGlzIHRoZSAqUiBmb3JtdWxhKiBub3RhdGlvbiBmb3IgdGhlIHRlc3QgYmVpbmcgcGVyZm9ybWVkLiBIb3dldmVyLCB0aGlzIHRpbWUgd2UgKmRvIG5vdCBuZWVkIHRoZSBgcGl2b3RfbG9uZ2VyYCBmdW5jdGlvbiogYXMgd2UgYWxyZWFkeSB0aGUgYGdlbmRlcmAgYW5kIGB3ZWlnaHQubG9zc2AgdmFyaWFibGVzIGluIG91ciBkYXRhIGZyYW1lCgpUaGUgYHRfdGVzdGAgZnVuY3Rpb24gYWxsb3dzIHZhcmlvdXMgdHlwZSBvZiB0ZXN0IHRvIGJlIHBlcmZvcm1lZCBieSBjaGFuZ2luZyB0aGUgYXBwcm9wcmlhdGUgYXJndW1lbnRzIChzZWUgdGhlIGhlbHAgZm9yIGB0X3Rlc3RgIGZvciBkZXRhaWxzIChgP3RfdGVzdGApKS4gRm9yIGluc3RhbmNlLCB3ZSBjYW4gdGVsbCB0aGUgdGVzdCB0aGF0IHdlIGJlbGlldmUgb3VyIHZhcmlhbmNlcyBhcmUgZXF1YWwgb3Igbm90LgoKCmBgYHtyfQpkaWV0ICU+JSAKICB0X3Rlc3Qod3QubG9zcyB+IGdlbmRlcix2YXIuZXF1YWwgPSBUUlVFKSAKCmBgYApXZSBjYW4gc2VlIHRoYXQgdGhlIHQtc3RhdGlzdGljIHdlIG9ic2VydmUgaXMgY29uc2lzdGVudCB3aXRoIHRoZSBudWxsIGh5cG90aGVzaXMsIHRoYXQgdGhlIHdlaWdodCBsb3NzIGluIG1hbGVzIGFuZCBmZW1hbGVzIGlzIHRoZSBzYW1lLiBUaGF0IGlzLCB0aGUgcHJvYmFiaWxpdHkgb2Ygb2JzZXJ2aW5nIGEgdC1zdGF0aXN0aWMgb2YgMC4yIG9yIG1vcmUsIG9yIC0wLjIgb3IgbGVzcywgaXMgcXVpdGUgaGlnaC4KCipUaGlzIGlzIG5vdCBhIHNpZ25pZmljYW50IHJlc3VsdCAocD4wLjA1KSwgc28gdGhlcmUgaXMgbm8gZXZpZGVuY2Ugb2YgYSBkaWZmZXJlbmNlIGluIHdlaWdodCBsb3NzIGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXMqCgpgYGB7cn0KZGlldCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZ2VuZGVyLCB5PXd0Lmxvc3MpKSArIGdlb21fYm94cGxvdCgpICsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZD0idC50ZXN0IikKYGBgCgojIyBOb24tIFBhcmFtZXRyaWMgYWx0ZXJuYXRpdmVzIChlLmcuIHRoZSBXaWxjb3hvbiB0ZXN0KQoKQmVpbmcgYWJsZSB0byB1c2UgdGhlIGB0X3Rlc3RgIHJlbGllcyBvbiB0aGUgeW91ciBkYXRhIGJlaW5nIG5vcm1hbGx5LWRpc3RyaWJ1dGVkLiBJZiB3ZSBkbyBub3Qgc3VmZmljaWVudCBjb25maWRlbmNlIGluIHRoaXMgYXNzdW1wdGlvbiwgdGhlcmUgYXJlIGRpZmZlcmVudCBzdGF0aXN0aWNhbCB0ZXN0cyB0aGF0IGNhbiBiZSBhcHBsaWVkLiBSYXRoZXIgdGhhbiBjYWxjdWxhdGluZyBhbmQgY29tcGFyaW5nIHRoZSAqbWVhbnMqIGFuZCAqdmFyaWFuY2VzKiBvZiBkaWZmZXJlbnQgZ3JvdXBzIHRoZXkgYXJlICpyYW5rLWJhc2VkKiBtZXRob2RzLiBIb3dldmVyLCB0aGV5IHN0aWxsIGNvbWUgd2l0aCBhIHNldCBvZiBhc3N1bXB0aW9ucyBhbmQgaW52b2x2ZSB0aGUgZ2VuZXJhdGlvbiBvZiB0ZXN0IHN0YXRpc3RpY3MgYW5kIHAtdmFsdWVzLgoKIyMjIEluZGVwZW5kZW50IHNhbXBsZXMgPSBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0IChNYW5uIFdoaXRuZXkgVSB0ZXN0KQoKVGhpcyB0ZXN0IGhhcyBtYW55IGRpZmZlcmVudCBuYW1lcyBpbmNsdWRpbmcgdGhlIFdpbGNveG9uLCBXaWxjb3hvbiB0d28gc2FtcGxlIHRlc3QsIFdpbGNveG9uLU1hbm4tV2hpdG5leSwgV2lsY294b24gcmFuayBzdW0gYW5kIHRoZSBNYW5uLVdoaXRuZXktVSB0ZXN0LiBIb3dldmVyLCB0aGlzIHRlc3Qgc2hvdWxkIG5vdCBiZSBjb25mdXNlZCB3aXRoIHRoZSBXaWxjb3hvbiBzaWduZWQgcmFuayB0ZXN0ICh3aGljaCBpcyB1c2VkIGZvciBwYWlyZWQgdGVzdHMpLiBUbyBhdm9pZCBjb25mdXNpb24gdGhpcyB0ZXN0IGlzIHVzdWFsbHkgcmVmZXJyZWQgdG8gYXMgdGhlIE1hbm4tV2hpdG5leSBVIHRlc3QsIHdoaWNoIGlzIHVzZWQgd2hlbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIHRvIGJlIGV4YW1pbmVkIGlzIGNvbnRpbnVvdXMgYnV0IHRoZSBhc3N1bXB0aW9ucyBmb3IgcGFyYW1ldHJpYyB0ZXN0cyBhcmUgdmlvbGF0ZWQuCgpGb3J0dW5hdGVseSwgdGhlIGByc3RhdGl4YCBkZXZlbG9wZXJzIGhhdmUgbWFkZSB0aGUgZnVuY3Rpb24gdG8gZG8gYSBXaWxjb3gtdGVzdCBzaW1pbGFyIHRvIGRvaW5nIGEgdF90ZXN0LiAqKlRoZSBkaWZmaWN1bHR5IGlzIGluIGNob29zaW5nIHRoZSBjb3JyZWN0IHRlc3QgdG8gYXBwbHkgLSB3aGljaCBSIHdpbGwgbm90IGFkdmlzZSB5b3Ugb24qKi4KCkxldCdzIGdvIGJhY2sgdG8gb3VyIGV4YW1wbGUgb2YgY29tcGFyaW5nIHdlaWdodCBsb3NzIGJldHdlZW4gZ3JvdXBzIG1hbGUgYW5kIGZlbWFsZS4gVGhlIGVxdWl2YWxlbnQgbm9uLXBhcmFtZXRyaWMgdmVyc2lvbiBvZiB0aGUgdGVzdCB3ZSBwZXJmb3JtZWQgYmVmb3JlIGlzOi0KCmBgYHtyfQpkaWV0ICU+JSAKICB3aWxjb3hfdGVzdCh3dC5sb3NzIH4gZ2VuZGVyKQpgYGAKClRoZSBgd2lsY294X3Rlc3RgIGlzIGZsZXhpYmxlIGluIG11Y2ggdGhlIHNhbWUgd2F5IHRoYXQgYHRfdGVzdGAgaXMuIFdlIGNhbiBzd2l0Y2ggdG8gYXBwbHlpbmcgYSBwYWlyZWQgdGVzdCBieSBhZGRpbmcgdGhlIGFyZ3VtZW50IGBwYWlyZWQ9VFJVRWAuCgpgYGB7cn0KZGlldF9sb25nICU+JSAKICB3aWxjb3hfdGVzdCh3ZWlnaHQgfiB0aW1lX3BvaW50LCBwYWlyZWQ9VFJVRSkKYGBgCgoKIyMgQ29tcGFyZSBiZXR3ZWVuICptb3JlIHRoYW4gdHdvKiBncm91cHMKCiMjIyMgUGFyYW1ldHJpYyAoQU5PVkEpCgpUaGUgdHdvLXNhbXBsZSB0LXRlc3QgaXMgdXNlZnVsIHdoZW4gd2UgaGF2ZSBqdXN0IHR3byBncm91cHMgb2YgY29udGludW91cyBkYXRhIHRvIGNvbXBhcmUuIFdoZW4gd2Ugd2FudCB0byBjb21wYXJlIG1vcmUgdGhhbiB0d28gZ3JvdXBzLCBhIG9uZS13YXkgQU5PVkEgY2FuIGJlIHVzZWQgdG8gc2ltdWx0YW5lb3VzbHkgY29tcGFyZSBhbGwgZ3JvdXBzLCByYXRoZXIgdGhhbiBjYXJyeWluZyBvdXQgc2V2ZXJhbCBpbmRpdmlkdWFsIHR3by1zYW1wbGUgdC10ZXN0cy4gIFRoZSBtYWluIGFkdmFudGFnZSBvZiBkb2luZyB0aGlzIGlzIHRoYXQgaXQgcmVkdWNlcyB0aGUgbnVtYmVyIG9mIHRlc3RzIGJlaW5nIGNhcnJpZWQgb3V0LCBtZWFuaW5nIHRoYXQgdGhlIHR5cGUgSSBlcnJvciByYXRlICh0aGUgcHJvYmFiaWxpdHkgb2Ygc2VlaW5nIGEgc2lnbmlmaWNhbnQgcmVzdWx0IGp1c3QgYnkgY2hhbmNlKSBkb2VzIG5vdCBiZWNvbWUgaW5mbGF0ZWQuIAoKSW4gb3JkZXIgdG8ganVzdGlmeSBpZiBhbiBBTk9WQSB0ZXN0IGlzIGFwcHJvcHJpYXRlIHdlIGhhdmUgdG8gdGVzdCBmb3Igbm9ybWFsaXR5LgoKYGBge3J9CiNieSBoaXN0b2dyYW0KZGlldCAlPiUgICAKZ2doaXN0b2dyYW0oeCA9ICJ3dC5sb3NzIiwgZmFjZXQuYnkgPSAiZGlldC50eXBlIiwgYWRkX2RlbnNpdHkgPSBUUlVFLCB5ID0gIi4uZGVuc2l0eS4uIikgKyBzdGF0X292ZXJsYXlfbm9ybWFsX2RlbnNpdHkoY29sPSJyZWQiKQoKI2J5IFEtUSBwbG90CmRpZXQgJT4lIAogIGdncXFwbG90KHggPSAid3QubG9zcyIsIGZhY2V0LmJ5ID0gImRpZXQudHlwZSIpCgojYnkgc2hhcGlybyB0ZXN0Cmdyb3VwX2J5KGRpZXQsIGRpZXQudHlwZSkgJT4lIAogIHNoYXBpcm9fdGVzdCh3dC5sb3NzKQpgYGAKCgpBIG9uZS13YXkgQU5PVkEgY29tcGFyZXMgZ3JvdXAgbWVhbnMgYnkgcGFydGl0aW9uaW5nIHRoZSB2YXJpYXRpb24gaW4gdGhlIGRhdGEgaW50byAqYmV0d2VlbiBncm91cCB2YXJpYW5jZSogYW5kICp3aXRoaW4gZ3JvdXAgdmFyaWFuY2UqLiBMaWtlIHRoZSBvdGhlciBzdGF0aXN0aWNhbCB0ZXN0cyB3ZSBoYXZlIGVuY291bnRlcmVkLCB0aGUgZnVuY3Rpb25zIGluIFIgZG8gdGhlIGhhcmQgd29yayBvZiBjYWxjdWxhdGluZyB0aGUgc3RhdGlzdGljcy4gVGhlIGBhbm92YV90ZXN0YCBmdW5jdGlvbiBpcyBhIHRpZHkgdmVyc2lvbiBvZiB0aGUgQU5PVkEgdGVzdC4KCmBgYHtyfQpkaWV0ICU+JSAKICBhbm92YV90ZXN0KHd0Lmxvc3MgfiBkaWV0LnR5cGUpCgpgYGAKCgpXaGVuIHRoZSB0ZXN0IHByb3ZpZGVzIGEgc2lnbmlmaWNhbnQgcmVzdWx0IChsaWtlIGFib3ZlKSBpdCB0ZWxscyB1cyB0aGF0IHRoZXJlIGlzIGF0IGxlYXN0IG9uIGRpZmZlcmVuY2UgaW4gdGhlIGdyb3Vwcy4gSG93ZXZlciwgaXQgZG9lcyBub3QgdGVsbCB1cyB3aGljaCBncm91cCBpcyBkaWZmZXJlbnQuIEZvciB0aGlzLCB3ZSBjYW4gYXBwbHkgYSAicG9zdC1ob2MgdGVzdCIgc3VjaCBhcyB0aGUgVHVrZXkgdGVzdC4gSWYgYGFub3ZhX3Rlc3RgIGRpZCBub3QgcHJvZHVjZSBhIHNpZ25pZmljYW50IHAtdmFsdWUsIHdlIHdvdWxkbid0IHByb2NlZWQgd2l0aCB0aGlzIHN0ZXAKCmBgYHtyfQpkaWV0ICU+JSAgCiAgdHVrZXlfaHNkKHd0Lmxvc3MgfiBkaWV0LnR5cGUpCmBgYAoKQXMgd2UgaGF2ZSBzZWVuIHByZXZpb3VzbHksIGEgc3RhbmRhcmQgbWV0aG9kIG9mIHByZXNlbnRpbmcgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gZ3JvdXBzIGlzIHRvIHVzZSB0aGUgYHN0YXRfY29tcGFyZV9tZWFuc2AgZnVuY3Rpb24gdG8gYXV0b21hdGljYWxseSBhZGQgcC12YWx1ZXMgdG8gYSBib3hwbG90IG9yIHZpb2xpbiBwbG90CgpgYGB7cn0KZ2dwbG90KGRpZXQsIGFlcyh4ID0gZGlldC50eXBlLCB5ID0gd3QubG9zcykpICsgZ2VvbV92aW9saW4oKSArIGdlb21faml0dGVyKHdpZHRoPTAuMSkgKyBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kPSJhbm92YSIpCmBgYAoKSG93ZXZlciwgaW4gdGhlIGNhc2Ugb2YgbW9yZSB0aGFuIHR3byBncm91cHMgaXQgd2lsbCBvbmx5IHNob3cgYSBzaW5nbGUgcC12YWx1ZSBmcm9tIHRoZSBBTk9WQSByYXRoZXIgdGhhbiBpbmRpdmlkdWFsIGNvbXBhcmlzb25zLiBXZSBjYW4gZXhwbGljaXRseSBsaXN0IHBhcnRpY3VsYXIgY29udHJhc3RzIHdlIGFyZSBpbnRlcmVzdGVkIGluLgoKYGBge3J9Cm15X2NvbXBhcmlzb25zIDwtIGxpc3QoIGMoIkEiLCAiQiIpLCBjKCJBIiwgIkMiKSwgYygiQiIsICJDIikgKQpnZ3Bsb3QoZGlldCwgYWVzKHggPSBkaWV0LnR5cGUsIHkgPSB3dC5sb3NzKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2VvbV9qaXR0ZXIod2lkdGg9MC4xKSArIAogIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAidC50ZXN0Iixjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zKQpgYGAKQWx0ZXJuYXRpdmVseSwgd2UgY2FuIG1hbnVhbGx5LWNvbXB1dGUgdGhlIHAtdmFsdWVzIGFuZCBhZGQgdGhlc2UgdG8gdGhlIHBsb3QuCgpgYGB7cn0Kc3RhdF9yZXMgPC0gZGlldCAlPiUgCiAgdHVrZXlfaHNkKHd0Lmxvc3MgfiBkaWV0LnR5cGUpCgoKZ2dwbG90KGRpZXQsIGFlcyh4ID0gZGlldC50eXBlLCB5ID0gd3QubG9zcykpICsgZ2VvbV92aW9saW4oKSArIGdlb21faml0dGVyKHdpZHRoPTAuMSkrCiAgc3RhdF9wdmFsdWVfbWFudWFsKHN0YXRfcmVzLCBsYWJlbCA9ICJwLmFkaiIseS5wb3NpdGlvbiA9IGMoMTEsIDEzLCAxNSkpCmBgYAoKCgojIyMgTm9uLVBhcmFtZXRyaWMgKEtydXNrYWwgV2FsbGlzKSAKCkRhdGEgdGhhdCBkbyBub3QgbWVldCB0aGUgYXNzdW1wdGlvbnMgb2YgQU5PVkEgKGUuZy4gbm9ybWFsaXR5KSBjYW4gYmUgdGVzdGVkIHVzaW5nIGEgbm9uLXBhcmFtZXRyaWMgYWx0ZXJuYXRpdmUuIFRoZSAqS3J1c2thbC1XYWxsaXMqIHRlc3QgaXMgZGVyaXZlZCBmcm9tIHRoZSBvbmUtd2F5IEFOT1ZBLCBidXQgdXNlcyByYW5rcyByYXRoZXIgdGhhbiBhY3R1YWwgb2JzZXJ2YXRpb25zLiBJdCBpcyBhbHNvIHRoZSBleHRlbnNpb24gb2YgdGhlIE1hbm4tV2hpdG5leSBVIHRlc3QgdG8gbW9yZSB0aGFuIHR3byBncm91cHMuCgpgYGB7cn0KZGlldCAlPiUgCiAga3J1c2thbF90ZXN0KHd0Lmxvc3MgfiBkaWV0LnR5cGUpCmBgYApMaWtlIHRoZSBvbmUtd2F5IEFOT1ZBIHRoaXMgd2lsbCBvbmx5IHRlbGwgdXMgdGhhdCBhdCBsZWFzdCBvbmUgZ3JvdXAgaXMgZGlmZmVyZW50IGFuZCBub3Qgc3BlY2lmaWNhbGx5IHdoaWNoIGdyb3VwKHMpLiBUaGUgcG9zdC1ob2MgYGR1bm4udGVzdGAgaXMgcmVjb21tZW5kZWQgd2hpY2ggYWxzbyBwZXJmb3JtcyBtdWx0aXBsZSB0ZXN0aW5nIGNvcnJlY3Rpb24uCgpgYGB7cn0KZGlldCAlPiUgCiAgZHVubl90ZXN0KHd0Lmxvc3MgfiBkaWV0LnR5cGUsIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIikKYGBgCgoKQXQgdGhpcyBwb2ludCB3ZSBjb3VsZCBiZSBhYm91dCB0byByZWNvbW1lbmQgZGlldCBDIHRvIHRob3NlIHRoYXQgd2lzaCB0byBsb3NlIHdlaWdodC4gSG93ZXZlciwgYXJlIHRoZXJlIGFueSBvdGhlciBmYWN0b3JzIGluIHRoZSBkYXRhIHRoYXQgd2Ugc2hvdWxkIGJlIGNvbnNpZGVyaW5nPyBXaXRoIGBnZ3Bsb3QyYCB3ZSBjYW4gcXVpdGUgZWFzaWx5IHZpc3VhbGlzZSB0aGUgZWZmZWN0cyBvZiBtdWx0aXBsZSBmYWN0b3JzIG9uIHRoZSBkYXRhLiBMZXRzIGFkZCBib3RoIGdlbmRlciBhbmQgZGlldCB0eXBlIGludG8gdGhlIHBsb3QuIEl0IG5vdyBhcHBlYXJzIHRoYXQgZGlldCBDIGlzIGhhdmluZyBhbiBlZmZlY3Qgb24gbWFsZXMgYnV0IG5vdCBmZW1hbGVzLgoKYGBge3J9CmdncGxvdChkaWV0LCBhZXMoeCA9IGRpZXQudHlwZSwgeSA9IHd0Lmxvc3MsZmlsbD1nZW5kZXIpKSArIGdlb21fYm94cGxvdCgpCmBgYAoKIyMgVHdvLXdheSBBTk9WQQoKVGhlICpmb3JtdWxhKiBub3RhdGlvbiBhbGxvd3MgdXMgdG8gc3BlY2lmeSBhbiAqaW50ZXJhY3Rpb24qIGJldHdlZW4gZ2VuZGVyIGFuZCBkaWV0IHR5cGUuIEluIG90aGVyIHdvcmRzLCB3ZSBhcmUgbG9va2luZyB0byBzZWUgaWYgdGhlIGVmZmVjdCBvZiBkaWV0IHR5cGUgaXMgZGlmZmVyZW50IGZvciBtYWxlcyBhbmQgZmVtYWxlcy4gSW4gUiwgdGhlIGZvcm11bGEgZm9yIGFuIGludGVyYWN0aW9uIGlzIHNwZWNpZmllZCB1c2luZyBhIGAqYCBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBhc3Nlc3NpbmcgdGhlIGludGVyYWN0aW9uIGZvci4KCmBgYHtyfQpkaWV0ICU+JSAKICBhbm92YV90ZXN0KHd0Lmxvc3MgfiBkaWV0LnR5cGUqZ2VuZGVyKQpgYGAKCgpUaGlzIHRlbGxzIHVzIHRoYXQgYW4gZWZmZWN0IGV4aXN0cyBiZXR3ZWVuIGRpZXQgdHlwZSBhbmQgZ2VuZGVyLCBidXQgbGlrZSBiZWZvcmUgd2UgaGF2ZSB0byBydW4gYSBwb3N0LWhvYyB0ZXN0IHRvIGRpc2NvdmVyIG1vcmUKCmBgYHtyfQpkaWV0ICU+JSAKICB0dWtleV9oc2Qod3QubG9zcyB+IGRpZXQudHlwZSpnZW5kZXIpICU+JSAKICBmaWx0ZXIocC5hZGouc2lnbmlmICE9ICJucyIpCmBgYAoKCjxkaXYgY2xhc3M9ImV4ZXJjaXNlIj4KKipFeGVyY2lzZSoqCgpUaGUgZXhjZWwgZmlsZSDigJhSQ0My4oCZIGNvbnRhaW5zIGRhdGEgYWJvdXQgdGhlIGV4cHJlc3Npb24gbGV2ZWxzIG9mIHNvbWUgZ2VuZXMgaW4gcGF0aWVudHMgd2l0aCByZW5hbCBjZWxsIGNhcmNpbm9tYS4gSW4geW91ciBzdHVkeSwgeW91IHB1dCB0aGUgZm9sbG93aW5nIGh5cG90aGVzZXMuClBsZWFzZSB0ZXN0IHRob3NlIGFsdGVybmF0aXZlIGh5cG90aGVzZXMgYW5kIHN0YXRlIHdoZXRoZXIgeW91IHdpbGwgYWNjZXB0IG9yIHJlamVjdCBlYWNoIG9uZS4KCjEuCUZlbWFsZXMgaGF2ZSBhIGhpZ2hlciBsZXZlbCBvZiBFMkYzIHRoYW4gbWFsZXMgCjIuCUFOWEEgZXhwcmVzc2lvbiBsZXZlbHMgdmFyeSBiZXR3ZWVuIHVuaWxhdGVyYWwgYW5kIGJpbGF0ZXJhbCB0dW1vcnMKMy4JSW5kaXZpZHVhbHMgd2l0aCBSQ0MgZ3JhZGUgSUkgaGF2ZSBkaWZmZXJlbnQgbGV2ZWxzIG9mIEUyRjMgdGhhbiB0aG9zZSB3aXRoIGdyYWRlIElJSSBvciBJViAKNC4JVGhlIG1lYW4gdmFsdWUgb2YgbWlSNDk5IGRlY3JlYXNlcyBzaWduaWZpY2FudGx5IGFmdGVyIHRyZWF0bWVudAo1LglERkZBIGlzIGhpZ2hlciBpbiBwYXRpZW50cyB3aXRoIGdyYWRlIElWIHR1bW9ycwo8L2Rpdj4KCiMgU29sdXRpb25zCgoKKipUbyBiZSByZXZlYWxlZCBkdXJpbmcgdGhlIHdvcmtzaG9wISoqCgojIyBFeGVyY2lzZSAxCgpgYGB7cn0KIyMgTkVXCgp0YWIgPC0gcmVhZHhsOjpyZWFkX3hsc3goImRhdGEvRVggQmlvc3RhdCBQMS54bHN4IikgJT4lIG1ha2VfY2xlYW5fbmFtZXMoKQojIzItTWFrZSBhIGNyb3NzIHRhYmxlIHNob3dpbmcgdGhlIGdlbmRlciBpbiB0aGUgcm93cyBhbmQgdHVtb3IgZ3JhZGUgaW4gdGhlIGNvbHVtbnMKCmNvdW50KHRhYiwgR2VuZGVyLCBUdW1vci5ncmFkZSkKCgojIzMtRGVmaW5lIHRoZSBwZXJjZW50YWdlIG9mIEdyYWRlIElJSSB0dW1vcnMgd2l0aGluIGZlbWFsZXMgCmZyZXFfdGFibGUodGFiLCBHZW5kZXIsIFR1bW9yLmdyYWRlKQoKIyM0LVVzZSB0aGUgYXBwcm9wcmlhdGUgdGVzdCB0byBjaGVjayBpZiB0aGUgdHVtb3IgZ3JhZGUgZGVwZW5kcyBvbiB0aGUgZ2VuZGVyIAoKY291bnQodGFiLCBHZW5kZXIsIFR1bW9yLmdyYWRlKSAlPiUgCiAgICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEdlbmRlcix2YWx1ZXNfZnJvbSA9IG4pICU+JSAKICBzZWxlY3QoLVR1bW9yLmdyYWRlKSAlPiUgCiAgY2hpc3FfdGVzdCgpCgpgYGAKCiMjIEV4ZXJjaXNlIDIKCgpgYGB7cn0KIyMxLVJlYWQgdGhlIGV4Y2VsIGZpbGUgY2FsbGVkICdFWCBCaW9zdGF0IFAyJyBpbnRvIFIgCkJpb3N0YXQyIDwtIHJlYWR4bDo6cmVhZF94bHN4KCJkYXRhL0VYIEJpb3N0YXQgUDIueGxzeCIpCgpnZ2hpc3RvZ3JhbShCaW9zdGF0MiwgeCA9ICJBZ2UiKQoKZ2doaXN0b2dyYW0oQmlvc3RhdDIsIHggPSAiQWdlIiwgYWRkX2RlbnNpdHkgPSBUUlVFLCB5ID0gIi4uZGVuc2l0eS4uIikgKyBzdGF0X292ZXJsYXlfbm9ybWFsX2RlbnNpdHkoY29sPSJibHVlIikKCgpnZ3FxcGxvdChCaW9zdGF0MiwgeCA9ICJBZ2UiKQpCaW9zdGF0MiAlPiUgCiAgc2hhcGlyb190ZXN0KHZhcnMgPSAiQWdlIikKIyBBZ2UgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQKCmdnaGlzdG9ncmFtKEJpb3N0YXQyLCB4ID0gImhvc3BpdGFsaXphdGlvbiBkYXlzIikKCmdnaGlzdG9ncmFtKEJpb3N0YXQyLCB4ID0gImhvc3BpdGFsaXphdGlvbiBkYXlzIiwgYWRkX2RlbnNpdHkgPSBUUlVFLCB5ID0gIi4uZGVuc2l0eS4uIikgKyBzdGF0X292ZXJsYXlfbm9ybWFsX2RlbnNpdHkoY29sPSJibHVlIikKCgpnZ3FxcGxvdChCaW9zdGF0MiwgeCA9ICJob3NwaXRhbGl6YXRpb24gZGF5cyIpCkJpb3N0YXQyICU+JSAKICBzaGFwaXJvX3Rlc3QodmFycyA9ICJob3NwaXRhbGl6YXRpb24gZGF5cyIpCgojIGhvc3BpdGFsaXphdGlvbiBkYXlzIE5PVCBub3JtYWxseSBkaXN0cmlidXRlZAoKZ2V0X3N1bW1hcnlfc3RhdHMoQmlvc3RhdDIpCgpgYGAKCiMjIEV4ZXJjaXNlIDMKCiMjIyAzLjEKCmBgYHtyfQpSQ0MyIDwtIHJlYWR4bDo6cmVhZF94bHN4KCJkYXRhL1JDQzIueGxzeCIpCgpnZ2hpc3RvZ3JhbShSQ0MyLCB4ID0gIkUyRjMiLCAKICAgICAgICAgICAgeSA9ICIuLmRlbnNpdHkuLiIsCiAgICAgICAgICAgIGZhY2V0LmJ5ID0gImdlbmRlciIpICsgc3RhdF9vdmVybGF5X25vcm1hbF9kZW5zaXR5KGNvbD0iYmx1ZSIpCgpSQ0MyICU+JSAKICBncm91cF9ieShnZW5kZXIpICU+JSAKICBzaGFwaXJvX3Rlc3QoRTJGMykKI2JvdGggZ3JvdXBzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkCiNwYXJhbWV0cmljICogMiBncm91cHMgLS0+IHQtdGVzdAoKUkNDMiAlPiUgCiAgZ3JvdXBfYnkoZ2VuZGVyKSAlPiUgCiAgZ2V0X3N1bW1hcnlfc3RhdHMoIkUyRjMiLHR5cGU9ImNvbW1vbiIpCgp0X3Rlc3QoUkNDMiwgRTJGMyB+IGdlbmRlcix2YXIuZXF1YWwgPSBUUlVFKQojQU5TV0VSPVJFSkVDVAoKZ2dwbG90KFJDQzIsIGFlcyh4ID0gZ2VuZGVyLCB5ID0gRTJGMykpICsgZ2VvbV92aW9saW4oKSArIGdlb21faml0dGVyKHdpZHRoID0gMC4xKSArIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAidC50ZXN0IikKCmBgYAoKIyMjIDMuMgoKYGBge3J9CmdnaGlzdG9ncmFtKFJDQzIsIHggPSAiQU5YQSIsIGZhY2V0LmJ5ID0gIlNpZGUiKQoKUkNDMiAlPiUgCiAgZ3JvdXBfYnkoU2lkZSkgJT4lIAogIHNoYXBpcm9fdGVzdChBTlhBKQojbm90IG5vcm1hbAojbm9uLXBhcmFtZXRyaWMgKiAyIGdyb3VwcyAtLT4gV2lsY294b24gKE1hbm4gV2hpdG5leSBVKQp3aWxjb3hfdGVzdChSQ0MyLCBBTlhBIH4gU2lkZSkKI0FOU1dFUj1SRUpFQ1QKZ2dwbG90KFJDQzIsIGFlcyh4ID0gU2lkZSwgeSA9IEFOWEEpKSArIGdlb21fdmlvbGluKCkgKyBnZW9tX2ppdHRlcigpICsgc3RhdF9jb21wYXJlX21lYW5zKCkKCmBgYAoKCgojIyMgMy4zCgoKYGBge3J9CmdnaGlzdG9ncmFtKFJDQzIsIHggPSAiRTJGMyIsIGZhY2V0LmJ5ID0gIkdyYWRlIiwgeSA9ICIuLmRlbnNpdHkuLiIpICsgc3RhdF9vdmVybGF5X25vcm1hbF9kZW5zaXR5KCkgCgojMyBncm91cHMgbm9ybWFsCiNwYXJhbWV0cmljICogPiAyIGdyb3VwcyAtLT4gQU5PVkEKCmFub3ZhX3Rlc3QoUkNDMiwgRTJGMyB+IEdyYWRlKQojdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGJ1dCBiZXR3ZWVuIHdoaWNoIGdyb3Vwcz8gLS0+IHBvc3QgSG9jCnR1a2V5X2hzZChSQ0MyLCBFMkYzIH4gR3JhZGUpCiNBTlNXRVI9IEFDQ0VQVApteV9jb21wYXJpc29ucyA8LSBsaXN0KCBjKCJJSSIsICJJSUkiKSwgYygiSUkiLCAiSVYiKSwgYygiSUlJIiwgIklWIikgKQoKZ2dwbG90KFJDQzIsIGFlcyh4ID0gR3JhZGUsIHkgPSBFMkYzKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2VvbV9qaXR0ZXIod2lkdGg9MC4xKSArIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2Q9InQudGVzdCIsY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucykKCgpgYGAKCgoKIyMjIDMuNAoKCmBgYHtyfQptaXI0OTlfZGF0YSA8LSAKICBSQ0MyICU+JQogIHNlbGVjdChjb250YWlucygibWlyNDk5IikpICU+JSAKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSkKZ2doaXN0b2dyYW0obWlyNDk5X2RhdGEsIHggPSAidmFsdWUiLCBmYWNldC5ieSA9ICJuYW1lIikKCm1pcjQ5OV9kYXRhICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgc2hhcGlyb190ZXN0KHZhbHVlKQojbm90IG5vcm1hbAojbm9uLXBhcmFtZXRyaWMgKiAyIHBhaXJlZCBncm91cHMgLS0+IFdpbGNveG9uIHNpZ25lZCByYW5rIHRlc3QKCm1pcjQ5OV9kYXRhICU+JSAKICB3aWxjb3hfdGVzdCh2YWx1ZSB+IG5hbWUsIHBhaXJlZCA9IFRSVUUsYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpCm1pcjQ5OV9kYXRhICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgZ2V0X3N1bW1hcnlfc3RhdHModmFsdWUpCiNpdCBpbmNyZWFzZXMgYWZ0ZXIgdHR0CiNBTlNXRVIgPSBSRUpFQ1QgICAKYGBgCiMjIyAzLjUKCmBgYHtyfQpnZ2hpc3RvZ3JhbShSQ0MyLCB4ID0gIkRGRkEiLCBmYWNldC5ieSA9ICJHcmFkZSIpCiNub3Qgbm9ybWFsCiNub24tcGFyYW1ldHJpYyAqID4gMiBncm91cHMgLS0+IGtydXNrYWwgV2FsbGlzClJDQzIgJT4lIAogIGtydXNrYWxfdGVzdChERkZBIH4gR3JhZGUpCiNBTlNXRVI9IFJFSkVDVAojTm8gbmVlZCB0byBwZXJmb3JtIHBvc3QtaG9jIHRlc3QKYGBgCgoKCg==