Statistical Model for Predicting Newborn Weight
Company Context Company: Neonatal Health Solutions
Objective: Create a statistical model capable of accurately
predicting newborn birth weight, based on clinical variables collected
from three hospitals.
The project aims to improve the management of high-risk pregnancies,
optimizing hospital resources and ensuring better outcomes for neonatal
health.
The variables collected include:
Maternal Age: Measure of age in years.
Number of Pregnancies: How many pregnancies the mother has
previously had.
Maternal smoking: A binary indicator (0 = non-smoker, 1 =
smoker).
Pregnancy duration: Number of weeks of gestation.
Infant weight: Birth weight in grams.
Length and Head circumference: Infant length and head diameter,
which can also be measured during pregnancy via ultrasound.
Type of delivery: Natural or cesarean.
Hospital of birth: Hospital 1, 2, or 3.
Infant sex: Male (M) or female (F).
kable(summary(dataset), caption="Summary of the variables in the dataset") %>%
kable_styling()
Summary of the variables in the dataset
| |
Anni.madre |
N.gravidanze |
Fumatrici |
Gestazione |
Peso |
Lunghezza |
Cranio |
Tipo.parto |
Ospedale |
Sesso |
| |
Min. : 0.00 |
Min. : 0.0000 |
0:2396 |
Min. :25.00 |
Min. : 830 |
Min. :310.0 |
Min. :235 |
Length:2500 |
Length:2500 |
Length:2500 |
| |
1st Qu.:25.00 |
1st Qu.: 0.0000 |
1: 104 |
1st Qu.:38.00 |
1st Qu.:2990 |
1st Qu.:480.0 |
1st Qu.:330 |
Class :character |
Class :character |
Class :character |
| |
Median :28.00 |
Median : 1.0000 |
NA |
Median :39.00 |
Median :3300 |
Median :500.0 |
Median :340 |
Mode :character |
Mode :character |
Mode :character |
| |
Mean :28.16 |
Mean : 0.9812 |
NA |
Mean :38.98 |
Mean :3284 |
Mean :494.7 |
Mean :340 |
NA |
NA |
NA |
| |
3rd Qu.:32.00 |
3rd Qu.: 1.0000 |
NA |
3rd Qu.:40.00 |
3rd Qu.:3620 |
3rd Qu.:510.0 |
3rd Qu.:350 |
NA |
NA |
NA |
| |
Max. :46.00 |
Max. :12.0000 |
NA |
Max. :43.00 |
Max. :4930 |
Max. :565.0 |
Max. :390 |
NA |
NA |
NA |
We note that the variable Age of the mother has a minimum value equal
to 0 meaning that there are some wrong data. So we first display the
distribution of the age of the mothers.
ggplot(data = subset(dataset))+
geom_bar(aes(x=Anni.madre),
stat="count",
col="khaki",
fill="khaki")+
labs(title="Distribution of the mother age",
x="Age",
y="absolute frequency")+
scale_y_continuous(breaks = seq(0,1200,200))+
scale_x_continuous(breaks = seq(0,46,2))+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)))

We can assume that the minimum meaningfull age of a mother is 12
years. So we filter the dataset to remove the dirty data corresponding
to mothers with an age smaller than 12.
dataset <- dataset %>%
filter(Anni.madre >=12)
Next, we start analyzing the anthropometrics data (Weigth, Length
and Cranial Circumference) of the newborns in the dataset.
First we report a table with the summary of the statistics of the
anthropometrics variables
Indices of weight, length and cranial diameter
| |
quartile_1 |
median |
quartile_3 |
mean |
sd |
cv |
skewness |
kurtosis |
std_err |
| Cranial circumference (mm) |
330 |
340 |
350 |
340.03 |
16.43 |
4.83 |
-0.79 |
2.94 |
0.33 |
| Weight (gr) |
2990 |
3300 |
3620 |
3284.18 |
525.23 |
15.99 |
-0.65 |
2.03 |
10.51 |
| Length (mm) |
480 |
500 |
510 |
494.70 |
26.33 |
5.32 |
-1.51 |
6.48 |
0.53 |
Second we display the distribution of the anthropometric variables
again a normal distribution
# the function normalize takes in input a variable in string form and returns its values normalized by its mean and standard deviation
normalize <- function(x){
return ((x-mean(x))/sd(x))
}
# we generate a standard normal distribution
gaussian_distribution <- rnorm(1000000,0,1)
# we plot the density of the different variables against a standard normal distribution
ggplot()+
geom_density(aes(x=gaussian_distribution, fill="N01"), color=NA, alpha=.8)+
geom_density(aes(x=normalize(Peso), color="Weight"), linewidth=1.5)+
geom_density(aes(x=normalize(Cranio), color="Cranial circumference"), linewidth=1.5)+
geom_density(aes(x=normalize(Lunghezza), color="Length"), linewidth=1.5)+
labs(title="Distribution of the variables",
x="Normalized variable ",
y="density")+
scale_fill_manual(values = c(N01 = "grey"),
labels = c(N01 = "N(0,1)")) +
theme_classic()+
theme(plot.title.position = "panel",
plot.title=element_text(hjust=0.5))+
guides(fill = guide_legend(override.aes = list(color = NA)))+
labs(color = "Variabile",
fill = "Distribuzione normale")

The plots as also the values of skeweness and Kurtosis show that:
All the anthropometric variables are more peaked than a normal
distribution, so the probability of outliers is smaller that for the
normal distribution with same mean and standard deviation.
Values in the left tails of the distributions are more likely
than values in the right tail. This could be due to the data relative to
premature births.
To check if the asymmetry is due to the premature births we plot the
distribution of births by gestational weeks.
ggplot(data=dataset)+
geom_bar(aes(x=Gestazione),
stat="count",
col="pink",
fill="pink")+
labs(title="Distribution of gestational age at childbirth",
x="gestational age (weeks)",
y="absolute frequency")+
scale_y_continuous(breaks = seq(0,750,50))+
scale_x_continuous(breaks = seq(25,43,1))+
theme_classic()+
theme(axis.text.x = element_text(angle = 15, hjust = 1),
axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)))

A delivery is considered premature if it occurs before 37 weeks of
gestation. By looking at the barplot we note there exist different many
premature birthds in the dataset. We expect the anthropometric
measurements of premature newborns to be significantly smaller.
So we filter the data relative only to the non-premature births and
study their statistics.
regular_deliveries_data <- dataset %>% filter(Gestazione >= 37)
statistics_regular_deliveries <- data.frame(
quartile_1 = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, function(x) quantile(x,probs=0.25, names=FALSE)),2),
median = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, median),2),
quartile_3 = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, function(x) quantile(x,probs=0.75, names=FALSE)),2),
mean = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, mean),2),
sd = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, sd),2),
cv = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, cv_funct),2),
skewness = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, skewness),2),
kurtosis = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, kurtosis_index),2),
std_err = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")],2,std.err),2)
)
rownames(statistics_regular_deliveries) <- c("Cranial circumference (mm)", "Weight (gr)", "Length (mm)")
kable(statistics_regular_deliveries, caption="Indices of weight, length and cranial diameter of the non-premature births") %>%
kable_styling()
Indices of weight, length and cranial diameter of the non-premature births
| |
quartile_1 |
median |
quartile_3 |
mean |
sd |
cv |
skewness |
kurtosis |
std_err |
| Cranial circumference (mm) |
332 |
340.5 |
350 |
341.71 |
14.21 |
4.16 |
-0.01 |
0.30 |
0.29 |
| Weight (gr) |
3050 |
3320.0 |
3640 |
3349.56 |
443.69 |
13.25 |
0.13 |
0.21 |
9.18 |
| Length (mm) |
485 |
500.0 |
510 |
498.11 |
21.16 |
4.25 |
-0.44 |
2.74 |
0.44 |
# we plot the density of the different variables against a standard normal distribution
ggplot()+
geom_density(aes(x=gaussian_distribution, fill="N01"), color=NA, alpha=.8)+
geom_density(aes(x=normalize(regular_deliveries_data$Peso), color="Weight"), linewidth=1.5)+
geom_density(aes(x=normalize(regular_deliveries_data$Cranio), color="Cranial circumference"), linewidth=1.5)+
geom_density(aes(x=normalize(regular_deliveries_data$Lunghezza), color="Length"), linewidth=1.5)+
labs(title="Distribution of the anthropometric variables \n relative to the non-premature deliveries",
x="Normalized variable ",
y="density")+
scale_fill_manual(values = c(N01 = "grey"),
labels = c(N01 = "N(0,1)")) +
theme_classic()+
theme(plot.title.position = "panel",
plot.title=element_text(hjust=0.5))+
guides(fill = guide_legend(override.aes = list(color = NA)))+
labs(color = "Variabile",
fill = "Distribuzione normale")

The significantly smaller values of skeweness of all the
anthropometric variables corresponding only to the non-premature births
confirm that the asymmetry that we had previously observed was mainly
due to the presence of premature births. Also the values of the kurtosis
have significanlty decreased suggesting a much better normal
approximation of the distribution of the anthropometric variables when
filtering the data corresponding to the only non-premature deliveries.
The length is the only variables that is not really normally
distributed. The non-normality of the variable Lenght could be due to
the presenze of some corrupted data. To this end we study the
correlation between the anthropometric variables.
cat("The correlation coefficiente of the variable Length with the varibles Weight and Cranial circumference in non premature newborns is equal to: \n",
"-cor(Length, Weight) = ", cor(regular_deliveries_data$Lunghezza, regular_deliveries_data$Peso)
, "\n",
"-cor(Length, Cranial circumference) = ", cor(regular_deliveries_data$Lunghezza, regular_deliveries_data$Cranio)
)
The correlation coefficiente of the variable Length with the varibles Weight and Cranial circumference in non premature newborns is equal to:
-cor(Length, Weight) = 0.7118152
-cor(Length, Cranial circumference) = 0.4566794
scatt1 = ggplot(regular_deliveries_data, aes(x = Lunghezza, y = Peso)) +
geom_point()+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)))+
labs(title="Scatterplot of Lenght against Weight",
x=" Lenght(mm)",
y=" Weight(gr)")+
scale_y_continuous(breaks = seq(2000,5000,500))+
scale_x_continuous(breaks = seq(300,600,50))
scatt2 = ggplot(regular_deliveries_data, aes(x = Lunghezza, y = Cranio)) +
geom_point()+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)))+
labs(title="Scatterplot of Lenght against Cranial circumference",
x=" Lenght(mm)",
y=" Cranial circumference(mm)")+
scale_x_continuous(breaks = seq(300,600,50))
comb_fig_scatt <- scatt1 + scatt2 + plot_layout(ncol=2, heights = c(5), widths= c(5,5))
print(comb_fig_scatt)

From the scatterplots, it can be seen that there is one outlier
measurement reporting a length smaller than 350 mm, which could be due
to an error in the dataset, such as a typo in the annotation of the
newborn’s length. So we decide to clean the dataset of regular newborns
from this datapoint.
regular_deliveries_data <- regular_deliveries_data %>% filter(Lunghezza >= 350)
statistics_regular_deliveries <- data.frame(
quartile_1 = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, function(x) quantile(x,probs=0.25, names=FALSE)),2),
median = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, median),2),
quartile_3 = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, function(x) quantile(x,probs=0.75, names=FALSE)),2),
mean = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, mean),2),
sd = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, sd),2),
cv = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, cv_funct),2),
skewness = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, skewness),2),
kurtosis = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")], 2, kurtosis_index),2),
std_err = round(apply(regular_deliveries_data[c("Cranio","Peso","Lunghezza")],2,std.err),2)
)
rownames(statistics_regular_deliveries) <- c("Cranial circumference (mm)", "Weight (gr)", "Length (mm)")
kable(statistics_regular_deliveries, caption="Indices of weight, length and cranial diameter of the non-premature births") %>%
kable_styling()
Indices of weight, length and cranial diameter of the non-premature births
| |
quartile_1 |
median |
quartile_3 |
mean |
sd |
cv |
skewness |
kurtosis |
std_err |
| Cranial circumference (mm) |
332 |
340 |
350 |
341.69 |
14.20 |
4.15 |
-0.01 |
0.30 |
0.29 |
| Weight (gr) |
3050 |
3320 |
3640 |
3349.12 |
443.28 |
13.24 |
0.13 |
0.21 |
9.17 |
| Length (mm) |
485 |
500 |
510 |
498.19 |
20.82 |
4.18 |
-0.18 |
0.56 |
0.43 |
We observe that now, in the cleaned dataset, also the variable Length
follows approximately a normal distribution, with both kurtosis and
skewness coefficients close to 0.
Analysis of weight, length and cranial diameter of the sample with
respect to the population statistics.
According to the study International
standards for newborn weight, length, and head circumference by
gestational age and sex, the birthweight, birthlength and birth head
circumference of babies born in Italy from the 37th week of gestation
on, have the following mean and standard deviation:
birthweight: Mean = 3.3, SD = 0.4,
birthlength: Mean = 49.4, SD = 1.7,
birth head circumference: Mean = 34.0, SD = 1.2
From the central limit theorem we know that given a random variable X
with mean \(\mu_0\) and standard
deviation \(\sigma\), the mean over a
random sample of N people distributes as a random variable following a
normal distribution with mean \(\mu_0\)
and standard deviation \(\sigma/N\).
So for the three variables weight, length and cranial circumference
we assume as null hypothesis (H0) that they have mean \(\mu_0=\) 3300 gr, 49.4 cm and 34 cm and
standard deviation \(\sigma=\) 400gr,
1.7cm, 1.2cm, respectively. Then we test this hypotheses using a Z-test.
To this end we consider the sub-dataset corresponding to the births
after the 37th week of gestation, having length \(N\).
Then we compute the Z-test value \[Z =
\frac{mean(Variable)-\mu_0}{\sigma/\sqrt{N}}.\]
We compute the corresponfing p-values, i.e. the probability of
getting a value equal or smaller than mean(Variable) by randomly
sampling N births. If the p-value is smaller than the level of
significance that we set to 0.05, we reject the hypothesis H0.
z_test = function(x, mu0, stdev, alfa){
x = na.omit(x)
mu_cap = mean(x)
n = length(x)
Z = (mu_cap - mu0) / (stdev / sqrt(n))
valori.soglia = qnorm(c(alfa/2, 1-alfa/2))
CI <- c(mu_cap+qnorm(alfa/2)*(stdev/sqrt(n)),
mu_cap-qnorm(alfa/2)*(stdev/sqrt(n)))
return(
list(mean.sample= mu_cap,
stat.test = Z,
threshold.val = valori.soglia,
pvalue = 2*pnorm(-abs(Z)),
Int.Conf. = CI
))
}
z_test_weight = z_test(regular_deliveries_data$Peso, 3300, 400, 0.05)
z_test_length = z_test(regular_deliveries_data$Lunghezza, 494, 17, 0.05)
z_test_cranial_diam = z_test(regular_deliveries_data$Cranio, 340, 12, 0.05)
cat("The p-values of length, weight and cranial circumference are all smaller than 0.05, so we reject the hypothesis H0 that the three variables are distributed according to the distribution of weight, length and cranial diameter of the italian population. \n",
"-p_value(Weight) = ", z_test_weight$pvalue , "\n",
"-p_value(Length) = ", z_test_length$pvalue , "\n",
"-p_value(Cranial diameter) = ", z_test_cranial_diam$pvalue )
The p-values of length, weight and cranial circumference are all smaller than 0.05, so we reject the hypothesis H0 that the three variables are distributed according to the distribution of weight, length and cranial diameter of the italian population.
-p_value(Weight) = 2.960815e-09
-p_value(Length) = 1.124683e-32
-p_value(Cranial diameter) = 9.627454e-12
In particular we display the Z-test values of the anthropometric
variables against the level of significance of 0.05 of the Z-test.
ggplot()+
geom_density(aes(x=gaussian_distribution, fill="N01"), color=NA, alpha=.8) +
geom_vline(aes(xintercept=z_test_weight$stat.test, color="Weight"), linewidth=1.5) +
geom_vline(aes(xintercept=z_test_length$stat.test, color="Length"), linewidth=1.5)+
geom_vline(aes(xintercept=z_test_cranial_diam$stat.test, color="Cranial circumference"), linewidth=1.5)+
geom_vline(aes(xintercept=z_test_length$threshold.val, color="Threshold p=0.05"),linewidth=1, linetype="dashed")+
scale_color_manual(values= c("Weight"= "gold1", "Length"="gold4", "Cranial circumference"="gold3", "Threshold p=0.05"="red"))+
scale_fill_manual(values = c(N01 = "grey"),
labels = c(N01 = "N(0,1)")) +
labs(title="Z values of weight, length and cranial circumference",
x=" ",
y=" ")+
theme_classic()+
theme(axis.text.x = element_text(angle = 15, hjust = 1),
axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)),
legend.position ="bottom")

Analysis of the differences in the antrhopometric variables across
the different between males and females.
First we display the distribution of newborns between the two sexes,
which result quite uniform.
sex_colors <- c("M" = "dodgerblue", "F" = "hotpink")
ggplot(data=dataset)+
geom_bar(aes(x=Sesso,
fill=Sesso,
color=Sesso),
stat="count")+
labs(title="Sex distribution of newborns",
x="sex",
y="absolute frequency",
color="SEX:",
fill="SEX:")+
scale_fill_manual(values= sex_colors)+
scale_y_continuous(breaks = seq(0,1500,100))+
theme_classic()+
theme(axis.text.x = element_text(angle = 15, hjust = 1),
axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)))

Second we study the statistics of the anthropometric variables across
the two sexes and display them via a boxplot. In order to test later
differences across the sexes using a t.test it is important to compare
normally distrubuted quantities. For this reason, we restrict our study
only to the not-premature deliveries.
cv_funct <- function(x) {
return(sd(x) / mean(x) * 100)
}
conditional_dataset_sex <- regular_deliveries_data %>%
group_by(Sesso) %>%
summarise(mean_peso = round(mean(Peso),2),
sd_peso = round(sd(Peso),2),
cv_peso = round(cv_funct(Peso), 2),
skew_peso = round(skewness(Peso), 2),
kurt_peso = round(kurtosis_index(Peso), 2),
mean_lunghezza = round(mean(Lunghezza),2),
sd_lunghezza = round(sd(Lunghezza),2),
cv_lunghezza = round(cv_funct(Lunghezza), 2),
skew_lunghezza = round(skewness(Lunghezza), 2),
kurt_lunghezza = round(kurtosis_index(Lunghezza), 2),
mean_cranio = round(mean(Cranio),2),
sd_cranio = round(sd(Cranio),2),
cv_cranio = round(cv_funct(Cranio), 2),
skew_cranio = round(skewness(Cranio), 2),
kurt_cranio = round(kurtosis_index(Cranio), 2))
colnames(conditional_dataset_sex) <- c("sex", "mean", "sd", "cv", "Skew", "kurt" , "mean", "sd", "cv" , "Skew", "kurt", "mean", "sd", "cv", "Skew", "kurt")
kable(conditional_dataset_sex, caption="Indices of weight, length and cranial diameter of non-premature newborns, divided by sex") %>%
kable_styling(bootstrap_options = "condensed", full_width = TRUE) %>%
add_header_above(c(" "=1, "Weight" = 5, "Length" = 5, "Cranial circumference" = 5)) %>%
row_spec(1, background = "pink")%>%
row_spec(2, background = "lightblue") %>%
column_spec(c(1,6,11), border_right = TRUE)
Indices of weight, length and cranial diameter of non-premature newborns, divided by sex
|
Weight |
Length |
Cranial circumference |
| sex |
mean |
sd |
cv |
Skew |
kurt |
mean |
sd |
cv |
Skew |
kurt |
mean |
sd |
cv |
Skew |
kurt |
| F |
3237.00 |
433.6 |
13.4 |
0.35 |
0.63 |
493.95 |
21.12 |
4.28 |
-0.17 |
0.74 |
339.56 |
14.08 |
4.15 |
0.06 |
0.33 |
| M |
3458.11 |
425.2 |
12.3 |
-0.04 |
0.26 |
502.31 |
19.67 |
3.92 |
-0.13 |
0.34 |
343.77 |
14.00 |
4.07 |
-0.07 |
0.38 |
box_length_sex <- ggplot(data=regular_deliveries_data,
aes(x=Sesso,
y=Lunghezza,
fill=Sesso),
color=Sesso)+
geom_boxplot()+
labs(title="Length ditribution according to sex\n of non premature newborns",
x=" ",
y="length (cm)")+
scale_fill_manual(values= sex_colors)+
theme_classic()+
theme(plot.title.position = "panel",
plot.title = element_text(size=16, hjust=0.5),
axis.title.x = element_text(size=14),
axis.title.y = element_text(size=14),
axis.text.x = element_text(size=14),
axis.text.y = element_text(size=10),
legend.position = "none")+
scale_y_continuous(breaks = seq(310, 560, by = 25))+
scale_x_discrete(labels=c("M"="Male", "F"="Female"))
box_weight_sex <- ggplot(data=regular_deliveries_data,
aes(x=Sesso,
y=Peso,
fill=Sesso),
color=Sesso)+
geom_boxplot()+
labs(title="Weight ditribution according to sex\n of non premature newborns",
x=" ",
y="weight (Kg)")+
scale_fill_manual(values= sex_colors)+
theme_classic()+
theme(plot.title.position = "panel",
plot.title = element_text(size=16, hjust=0.5),
axis.title.x = element_text(size=14),
axis.title.y = element_text(size=14),
axis.text.x = element_text(size=14),
axis.text.y = element_text(size=10),
legend.position = "none")+
scale_y_continuous(breaks = seq(1000, 5000, by = 400),
labels = seq(1.0, 5.0, by = 0.4))+
scale_x_discrete(labels=c("M"="Male", "F"="Female"))
box_head_sex <- ggplot(data=regular_deliveries_data,
aes(x=Sesso,
y=Cranio,
fill=Sesso),
color=Sesso)+
geom_boxplot()+
labs(title="Cranial diameter ditribution according to sex\n of non premature newborns",
x=" ",
y="diameter (cm)")+
scale_fill_manual(values= c("M"="dodgerblue", "F"="hotpink"))+
theme_classic()+
theme(plot.title.position = "panel",
plot.title = element_text(size=16, hjust=0.5),
axis.title.x = element_text(size=14),
axis.title.y = element_text(size=14),
axis.text.x = element_text(size=14),
axis.text.y = element_text(size=10),
legend.position = "none")+
scale_y_continuous(breaks = seq(250, 400, by = 25))+
scale_x_discrete(labels=c("M"="Male", "F"="Female"))
comb_fig_antropometrics <- box_head_sex + box_weight_sex + box_length_sex + plot_layout(ncol=3, heights = c(5), widths= c(5,5,5))
print(comb_fig_antropometrics)

The data suggest a difference in the anthropometric variables across
the two sexes, with higher values for all the variables in case of males
rather than females.
We test the hypothesis that the antropometric values of males and
females are significantly different
In order to perform a meaningfull t-test that compares the
distributions of anthropometric measurements of males and females we
first have to check that the distributions of the antrhopometric
measurements of males and females are approximatelly normal and have
similar variances. The previous table suggest that this should be true
if we restrict our study only to the non-premature deliveries. We
perform Q-Q tests and Shapiro Wilk tests to verify that the three
variables distribute according to normal distributions for both sexes.
We recall the Q-Q plots display the observed quantiles of the variables
against the quantiles of a Gaussian distribution. So, if the variables
come from a normal distribution, the points in the Q-Q plot will
approximately lie along a straight line.
males <- regular_deliveries_data %>%
filter(Sesso=="M")
females <- regular_deliveries_data %>%
filter(Sesso=="F" & Lunghezza>400)
## QQ-plots of the length
QQ_length_males = ggplot(males, aes(sample = Lunghezza)) +
labs(title="Q-Q Plot of the length\n of male newborns",
x="Theoretical Quantiles",
y="Observed Quantiles")+
stat_qq(color = "dodgerblue") +
stat_qq_line(color="red") +
theme_classic()
QQ_length_females = ggplot(females, aes(sample = Lunghezza)) +
labs(title="Q-Q Plot of the length\n of female newborns",
x="Theoretical Quantiles",
y="Observed Quantiles")+
stat_qq(color = "hotpink") +
stat_qq_line(color="black") +
theme_classic()
## QQ_plots of the weight
QQ_weight_males = ggplot(males, aes(sample = Peso)) +
labs(title="Q-Q Plot of the weight\n of male newborns",
x="Theoretical Quantiles",
y="Observed Quantiles")+
stat_qq(color = "dodgerblue") +
stat_qq_line(color="red") +
theme_classic()
QQ_weight_females = ggplot(females, aes(sample = Peso)) +
labs(title="Q-Q Plot of the weight\n of female newborns",
x="Theoretical Quantiles",
y="Observed Quantiles")+
stat_qq(color = "hotpink") +
stat_qq_line(color="black") +
theme_classic()
QQ_cranial_males = ggplot(males, aes(sample = Cranio)) +
labs(title="Q-Q Plot of the cranial circumference\n of male newborns",
x="Theoretical Quantiles",
y="Observed Quantiles")+
stat_qq(color = "dodgerblue") +
stat_qq_line(color="red") +
theme_classic()
QQ_cranial_females = ggplot(females, aes(sample = Cranio)) +
labs(title="Q-Q Plot of the cranial circumference\n of female newborns",
x="Theoretical Quantiles",
y="Observed Quantiles")+
stat_qq(color = "hotpink") +
stat_qq_line(color="black") +
theme_classic()
comb_QQ <- QQ_length_males + QQ_length_females +
QQ_weight_males + QQ_weight_females +
QQ_cranial_males + QQ_cranial_females +
plot_layout(ncol=2, heights = c(5,5,5), widths= c(5,5))
print(comb_QQ)

shaptestLM = shapiro.test(males$Lunghezza)
shaptestLF = shapiro.test(females$Lunghezza)
shaptestWM = shapiro.test(males$Peso)
shaptestWF = shapiro.test(females$Peso)
shaptestCM = shapiro.test(males$Cranio)
shaptestCF = shapiro.test(females$Cranio)
cat("The maximum Shapiro-Wilk statistics of the 6 normality tests about distribution of weight, length and cranial circumference across the two sexes is:", min(shaptestLM$statistic, shaptestLF$statistic, shaptestWM$statistic, shaptestWF$statistic, shaptestCM$statistic, shaptestCF$statistic), "\n")
The maximum Shapiro-Wilk statistics of the 6 normality tests about distribution of weight, length and cranial circumference across the two sexes is: 0.9875359
cat("The minimum Shapiro-Wilk p.value of the 6 normality tests about distribution of weight, length and cranial circumference across the two sexes is:", min(shaptestLM$p.value, shaptestLF$p.value, shaptestWM$p.value, shaptestWF$p.value, shaptestCM$p.value, shaptestCF$p.value))
The minimum Shapiro-Wilk p.value of the 6 normality tests about distribution of weight, length and cranial circumference across the two sexes is: 2.185776e-08
From the Q-Q plots and the Shapiro-Wilk tests we can argue that the
anthropometric variables, even if not exactly distributed according to
normal distributions, are really close to normal distributions. So we
can perform a t.test to verify the null hypothesis that the distribution
followed by males and females is the same.
ttest_length = t.test(males$Lunghezza, females$Lunghezza,
alternative = "two.sided",
mu = 0,
var.equal = TRUE,
conf.level = 0.95,
paired = FALSE)
ttest_weight = t.test(males$Peso, females$Peso,
alternative = "two.sided",
mu = 0,
var.equal = TRUE,
conf.level = 0.95,
paired = FALSE)
ttest_cranium = t.test(males$Cranio, females$Cranio,
alternative = "two.sided",
mu = 0,
var.equal = TRUE,
conf.level = 0.95,
paired = FALSE)
cat("The p-values of the t-tests about length, weight and cranial circumference distribution comparison between males and females are: \n",
"-p_value(Weight) = ", ttest_weight$p.value , "\n",
"-p_value(Length) = ", ttest_length$p.value , "\n",
"-p_value(Cranial diameter) = ", ttest_cranium$p.value )
The p-values of the t-tests about length, weight and cranial circumference distribution comparison between males and females are:
-p_value(Weight) = 3.149166e-34
-p_value(Length) = 1.88921e-22
-p_value(Cranial diameter) = 8.994501e-13
The very small p-values of the three t.tests show that there is a
significant statistical difference in the mean of the anthropometric
variables between males and females. In particular we can refuse the
null hypothesis H0 and assert that the distributions of the
anthropometric measurements followed by males and females are
different.
Analysis of cesarean deliveries
Now we analyze the number of cesarean deliveries across the different
hospitals. First we study the the absolute and relative frequency of
each hospital.
#create a conditional dataset with the number of deliveries and cesarean deliveries per hospital
conditional_dataset_ospedale <-
dataset %>%
group_by(Ospedale) %>%
summarise(cesareo = sum(Tipo.parto == "Ces", na.rm = TRUE),
naturale = sum(Tipo.parto == "Nat", na.rm = TRUE),
parti= sum())
Freq_ass_hosp = table(dataset["Ospedale"])
Freq_rel_hosp = table(dataset["Ospedale"])/N_observations
Freq_hosp = cbind(Freq_ass_hosp,Freq_rel_hosp)
rownames(Freq_hosp) <- c("Hospital1","Hospital2","Hospital3")
colnames(Freq_hosp) <- c("Absolute frequency","Relative frequency")
kable(t(Freq_hosp), caption = 'Deliveries distribution across hospitals') %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
Deliveries distribution across hospitals
| |
Hospital1 |
Hospital2 |
Hospital3 |
| Absolute frequency |
816.0000 |
848.0000 |
834.0000 |
| Relative frequency |
0.3264 |
0.3392 |
0.3336 |
We have observed that the distribution of the deliveries across the
three hospitals is essentially uniform.
Next we use a boxplot to display the percentage of cesarean
deliveries in each hospital.
hospitals=c("osp1" = "Hospital1", "osp2"="Hospital2", "osp3"="Hospital3")
dataset$Tipo.parto <- factor(dataset$Tipo.parto, levels = c("Nat", "Ces"))
bar_cesarean_hospital = ggplot(data=dataset)+
geom_bar(aes(x=Ospedale,
fill=Tipo.parto),
position="fill")+
labs(title="Percentage of cesarean childbirths by hospitals",
x="",
y="Percentage",
fill="type of delivery:")+
scale_fill_manual(values= c("Ces"="red", "Nat"="ivory2"), labels = c("Ces"= "Cesarean", "Nat"="Natural"))+
theme_classic()+
theme(plot.title.position = "panel",
plot.title = element_text(size=14, hjust=0.5),
axis.title.x = element_text(size=12),
axis.title.y = element_text(size=12),
axis.text.x = element_text(size=10),
axis.text.y = element_text(size=10),
legend.position = "bottom",
legend.title = element_text(size = 12),
legend.text = element_text(size = 12))+
scale_y_continuous(labels = percent_format(),
breaks = seq(0, 1, by = 0.1))+
scale_x_discrete(labels=hospitals)
print(bar_cesarean_hospital)

The boxplot show that in all the three hospitals the percentage of
cesarean deliveries is approximately of 30%. In particular, the number
of cesarean deliveries seems to be marginally lower in the Hospital3
with respect to Hospital1 and Hospital2.
Next we test the null hypothesis that the distribution of cesarean
deliveries is the same and so uniform across the three hospitals
We first use a Pearson’s Chi-squared test to examine the hypothesis
that the proportion of cesarean deliveries is equal across the
hospitals. It compares the observed frequencies of cesarean and natural
deliveries in each hospital with the expected frequencies calculated
under the null hypothesis of uniform distribution of cesarean deliveries
across hospitals, literally: \[Expected\_Freq\_Ces(Hosp) = Prob(Cesarean)*
Number\_Deliveries(Hosp) \] where \(Prob(Cesarean)=N\_tot(Cesarean)/N\_tot(deliveries)\).
The test assesses whether the observed differences are statistically
significant by providing a chi-squared statistic and a p-value to
support or reject the null hypothesis.
# create contingency table bewtween hospitals and kind of delivery
table_delivery_hospital = table(Ospedale, Tipo.parto)
#The Pearson’s Chi-squared test is performed
chisq_test = chisq.test(table_delivery_hospital)
cat("The p-value of the Pearson's Chi-squared test is" , chisq_test$p.value)
The p-value of the Pearson's Chi-squared test is 0.5777576
Based on the p-value of the Pearson’s Chi-squared we can not reject
the null-hypothesis.
The test Chi-squared that we have performed is based on the
assumption that for sufficiently many observations the distribution of
the frequencies of cesarean deliveries at each hospital is close to a
normal distribution, because of the central limit theorem. However, in
this case, we know that the number of cesarean deliveries at the \(i\)-th hospital follows a binomial
distribution \(B(p_i)\). So we can also
perform a binomial test for each hospital to examine the hypothesis that
\(p_i=Prob(Cesarean)\) for each
hospital. \(Prob(Cesarean)\) as defined
above is assumed as an accurate approximation of probability of cesarean
delivery if the distribution is uniform across the hospitals, in
particular since the distribution of deliveries per hospital is quite
uniform there is no need to use a weighted formula for the probability
\(Prob(Cesarean)\). We report the the
\(p\)-value and the confidence interval
of this test for each hospital.
# first we create a table with the total number of deliveries and cesarean deliveries observed at each hospital.
sub_dataset = subset(dataset, Ospedale=="osp1")
N_ces_hosp = sum(sub_dataset$Tipo.parto=="Ces")
N_deliveries_hosp = nrow(sub_dataset)
Freq_ces_hosp = table(Ospedale[Tipo.parto=="Ces"])
Ces_hosp = cbind(Freq_ass_hosp,Freq_ces_hosp)
Ces_hosp = as.data.frame(Ces_hosp)
rownames(Ces_hosp) <- c("Hospital_1", "Hospital_2", "Hospital_3")
# Next we compute Prob(cesarean) that should be a good approximation of the probability of oberving a cesarean delivery assuming this is uniform across the three hospitals.
prob_cesarean = sum(Tipo.parto=="Ces")/N_observations
# Last we perform a binomial test for each hospital
p_values <- numeric(nrow(Ces_hosp))
conf_int <- numeric(nrow(Ces_hosp))
for(i in seq_len(nrow(Ces_hosp))){
test <- binom.test(Ces_hosp$Freq_ces_hosp[i], Ces_hosp$Freq_ass_hosp[i], p = prob_cesarean, alternative = "two.sided")
p_values[i] <- test$p.value
conf_int[i] <- paste0("(", round(test$conf.int[1],2), ",", round(test$conf.int[2],2),")")
}
Ces_hosp$p_value <- p_values
Ces_hosp$conf_int <- conf_int
kable(t(Ces_hosp[, c("p_value", "conf_int")]), caption = 'P-values and confidence intervals for the binomial outcomes of each hospital,1n calculated under the assumption of a binomial distribution with a uniform probability\n of cesarean deliveries across all hospitals.') %>%
kable_styling(bootstrap_options = c("striped", "hover"), position="left")
P-values and confidence intervals for the binomial outcomes of each hospital,1n calculated under the assumption of a binomial distribution with a uniform probability
of cesarean deliveries across all hospitals.
| |
Hospital_1 |
Hospital_2 |
Hospital_3 |
| p_value |
0.7289190 |
0.5967907 |
0.4236389 |
| conf_int |
(0.27,0.33) |
(0.27,0.33) |
(0.25,0.31) |
Also in this case the p-value of the binomial tests do not allow to
reject the null hypothesis asserting that the number of deliveries
across the three hospitals is uniform.
Next we analyze the frequency of smoking mothers.
Freq_rel_smoker = sum(dataset$Fumatrici == 1)/N_observations
cat("The percentage of smoking mothers is:", paste0(Freq_rel_smoker,"%"))
The percentage of smoking mothers is: 0.0416%
Moreover we investigate if the smoke influence some of the other
variables, including weight, length and Cranial circumference and
gestational age.
boxplot_smoking_1= ggplot(data=dataset,
aes(x=Fumatrici,
y=Peso,
fill=Fumatrici))+
geom_boxplot()+
labs(title="Weight distribution",
x=" ",
y="weight (kg)")+
scale_fill_manual(values= c("0"="green", "1"="grey"),
labels = c("0"= "Non-smoker", "1"="Smoker"))+
theme_classic()+
theme(plot.title.position = "panel",
plot.title = element_text(size=16, hjust=0.5),
axis.title.x = element_text(size=14),
axis.title.y = element_text(size=14),
axis.text.x = element_text(size=14),
axis.text.y = element_text(size=10),
legend.position = "none")+
scale_y_continuous(labels = seq(1,5,0.5),
breaks = seq(1000, 5000, by = 500))+
scale_x_discrete(labels=c("Non-smoker", "Smoker"))
boxplot_smoking_2 = ggplot(data=dataset,
aes(x=Fumatrici,
y=Lunghezza,
fill=Fumatrici))+
geom_boxplot()+
labs(title="Length distribution",
x=" ",
y="Length (cm)")+
scale_fill_manual(values= c("0"="green", "1"="grey"),
labels = c("0"= "Non-smoker", "1"="Smoker"))+
theme_classic()+
theme(plot.title.position = "panel",
plot.title = element_text(size=16, hjust=0.5),
axis.title.x = element_text(size=14),
axis.title.y = element_text(size=14),
axis.text.x = element_text(size=14),
axis.text.y = element_text(size=10),
legend.position = "none")+
scale_y_continuous(breaks = seq(300,600,50),
labels = seq(30, 60, 5))+
scale_x_discrete(labels=c("Non-smoker", "Smoker"))
boxplot_smoking_3 = ggplot(data=dataset,
aes(x=Fumatrici,
y=Cranio,
fill=Fumatrici))+
geom_boxplot()+
labs(title="Cranial circumference distribution",
x=" ",
y="Cranial circumference (cm)")+
scale_fill_manual(values= c("0"="green", "1"="grey"),
labels = c("0"= "Non-smoker", "1"="Smoker"))+
theme_classic()+
theme(plot.title.position = "panel",
plot.title = element_text(size=16, hjust=0.5),
axis.title.x = element_text(size=14),
axis.title.y = element_text(size=14),
axis.text.x = element_text(size=14),
axis.text.y = element_text(size=10),
legend.position = "none")+
scale_y_continuous(labels = seq(25,40,5),
breaks = seq(250, 400, by = 50))+
scale_x_discrete(labels=c("Non-smoker", "Smoker"))
boxplot_smoking_4 = ggplot(data=dataset,
aes(x=Fumatrici,
y=Gestazione,
fill=Fumatrici))+
geom_boxplot()+
labs(title="Gestational time distribution",
x=" ",
y="Gestational time")+
scale_fill_manual(values= c("0"="green", "1"="grey"),
labels = c("0"= "Non-smoker", "1"="Smoker"))+
theme_classic()+
theme(plot.title.position = "panel",
plot.title = element_text(size=16, hjust=0.5),
axis.title.x = element_text(size=14),
axis.title.y = element_text(size=14),
axis.text.x = element_text(size=14),
axis.text.y = element_text(size=10),
legend.position = "none")+
scale_y_continuous(breaks = seq(26, 42, by = 2))+
scale_x_discrete(labels=c("Non-smoker", "Smoker"))
comb_smoke <- boxplot_smoking_1 + boxplot_smoking_2 + boxplot_smoking_3 + boxplot_smoking_4 + plot_layout(ncol=2, heights = c(5,5), widths= c(5,5))
print(comb_smoke)

The boxplot may suggest a difference in the measurements and
gestational time between smoking and non smoking mothers. We test this
hypothesis using a t.test.
Smokers_data <- dataset %>%
filter(Fumatrici=="1")
Not_smokers_data <- dataset %>%
filter(Fumatrici=="0")
ttest_smoke_weight = t.test(Smokers_data$Peso, Not_smokers_data$Peso,
alternative = "two.sided",
mu = 0,
var.equal = TRUE,
conf.level = 0.95,
paired = FALSE)
ttest_smoke_length = t.test(Smokers_data$Lunghezza, Not_smokers_data$Lunghezza,
alternative = "two.sided",
mu = 0,
var.equal = TRUE,
conf.level = 0.95,
paired = FALSE)
ttest_smoke_cranium = t.test(Smokers_data$Cranio, Not_smokers_data$Cranio,
alternative = "two.sided",
mu = 0,
var.equal = TRUE,
conf.level = 0.95,
paired = FALSE)
ttest_smoke_gestation = t.test(Smokers_data$Gestazione, Not_smokers_data$Gestazione,
alternative = "two.sided",
mu = 0,
var.equal = TRUE,
conf.level = 0.95,
paired = FALSE)
cat("The p-values of the t-tests about length, weight, cranial circumference and gestation time distribution comparison between smoking and non-smoking mothers are: \n",
"-p_value(Weight) = ", ttest_smoke_weight$p.value , "\n",
"-p_value(Length) = ", ttest_smoke_length$p.value , "\n",
"-p_value(Cranial diameter) = ", ttest_smoke_cranium$p.value, "\n",
"-p_value(Cranial diameter) = ", ttest_smoke_gestation$p.value)
The p-values of the t-tests about length, weight, cranial circumference and gestation time distribution comparison between smoking and non-smoking mothers are:
-p_value(Weight) = 0.3428237
-p_value(Length) = 0.2984492
-p_value(Cranial diameter) = 0.6650278
-p_value(Cranial diameter) = 0.1064455
The t.tests do not allow us to reject the hypothesis that the
gestational time and antropometric measurments of newborns are
statistically different according to smoking and not-smoking
mothers.
Next we analyze the number of deliveries and relation with the age
of the mothers.
First we explore the variable number of deliveries.
Freq_abs_N.deliveries = table(dataset["N.gravidanze"])
Freq_rel_N.deliveries = table(dataset["N.gravidanze"])/N_observations
Freq_N.deliveries=data.frame(N.gravidanze = names(Freq_abs_N.deliveries),
Freq_abs = as.numeric(Freq_abs_N.deliveries),
Freq_rel = paste(round(Freq_rel_N.deliveries,2),"%"))
Freq_N.deliveries$N.gravidanze <- factor(Freq_N.deliveries$N.gravidanze,
levels=as.character(sort(as.numeric(unique(Freq_N.deliveries$N.gravidanze)))))
ggplot(data=Freq_N.deliveries)+
geom_bar(aes(x=N.gravidanze, y=Freq_abs),
stat="identity",
col="aquamarine",
fill="aquamarine")+
labs(title="Number of previous pregnancies",
x="",
y="absolute frequency")+
scale_y_continuous(breaks = seq(0,1200,200))+
geom_text(aes(x=N.gravidanze, y=Freq_abs+50, label = Freq_rel))+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)))

We observe that most of deliveries correspond to first deliveries and
that less than 10% of the mothers have 4 children or more.
Next we investigate if there is a correlation between the number of
children and the age of the mother. To this end we split the dataset in
classes according to the Number of deliveries and years of the mother
and we display the dstribution according to the cross classes.
dataset$N.gravidanze_CL <- cut(dataset$N.gravidanze,
breaks=c(0,1,2,3,100),
right=FALSE,
labels=c("0", "1","2","3+"))
dataset$Anni.madre_CL <- cut(dataset$Anni.madre,
breaks=c(11,20,26,32,38,46))
dataset$N.gravidanze_CL <- cut(dataset$N.gravidanze,
breaks=c(0,1,2,3,100),
right=FALSE,
labels=c("0","1","2","3+"))
cont_table_year_N.delivery = table(dataset$Anni.madre_CL, dataset$N.gravidanze_CL)
ggpubr::ggballoonplot(data=as.data.frame(cont_table_year_N.delivery),
fill="khaki")

As expected we observe that an increasing number of children usually
correspond to older mothers. We test the hypothesis the the distribution
of number of childer is not uniform across the ages via a Pearson
chi-squared test.
chisq_test = chisq.test(cont_table_year_N.delivery)
cat("The p-value of the Pearson's Chi-squared test is" , chisq_test$p.value)
The p-value of the Pearson's Chi-squared test is 1.116617e-91
The Pearson’s Chi squared test confirms the hypothesis that the
distribution of number of deliveries per age is not uniform.
Creation of a regression model for the weight of the newborn.
We start studying the correlations between the different variables
and the variable weight. First we display the correlations between the
different quantitative variable and the variable weight.
# panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
# {
# #usr <- par("usr"); on.exit(par(usr))
# #par(usr = c(0, 1, 0, 1))
# r <- (cor(x, y))
# txt <- format(c(r, 1), digits = digits)[1]
# txt <- paste0(prefix, txt)
# if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
# text(0.5, 0.5, txt, cex = 1.5)
# }
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
r <- cor(x, y, use = "complete.obs")
txt <- format(c(r, 1), digits = digits)[1]
txt <- paste0(prefix, txt)
usr <- par("usr") # leggi coordinate correnti
x_pos <- mean(usr[1:2]) # centro asse x
y_pos <- mean(usr[3:4]) # centro asse y
if(missing(cex.cor)) cex.cor <- 10/strwidth(txt)
text(x_pos, y_pos, txt, cex = 1.5, ...)
}
#correlazioni
pairs(dataset[, c("Anni.madre","N.gravidanze", "Gestazione", "Peso", "Lunghezza", "Cranio")], lower.panel=panel.cor, upper.panel=panel.smooth)

The correlation matrix suggest a medium to high correlation between
Weight and Length/Cranium circumference and gestation time. Differently,
the weight seems not to be correlated to the number of deliveries and
age of the mother. Additionally we have already observed that there is
not a significant correlation between the weight of the newborn and the
fact that the mother is a smoker. Differently we have observed a strong
correlation between the sex of the newborn and its weight.
The scatter plots also suggest a possible nonlinear dependance of the
weight of the newborns with respect to gestation time and possibly
Length and cranium circumference.
Even if this is not observable from the correlation matrix, the
literature suggest that there could be a difference in the weight of the
newborns between the first child and the subsequent ones (see International
standards for newborn weight, length, and head circumference by
gestational age and sex), for this reason we split the dataset
according to the Number of delivery classes “0” and “1+” and use this as
a qualitative variable in the investigation of a good regression model
fo the weight of the newborns.
dataset$N.gravidanze_CL <- cut(dataset$N.gravidanze,
breaks=c(0,1,100),
right=FALSE,
labels=c("0","1+"))
We investiagte the best linear regression model using a stepwise
selection procedure. We start from the full model from which we omit the
variables Hospital and Kind of delivery since there is no reason why
these variables should influence the weight of the newborn. Then we
subtract or add back the variables that seems less influential. Finally
we select the best model based on the BIC metrics.
mod_tot<-lm(Peso ~ Anni.madre + N.gravidanze_CL + Fumatrici + Gestazione + Lunghezza + Cranio + Sesso, data=dataset)
summary(mod_tot)
Call:
lm(formula = Peso ~ Anni.madre + N.gravidanze_CL + Fumatrici +
Gestazione + Lunghezza + Cranio + Sesso, data = dataset)
Residuals:
Min 1Q Median 3Q Max
-1163.53 -183.34 -14.47 164.63 2615.88
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -6721.5968 141.3193 -47.563 < 2e-16 ***
Anni.madre 1.2298 1.1238 1.094 0.2739
N.gravidanze_CL1+ 23.2268 11.8572 1.959 0.0502 .
Fumatrici1 -30.5500 27.6434 -1.105 0.2692
Gestazione 33.1338 3.8410 8.626 < 2e-16 ***
Lunghezza 10.2148 0.3011 33.930 < 2e-16 ***
Cranio 10.5152 0.4282 24.556 < 2e-16 ***
SessoM 78.5750 11.2142 7.007 3.13e-12 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 274.8 on 2490 degrees of freedom
Multiple R-squared: 0.727, Adjusted R-squared: 0.7262
F-statistic: 947.2 on 7 and 2490 DF, p-value: < 2.2e-16
The variables “age”, “N.deliveries” and “smoking” seeem to be the
less significant. So we start removing the variable “age” from the
model.
mod1<-lm(Peso ~ N.gravidanze_CL + Fumatrici + Gestazione + Lunghezza + Cranio + Sesso, data=dataset)
summary(mod1)
Call:
lm(formula = Peso ~ N.gravidanze_CL + Fumatrici + Gestazione +
Lunghezza + Cranio + Sesso, data = dataset)
Residuals:
Min 1Q Median 3Q Max
-1148.91 -183.57 -14.79 163.87 2620.69
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -6679.3566 135.9513 -49.131 < 2e-16 ***
N.gravidanze_CL1+ 27.2419 11.2757 2.416 0.0158 *
Fumatrici1 -30.8461 27.6432 -1.116 0.2646
Gestazione 32.7241 3.8229 8.560 < 2e-16 ***
Lunghezza 10.2109 0.3010 33.918 < 2e-16 ***
Cranio 10.5387 0.4277 24.640 < 2e-16 ***
SessoM 78.7767 11.2132 7.025 2.74e-12 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 274.8 on 2491 degrees of freedom
Multiple R-squared: 0.7269, Adjusted R-squared: 0.7262
F-statistic: 1105 on 6 and 2491 DF, p-value: < 2.2e-16
cat(“After removing the variable "age" the variables "N.deliveries"
and "smoking" are still not significant.” ) cat(“So we remove the
variable "smoking" from the model.” )
mod2<-lm(Peso ~ N.gravidanze_CL + Gestazione + Lunghezza + Cranio + Sesso, data=dataset)
summary(mod2)
Call:
lm(formula = Peso ~ N.gravidanze_CL + Gestazione + Lunghezza +
Cranio + Sesso, data = dataset)
Residuals:
Min 1Q Median 3Q Max
-1147.94 -184.03 -14.54 164.49 2624.44
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -6678.5707 135.9561 -49.123 < 2e-16 ***
N.gravidanze_CL1+ 26.4198 11.2522 2.348 0.019 *
Gestazione 32.4468 3.8150 8.505 < 2e-16 ***
Lunghezza 10.2257 0.3008 33.999 < 2e-16 ***
Cranio 10.5444 0.4277 24.654 < 2e-16 ***
SessoM 78.5900 11.2125 7.009 3.07e-12 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 274.8 on 2492 degrees of freedom
Multiple R-squared: 0.7267, Adjusted R-squared: 0.7262
F-statistic: 1325 on 5 and 2492 DF, p-value: < 2.2e-16
After removing the variable smoking the variables N.deliveries is
still little significant. So we remove also this variable from the
model.
mod3<-lm(Peso ~ Gestazione + Lunghezza + Cranio + Sesso, data=dataset)
summary(mod3)
Call:
lm(formula = Peso ~ Gestazione + Lunghezza + Cranio + Sesso,
data = dataset)
Residuals:
Min 1Q Median 3Q Max
-1138.1 -184.4 -17.4 163.3 2626.7
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -6651.6732 135.5952 -49.055 < 2e-16 ***
Gestazione 31.3262 3.7884 8.269 < 2e-16 ***
Lunghezza 10.2024 0.3009 33.909 < 2e-16 ***
Cranio 10.6706 0.4247 25.126 < 2e-16 ***
SessoM 79.1027 11.2205 7.050 2.31e-12 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 275.1 on 2493 degrees of freedom
Multiple R-squared: 0.7261, Adjusted R-squared: 0.7257
F-statistic: 1652 on 4 and 2493 DF, p-value: < 2.2e-16
In the final model all the remaining variables seem very significant
so we don’t remove any further variable. We also note that the adjusted
R-squared has remained unchanged after removing the variables “age” and
“smoking” while has only slightly reduced when removing the variable
“N.deliveries”. Next we test the different models that we have
considered by looking at the analysis of variance between each model and
the subsequent one and then we look at the BIC value of the four
models.
kable(anova(mod_tot, mod1, mod2, mod3), caption="Analysis of Variance of each model with respect to the previous one") %>%
kable_styling()
Analysis of Variance of each model with respect to the previous one
| Res.Df |
RSS |
Df |
Sum of Sq |
F |
Pr(>F) |
| 2490 |
188062157 |
NA |
NA |
NA |
NA |
| 2491 |
188152606 |
-1 |
-90449.42 |
1.197578 |
0.2739122 |
| 2492 |
188246657 |
-1 |
-94050.27 |
1.245254 |
0.2645685 |
| 2493 |
188663107 |
-1 |
-416450.41 |
5.513930 |
0.0189435 |
The analysis of variance between each model and the subsequent one
shows that every time we have removed a variable the residual sum of
squares has reduced, however the reduction has been statistically
significant only once that we have removed all the three variables.
kable(BIC(mod_tot, mod1, mod2, mod3), caption="Bayesian Information Criterion (BIC) of the four models considered") %>%
kable_styling()
Bayesian Information Criterion (BIC) of the four models considered
| |
df |
BIC |
| mod_tot |
9 |
35209.56 |
| mod1 |
8 |
35202.94 |
| mod2 |
7 |
35196.36 |
| mod3 |
6 |
35194.06 |
Including only linear terms in the variables we find that the best
model, according to the BIC values, is the one that predicts the weight
of the newborn based only on the variables Length, Cranial
circumference, sex and gestation time, followed closely by the model
that included also the dependence upon the number of deliveries.
Next we start from the best model that we found and consider if to
include also nonlinear terms in the variables. In particular we note
that the the weigth should be proportional to the volume of the body and
that the volume likely depends on cubic terms in the variables length
and cranial circumferece. Indeed if we think about the body as a
cylinder or parallelepipedon we could write its volume in terms of \(length\times(cranial\_circumference)^2\) or
\(length^2\times
cranial\_circumference\).
Additionally the scatterplots suggest a possible nonlinear dependence
of the weight on the gestational age. As a first step we study the
correlation of some nonlinear terms between each other and with the
variable weight.
dataset$Gestazione2 <- (dataset$Gestazione)^2
dataset$logGestazione <- log(dataset$Gestazione)
pairs(dataset[, c("Peso", "Gestazione", "Gestazione2",
"logGestazione")], lower.panel=panel.cor, upper.panel=panel.smooth)

dataset$Lunghezza2 <- (dataset$Lunghezza)^2
dataset$Lunghezza2xCranio <- (dataset$Lunghezza)^2*(dataset$Cranio)
dataset$Cranio2 <- (dataset$Cranio)^2
dataset$LunghezzaxCranio2 <- dataset$Lunghezza*(dataset$Cranio)^2
pairs(dataset[, c("Peso","Lunghezza", "Lunghezza2", "Lunghezza2xCranio",
"Cranio", "Cranio2", "LunghezzaxCranio2")], lower.panel=panel.cor, upper.panel=panel.smooth)

Due to the realtively small range intervals of the variables we note
that the correlation between all the variables Gestation time, Length
and Cranial circumference with their quadratic version, as also between
gestation time and its logarithm, is 1 up to a second error
approximation. So it doesn’t make sense to include these terms in the
model since we can not expect them to perform significantly better than
the linear terms.
The situation is slightly different for the cubic terms mixed in
length and cranial circumference. Indeed, even if they have high
correlations with the variables length and cranial circumference they
also have higher correlations with the variable weight with respect to
the linear terms. So we try to include these terms in the model.
tot_non_lin_mod <- lm(Peso ~ N.gravidanze_CL + Gestazione + Lunghezza + Cranio + Lunghezza2xCranio + LunghezzaxCranio2 + Sesso, data=dataset)
nonlin_mod = MASS::stepAIC(tot_non_lin_mod, direction="both", k=log(N_observations))
Start: AIC=28038.58
Peso ~ N.gravidanze_CL + Gestazione + Lunghezza + Cranio + Lunghezza2xCranio +
LunghezzaxCranio2 + Sesso
Df Sum of Sq RSS AIC
<none> 182562021 28039
- N.gravidanze_CL 1 604520 183166541 28039
- Lunghezza 1 978930 183540951 28044
- LunghezzaxCranio2 1 1609628 184171649 28053
- Cranio 1 1946141 184508162 28057
- Sesso 1 3096848 185658869 28073
- Lunghezza2xCranio 1 3611489 186173510 28080
- Gestazione 1 7719667 190281688 28134
summary(nonlin_mod)
Call:
lm(formula = Peso ~ N.gravidanze_CL + Gestazione + Lunghezza +
Cranio + Lunghezza2xCranio + LunghezzaxCranio2 + Sesso, data = dataset)
Residuals:
Min 1Q Median 3Q Max
-1177.37 -182.96 -11.36 163.90 1860.40
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -3.618e+03 7.682e+02 -4.709 2.62e-06 ***
N.gravidanze_CL1+ 3.190e+01 1.111e+01 2.871 0.004121 **
Gestazione 4.063e+01 3.960e+00 10.261 < 2e-16 ***
Lunghezza -7.825e+00 2.142e+00 -3.654 0.000264 ***
Cranio 2.131e+01 4.136e+00 5.152 2.78e-07 ***
Lunghezza2xCranio 8.887e-05 1.266e-05 7.018 2.88e-12 ***
LunghezzaxCranio2 -9.650e-05 2.060e-05 -4.686 2.94e-06 ***
SessoM 7.207e+01 1.109e+01 6.499 9.73e-11 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 270.8 on 2490 degrees of freedom
Multiple R-squared: 0.735, Adjusted R-squared: 0.7342
F-statistic: 986.5 on 7 and 2490 DF, p-value: < 2.2e-16
kable(BIC(mod3, nonlin_mod), caption="Bayesian Information Criterion (BIC) of the linear model vs the nonlinear one") %>%
kable_styling()
Bayesian Information Criterion (BIC) of the linear model vs the nonlinear one
| |
df |
BIC |
| mod3 |
6 |
35194.06 |
| nonlin_mod |
9 |
35135.41 |
NA
The model selected by the stepwise method by taking into account for
all the possible nonlinear terms that we have previously considered as a
Bayesian Information Criterion (BIC) value significantly smaller than
the best model that is linear in all the variables.
Next we compute the variance inflation factors of the selected
model.
kable(car::vif(nonlin_mod), caption="Variance Inflation factors of the nonlinear model") %>%
kable_styling()
Variance Inflation factors of the nonlinear model
| |
x |
| N.gravidanze_CL |
1.035160 |
| Gestazione |
1.865538 |
| Lunghezza |
108.279420 |
| Cranio |
157.281246 |
| Lunghezza2xCranio |
666.841683 |
| LunghezzaxCranio2 |
790.238306 |
| Sesso |
1.047540 |
NA
As expected the model has extremely high variance inflaction factor
due to the high correlation coefficients between the variables. Since
the high variance inflation factors make the coefficient estimates
unstable and unreliable, we prefer to discard the last model.
However we have learnt that the inclusion of nonlinear terms can
improve the model. So, next, we try to update the last model by removing
variables that are highly correlated to see if we can get a model that
is more accurate than the linear model mod3 without having high variance
inflation factors. In particular we highlight that a model expressing
the weight linearly with respect to a volume would be physically much
more meaningfull than one espressing the weight linearly with respect to
lengths. For these reasons we opt for removing from the model the two
linear variables “length” and “cranial_circumference”
nonlin_mod2 <- update(nonlin_mod, . ~ . - Lunghezza - Cranio)
summary(nonlin_mod2)
Call:
lm(formula = Peso ~ N.gravidanze_CL + Gestazione + Lunghezza2xCranio +
LunghezzaxCranio2 + Sesso, data = dataset)
Residuals:
Min 1Q Median 3Q Max
-1157.23 -183.06 -14.76 163.04 2610.90
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.408e+03 1.214e+02 -11.598 < 2e-16 ***
N.gravidanze_CL1+ 3.268e+01 1.114e+01 2.934 0.00338 **
Gestazione 4.202e+01 3.660e+00 11.480 < 2e-16 ***
Lunghezza2xCranio 2.818e-05 1.560e-06 18.069 < 2e-16 ***
LunghezzaxCranio2 1.118e-05 2.228e-06 5.017 5.62e-07 ***
SessoM 7.099e+01 1.112e+01 6.383 2.06e-10 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 272.2 on 2492 degrees of freedom
Multiple R-squared: 0.732, Adjusted R-squared: 0.7315
F-statistic: 1361 on 5 and 2492 DF, p-value: < 2.2e-16
kable(car::vif(nonlin_mod2), caption="Variance Inflation factors of the nonlinear model") %>%
kable_styling()
Variance Inflation factors of the nonlinear model
| |
x |
| N.gravidanze_CL |
1.029988 |
| Gestazione |
1.577089 |
| Lunghezza2xCranio |
10.012010 |
| LunghezzaxCranio2 |
9.153736 |
| Sesso |
1.042580 |
After removing the variables length and cranial circumference the
variance inflation factor is still high for the two cubic variables. For
this reason we remove from the model also the variable \(Lunghezza\times Cranio^2\) which results
the less influential.
nonlin_mod3 <- update(nonlin_mod2, . ~ . - LunghezzaxCranio2)
summary(nonlin_mod3)
Call:
lm(formula = Peso ~ N.gravidanze_CL + Gestazione + Lunghezza2xCranio +
Sesso, data = dataset)
Residuals:
Min 1Q Median 3Q Max
-1178.36 -179.61 -14.04 161.78 2790.87
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.325e+03 1.209e+02 -10.964 < 2e-16 ***
N.gravidanze_CL1+ 3.886e+01 1.112e+01 3.494 0.000485 ***
Gestazione 4.088e+01 3.671e+00 11.139 < 2e-16 ***
Lunghezza2xCranio 3.536e-05 6.238e-07 56.679 < 2e-16 ***
SessoM 7.028e+01 1.117e+01 6.290 3.73e-10 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 273.5 on 2493 degrees of freedom
Multiple R-squared: 0.7293, Adjusted R-squared: 0.7289
F-statistic: 1679 on 4 and 2493 DF, p-value: < 2.2e-16
kable(car::vif(nonlin_mod3), caption="Variance Inflation factors of the nonlinear model") %>%
kable_styling()
Variance Inflation factors of the nonlinear model
| |
x |
| N.gravidanze_CL |
1.017382 |
| Gestazione |
1.571103 |
| Lunghezza2xCranio |
1.586448 |
| Sesso |
1.042414 |
kable(BIC(mod2, nonlin_mod, nonlin_mod2, nonlin_mod3), caption="Bayesian information factor of the linear mode vs nonlinear ones") %>%
kable_styling()
Bayesian information factor of the linear mode vs nonlinear ones
| |
df |
BIC |
| mod2 |
7 |
35196.36 |
| nonlin_mod |
9 |
35135.41 |
| nonlin_mod2 |
7 |
35147.43 |
| nonlin_mod3 |
6 |
35164.71 |
NA
NA
The final model predicts the weight of the new born based on
gestation time, squared length times cranium circumference, sex and
number of deliveries. The model has a BIC value larger than the best
model which included all the possible nonlinear terms but smaller than
the best model that included only linear terms in the variables.
Moreover, differently from the best model that included all the possible
nonlinear terms, the model “nonlin_mod3” has all the variance inflation
factors smaller than 5.
We point out that the model “nonlin_mod3”, including the mixed term
\(length^2\times cranial_circumferece\)
but not the linear terms in the variables \(length\) ad \(cranial_circumferece\), may break the
principle of marginality. However we highlight that the model is also
physically more meaningfull that one including the linear terms in the
variables \(length\) and \(cranial_circumference\). For these reasons
we accept this model and analyze it. We start analyzing its
coefficients
kable(coef(nonlin_mod3), caption="Coefficients of final nonlinear model") %>%
kable_styling()
Coefficients of final nonlinear model
| |
x |
| (Intercept) |
-1325.4187855 |
| N.gravidanze_CL1+ |
38.8606976 |
| Gestazione |
40.8848655 |
| Lunghezza2xCranio |
0.0000354 |
| SessoM |
70.2824691 |
The coefficients say that for each unit increment in the gestation
time (1 week) we observe an increment of approximately 40gr in the
weigth of the newborn. Similarly for each 1mm^3 increment in the volume
term (\(Length^2 \times
Cranial_circfumference\)) we register an increment of \(3.5*10^-5\) (gr) in the weight of the
newborn. Finally we observe that the males will register approximately
7gr more than females and child after the first one weight approximately
4gr more than a first child.
Next we analyze the residuals, outliers and leverages of the
model.
par(mfrow=c(2,2))
plot(nonlin_mod3)

lmtest::bptest(nonlin_mod3)
studentized Breusch-Pagan test
data: nonlin_mod3
BP = 13.12, df = 4, p-value = 0.01071
lmtest::dwtest(nonlin_mod3)
Durbin-Watson test
data: nonlin_mod3
DW = 1.9523, p-value = 0.1163
alternative hypothesis: true autocorrelation is greater than 0
shapiro.test(nonlin_mod3$residuals)
Shapiro-Wilk normality test
data: nonlin_mod3$residuals
W = 0.97047, p-value < 2.2e-16
The analysis shows that there is no autocorrelation of the residuals
(p-value of the Durbin-Watson test > 0.05). However we observe that
the residuals are not normally distributed (p-value of the Shapiro-Wilk
test <0.05) and that there is no heteroscedasticity (p-value of the
Breusch-Pagan < 0.05). Additionally we observe that there are some
highly influential outlier datapoints having Cook distance close to
0.5.
So we investigate deeper the leverages and outliers. We consider
leverages the points having leverage value larger than the threshold.
This is set equal to 3 times the leverage mean, i.e. the number of
parameters of the model over the number of observations in the dataset.
Moreover the outliers are identified by a Bonferroni test on the
studentized residuals of the model.
#leverage
lev<-hatvalues(nonlin_mod3)
plot(lev)
p<-sum(lev)
n<-length(lev)
soglia=3*p/n
abline(h=soglia,col=2)
title(main = "Leverage values of model mod1")

leverages=which(lev>soglia)
cat("There are", length(leverages), "leverages\n")
There are 46 leverages
#outliers
plot(rstudent(nonlin_mod3))
abline(h=c(-2,2))
title(main = "Studentized Residuals of model mod1")

cat("The outliers are:\n")
The outliers are:
car::outlierTest(nonlin_mod3)
#distanza di cook
cook<-cooks.distance(nonlin_mod3)
plot(cook,ylim = c(0,1))
title(main = "Cook distance of residuals of model mod1")

We note that the most influential outlier, the datapoint 1549, with a
Cook distance around 0.2, could have a relevant effect on the estimate
of the coefficients of the model but not drastical. By investigating
this datapoint we find that this is the same datapoint that we have
already met before which has a length much lower than expected, probably
for a typo in its transposition.
kable(t(dataset[1549,]), caption="Outlier datapoint") %>%
kable_styling()
Outlier datapoint
| |
1549 |
| Anni.madre |
35 |
| N.gravidanze |
1 |
| Fumatrici |
0 |
| Gestazione |
38 |
| Peso |
4370 |
| Lunghezza |
315 |
| Cranio |
374 |
| Tipo.parto |
Nat |
| Ospedale |
osp3 |
| Sesso |
F |
| N.gravidanze_CL |
1+ |
| Anni.madre_CL |
(32,38] |
| Gestazione2 |
1444 |
| logGestazione |
3.637586 |
| Lunghezza2 |
99225 |
| Lunghezza2xCranio |
37110150 |
| Cranio2 |
139876 |
| LunghezzaxCranio2 |
44060940 |
NA
Next we evaluate the quality of the model in terms of the \(R^2\) and RMSE metrics.
# R^2 :
summary_mod <- summary(nonlin_mod3)
R2 <- summary_mod$r.squared
cat("The R^2 value of the model is equal to", R2, ", so the model is explaining about 73% of the variance of the variable Weight. \n")
The R^2 value of the model is equal to 0.7293134 , so the model is explaining about 73% of the variance of the variable Weight.
# RMSE:
predictions <- predict(nonlin_mod3, newdata = dataset)
residuals <- dataset$Peso - predictions
RMSE <- sqrt(mean(residuals^2))
perRMSE=RMSE/mean(dataset$Peso)
cat("The RMSE value of the model is equal to", RMSE, ".\n")
The RMSE value of the model is equal to 273.2093 .
cat("This means that the model has a mean error of prediction of" , paste0(round(perRMSE,2),"%"),"with respect to the mean of the variable weight.\n")
This means that the model has a mean error of prediction of 0.08% with respect to the mean of the variable weight.
cat("Moreover this means that the variance of the prediction errors of the model is about", round(RMSE/sd(dataset$Peso),2), "of the variance of the variable weight")
Moreover this means that the variance of the prediction errors of the model is about 0.52 of the variance of the variable weight
Using the model to make predictions
Assume to have a female baby that will be delivered at the 39th week
and whose mother has already delivered two children. Then we can predict
her weight. For the new baby we assume a length and cranial
circumference equal to the mean weight and cranial circumferene of
female newborns at the 39th gestation week.
length= mean(subset(dataset, Sesso == "F" & Gestazione==39)$Lunghezza)
cranium= mean(subset(dataset, Sesso == "F" & Gestazione==39)$Cranio)
new_data <- data.frame("N.gravidanze" = c(2),
"Gestazione"=c(39),
"Lunghezza"=c(length),
"Cranio"=c(cranium),
"Sesso"=c("F")
)
new_data$Lunghezza2xCranio = (new_data$Lunghezza)^2*(new_data$Cranio)
new_data$Cranio2 <- (new_data$Cranio)^2
new_data$N.gravidanze_CL <- cut(new_data$N.gravidanze,
breaks=c(0,1,100),
right=FALSE,
labels=c("0","1+"))
weight_prediction <- round(predict(nonlin_mod3, newdata = new_data))
cat("The regression model predicts a weight equal to", paste0(weight_prediction,"gr"), ".\n")
The regression model predicts a weight equal to 3218gr .
Finally we display the relations captured in the model.
First we display how the weight is distributed according to the sex
and number of deliveries with respect to the quantitative variables in
the model, i.e. \(gestation\_time\) and
\((length)^2\times
cranial\_circumference\).
plot_fin_1 = ggplot(data=dataset)+
geom_point(aes(x=Gestazione,
y=Peso,
col=Sesso),position = "jitter")+
geom_smooth(aes(x=Gestazione,
y=Peso,
col=Sesso), se=F, method = "lm")+
scale_color_manual(values= sex_colors,
labels = c("M"= "Male", "F"="Female"))+
labs(title = "Weight as a function of Gestation time",
x = "gestation time",
y = "weight (gr)")+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)),
legend.title = element_text(size = 14),
legend.text = element_text(size = 14))
legend <- as_ggplot(get_legend(plot_fin_1))
plot_fin_1 = ggplot(data=dataset)+
geom_point(aes(x=Gestazione,
y=Peso,
col=Sesso),position = "jitter")+
geom_smooth(aes(x=Gestazione,
y=Peso,
col=Sesso), se=F, method = "lm")+
scale_color_manual(values= sex_colors,
labels = c("M"= "Male", "F"="Female"))+
labs(title = "Weight as a function of Gestation time",
x = "gestation time",
y = "weight (gr)")+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)),
legend.position = "none")
plot_fin_3 = ggplot(data=dataset)+
geom_point(aes(x=Lunghezza2xCranio,
y=Peso,
col=Sesso))+
geom_smooth(aes(x=Lunghezza2xCranio,
y=Peso,
col=Sesso), se=F, method = "lm")+
scale_color_manual(values= sex_colors,
labels = c("M"= "Male", "F"="Female"))+
labs(title = "Weight as a function of \n Lengt^2 x cranial circumference",
x = "Lengt^2 x cranial circumference (mm^3)",
y = "weight (gr)")+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)),
legend.position = "none")
comb_fin <- plot_fin_1 + plot_fin_3 + legend + plot_layout(ncol=3, heights = c(5), widths= c(5,5,1.5))
print(comb_fin)

plot_fin_1 = ggplot(data=dataset)+
geom_point(aes(x=Gestazione,
y=Peso,
col=N.gravidanze_CL),position = "jitter")+
geom_smooth(aes(x=Gestazione,
y=Peso,
col=N.gravidanze_CL), se=F, method = "lm")+
labs(title = "Weight as a function of Gestation time",
x = "gestation time",
y = "weight (gr)",
color = "N° previous deliveries")+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)),
legend.title = element_text(size = 14),
legend.text = element_text(size = 14))
legend <- as_ggplot(get_legend(plot_fin_1))
plot_fin_1 = ggplot(data=dataset)+
geom_point(aes(x=Gestazione,
y=Peso,
col=N.gravidanze_CL),position = "jitter")+
geom_smooth(aes(x=Gestazione,
y=Peso,
col=N.gravidanze_CL), se=F, method = "lm")+
labs(title = "Weight as a function of Gestation time",
x = "gestation time",
y = "weight (gr)")+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)),
legend.position = "none")
plot_fin_3 = ggplot(data=dataset)+
geom_point(aes(x=Lunghezza2xCranio,
y=Peso,
col=N.gravidanze_CL))+
geom_smooth(aes(x=Lunghezza2xCranio,
y=Peso,
col=N.gravidanze_CL), se=F, method = "lm")+
labs(title = "Weight as a function of \n Lengt^2 x cranial circumference",
x = "Lengt^2 x cranial circumference (mm^3)",
y = "weight (gr)")+
theme_classic()+
theme(axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)),
legend.position = "none")
comb_fin <- plot_fin_1 + plot_fin_3 + legend + plot_layout(ncol=3, heights = c(5), widths= c(5,5,1.5))
print(comb_fin)

The plots confirm that the weight increases while increasing all the
other variables in the model. Moreover we observe that the weight
observed in males is always higher than the weight observed in females.
Differently the difference in weight between first children and not
first children is only observable when varying the variable gestation
time. In this case we observe that the weight of first children is
slightly smaller than the weight of not first children. The observations
are in agreements with the discussion about the \(\beta\) coefficients of the model.
LS0tDQp0aXRsZTogIlN0YXRpc3RpY2FsX01vZGVsX05ld2Jvcm5fd2VpZ2h0Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KU3RhdGlzdGljYWwgTW9kZWwgZm9yIFByZWRpY3RpbmcgTmV3Ym9ybiBXZWlnaHQNCg0KQ29tcGFueSBDb250ZXh0IENvbXBhbnk6IE5lb25hdGFsIEhlYWx0aCBTb2x1dGlvbnMgDQoNCk9iamVjdGl2ZTogQ3JlYXRlIGEgc3RhdGlzdGljYWwgbW9kZWwgY2FwYWJsZSBvZiBhY2N1cmF0ZWx5IHByZWRpY3RpbmcgbmV3Ym9ybg0KYmlydGggd2VpZ2h0LCBiYXNlZCBvbiBjbGluaWNhbCB2YXJpYWJsZXMgY29sbGVjdGVkIGZyb20gdGhyZWUNCmhvc3BpdGFscy4gICANCg0KVGhlIHByb2plY3QgYWltcyB0byBpbXByb3ZlIHRoZSBtYW5hZ2VtZW50IG9mIGhpZ2gtcmlzayBwcmVnbmFuY2llcywgb3B0aW1pemluZyBob3NwaXRhbCByZXNvdXJjZXMgYW5kIGVuc3VyaW5nIGJldHRlciBvdXRjb21lcyBmb3IgbmVvbmF0YWwgaGVhbHRoLiAgIA0KDQpUaGUgdmFyaWFibGVzIGNvbGxlY3RlZCBpbmNsdWRlOiAgIA0KDQpNYXRlcm5hbCBBZ2U6IE1lYXN1cmUgb2YgYWdlIGluIHllYXJzLiAgIA0KDQotIE51bWJlciBvZiBQcmVnbmFuY2llczogSG93IG1hbnkgcHJlZ25hbmNpZXMgdGhlIG1vdGhlciBoYXMgcHJldmlvdXNseSBoYWQuICAgDQoNCi0gTWF0ZXJuYWwgc21va2luZzogQSBiaW5hcnkgaW5kaWNhdG9yICgwID0gbm9uLXNtb2tlciwgMSA9IHNtb2tlcikuICAgDQoNCi0gUHJlZ25hbmN5IGR1cmF0aW9uOiBOdW1iZXIgb2Ygd2Vla3Mgb2YgZ2VzdGF0aW9uLiAgIA0KDQotIEluZmFudCB3ZWlnaHQ6IEJpcnRoIHdlaWdodCBpbiBncmFtcy4gICANCg0KLSBMZW5ndGggYW5kIEhlYWQgY2lyY3VtZmVyZW5jZTogSW5mYW50IGxlbmd0aCBhbmQNCmhlYWQgZGlhbWV0ZXIsIHdoaWNoIGNhbiBhbHNvIGJlIG1lYXN1cmVkIGR1cmluZyBwcmVnbmFuY3kgdmlhDQp1bHRyYXNvdW5kLiAgIA0KDQotIFR5cGUgb2YgZGVsaXZlcnk6IE5hdHVyYWwgb3IgY2VzYXJlYW4uICAgDQoNCi0gSG9zcGl0YWwgb2YgYmlydGg6IEhvc3BpdGFsIDEsIDIsIG9yIDMuICAgDQoNCi0gSW5mYW50IHNleDogTWFsZSAoTSkgb3IgZmVtYWxlIChGKS4gICANCg0KDQpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShtb21lbnRzKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwYXRjaHdvcmspDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkoZ2dwdWJyKQ0Kb3B0aW9ucyh3aWR0aCA9IDEwMCkNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KGNhcikNCmxpYnJhcnkoZ2dwdWJyKQ0KYGBgDQoNCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBJTVBPUlQgVEhFIERBVEFTRVQNCmRhdGFzZXQgPC0gcmVhZC5jc3YoIm5lb25hdGkuY3N2IikNCg0KTl9vYnNlcnZhdGlvbnMgPSBkaW0oZGF0YXNldClbMV0NCk5fdmFyaWFibGVzID0gZGltKGRhdGFzZXQpWzJdDQpkYXRhc2V0JEZ1bWF0cmljaSA8LSBmYWN0b3IoZGF0YXNldCRGdW1hdHJpY2kpDQoNCmF0dGFjaChkYXRhc2V0KQ0KYGBgDQoNCg0KYGBge3J9DQprYWJsZShzdW1tYXJ5KGRhdGFzZXQpLCBjYXB0aW9uPSJTdW1tYXJ5IG9mIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQiKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KV2Ugbm90ZSB0aGF0IHRoZSB2YXJpYWJsZSBBZ2Ugb2YgdGhlIG1vdGhlciBoYXMgYSBtaW5pbXVtIHZhbHVlIGVxdWFsIHRvIDAgbWVhbmluZyB0aGF0IHRoZXJlIGFyZSBzb21lIHdyb25nIGRhdGEuIFNvIHdlIGZpcnN0IGRpc3BsYXkgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgYWdlIG9mIHRoZSBtb3RoZXJzLiANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHN1YnNldChkYXRhc2V0KSkrDQogIGdlb21fYmFyKGFlcyh4PUFubmkubWFkcmUpLA0KICAgICAgICAgICBzdGF0PSJjb3VudCIsDQogICAgICAgICAgIGNvbD0ia2hha2kiLA0KICAgICAgICAgICBmaWxsPSJraGFraSIpKw0KICBsYWJzKHRpdGxlPSJEaXN0cmlidXRpb24gb2YgdGhlIG1vdGhlciBhZ2UiLA0KICAgICAgIHg9IkFnZSIsDQogICAgICAgeT0iYWJzb2x1dGUgZnJlcXVlbmN5IikrDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMjAwLDIwMCkpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNDYsMikpKw0KICB0aGVtZV9jbGFzc2ljKCkrDQogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTApKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHIgPSAxMCkpKQ0KYGBgDQpXZSBjYW4gYXNzdW1lIHRoYXQgdGhlIG1pbmltdW0gbWVhbmluZ2Z1bGwgYWdlIG9mIGEgbW90aGVyIGlzIDEyIHllYXJzLiBTbyB3ZSBmaWx0ZXIgdGhlIGRhdGFzZXQgdG8gcmVtb3ZlIHRoZSBkaXJ0eSBkYXRhIGNvcnJlc3BvbmRpbmcgdG8gbW90aGVycyB3aXRoIGFuIGFnZSBzbWFsbGVyIHRoYW4gMTIuIA0KDQpgYGB7cn0NCmRhdGFzZXQgPC0gZGF0YXNldCAlPiUgDQogIGZpbHRlcihBbm5pLm1hZHJlID49MTIpDQpgYGANCg0KDQoNCiMjIE5leHQsIHdlIHN0YXJ0IGFuYWx5emluZyB0aGUgYW50aHJvcG9tZXRyaWNzIGRhdGEgKFdlaWd0aCwgTGVuZ3RoIGFuZCBDcmFuaWFsIENpcmN1bWZlcmVuY2UpIG9mIHRoZSBuZXdib3JucyBpbiB0aGUgZGF0YXNldC4gDQojIyMgRmlyc3Qgd2UgcmVwb3J0IGEgdGFibGUgd2l0aCB0aGUgc3VtbWFyeSBvZiB0aGUgc3RhdGlzdGljcyBvZiB0aGUgYW50aHJvcG9tZXRyaWNzIHZhcmlhYmxlcw0KDQpgYGB7ciBwcmVzc3VyZSwgZWNobz1GQUxTRX0NCmN2X2Z1bmN0IDwtIGZ1bmN0aW9uKHgpIHsNCiAgcmV0dXJuKHNkKHgpIC8gbWVhbih4KSAqIDEwMCkNCn0NCg0Ka3VydG9zaXNfaW5kZXggPC0gZnVuY3Rpb24oeCkgew0KICByZXR1cm4oa3VydG9zaXMoeCktMykNCn0NCg0KDQpzdGQuZXJyIDwtIGZ1bmN0aW9uKHgpew0KICByZXR1cm4gKHNkKHgpL3NxcnQoc3VtKCFpcy5uYSh4KSkpKQ0KfQ0KDQoNCnN1Yl9kYXRhIDwtIHN1YnNldChkYXRhc2V0W2MoIkNyYW5pbyIsIlBlc28iLCJMdW5naGV6emEiKV0pIywgIEdlc3RhemlvbmU+PTM3KQ0KDQpzdGF0aXN0aWNzIDwtIGRhdGEuZnJhbWUoDQogICAgICAgIA0KICBxdWFydGlsZV8xID0gcm91bmQoYXBwbHkoc3ViX2RhdGEsIDIsIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgscHJvYnM9MC4yNSwgbmFtZXM9RkFMU0UpKSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIG1lZGlhbiA9IHJvdW5kKGFwcGx5KHN1Yl9kYXRhLCAyLCBtZWRpYW4pLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBxdWFydGlsZV8zID0gcm91bmQoYXBwbHkoc3ViX2RhdGEsIDIsIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgscHJvYnM9MC43NSwgbmFtZXM9RkFMU0UpKSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIG1lYW4gPSByb3VuZChhcHBseShzdWJfZGF0YSwgMiwgbWVhbiksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBzZCA9IHJvdW5kKGFwcGx5KHN1Yl9kYXRhLCAyLCBzZCksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBjdiA9IHJvdW5kKGFwcGx5KHN1Yl9kYXRhLCAyLCBjdl9mdW5jdCksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBza2V3bmVzcyA9IHJvdW5kKGFwcGx5KHN1Yl9kYXRhLCAyLCBza2V3bmVzcyksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBrdXJ0b3NpcyA9IHJvdW5kKGFwcGx5KHN1Yl9kYXRhLCAyLCBrdXJ0b3Npc19pbmRleCksMiksDQogIA0KICBzdGRfZXJyID0gcm91bmQoYXBwbHkoc3ViX2RhdGEsMixzdGQuZXJyKSwyKQ0KKQ0KDQoNCnJvd25hbWVzKHN0YXRpc3RpY3MpIDwtIGMoIkNyYW5pYWwgY2lyY3VtZmVyZW5jZSAobW0pIiwgIldlaWdodCAoZ3IpIiwgIkxlbmd0aCAobW0pIikNCg0Ka2FibGUoc3RhdGlzdGljcywgY2FwdGlvbj0iSW5kaWNlcyBvZiB3ZWlnaHQsIGxlbmd0aCBhbmQgY3JhbmlhbCBkaWFtZXRlciIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQoNCiMjIyBTZWNvbmQgd2UgZGlzcGxheSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBhbnRocm9wb21ldHJpYyB2YXJpYWJsZXMgYWdhaW4gYSBub3JtYWwgZGlzdHJpYnV0aW9uDQoNCmBgYHtyfQ0KIyB0aGUgZnVuY3Rpb24gbm9ybWFsaXplIHRha2VzIGluIGlucHV0IGEgdmFyaWFibGUgaW4gc3RyaW5nIGZvcm0gYW5kIHJldHVybnMgaXRzIHZhbHVlcyBub3JtYWxpemVkIGJ5IGl0cyBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24NCm5vcm1hbGl6ZSA8LSBmdW5jdGlvbih4KXsNCiAgcmV0dXJuICgoeC1tZWFuKHgpKS9zZCh4KSkNCn0NCg0KIyB3ZSBnZW5lcmF0ZSBhIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24NCmdhdXNzaWFuX2Rpc3RyaWJ1dGlvbiA8LSBybm9ybSgxMDAwMDAwLDAsMSkNCg0KDQojIHdlIHBsb3QgdGhlIGRlbnNpdHkgb2YgdGhlIGRpZmZlcmVudCB2YXJpYWJsZXMgYWdhaW5zdCBhIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24NCmdncGxvdCgpKw0KICBnZW9tX2RlbnNpdHkoYWVzKHg9Z2F1c3NpYW5fZGlzdHJpYnV0aW9uLCBmaWxsPSJOMDEiKSwgY29sb3I9TkEsICBhbHBoYT0uOCkrDQogIGdlb21fZGVuc2l0eShhZXMoeD1ub3JtYWxpemUoUGVzbyksIGNvbG9yPSJXZWlnaHQiKSwgbGluZXdpZHRoPTEuNSkrDQogIGdlb21fZGVuc2l0eShhZXMoeD1ub3JtYWxpemUoQ3JhbmlvKSwgY29sb3I9IkNyYW5pYWwgY2lyY3VtZmVyZW5jZSIpLCBsaW5ld2lkdGg9MS41KSsNCiAgZ2VvbV9kZW5zaXR5KGFlcyh4PW5vcm1hbGl6ZShMdW5naGV6emEpLCBjb2xvcj0iTGVuZ3RoIiksIGxpbmV3aWR0aD0xLjUpKw0KICBsYWJzKHRpdGxlPSJEaXN0cmlidXRpb24gb2YgdGhlIHZhcmlhYmxlcyIsDQogICAgICAgeD0iTm9ybWFsaXplZCB2YXJpYWJsZSAiLA0KICAgICAgIHk9ImRlbnNpdHkiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhOMDEgPSAiZ3JleSIpLCAgIA0KICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKE4wMSA9ICJOKDAsMSkiKSkgKw0KICB0aGVtZV9jbGFzc2ljKCkrDQogIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGFuZWwiLA0KICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKSsNCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvciA9IE5BKSkpKw0KICBsYWJzKGNvbG9yID0gIlZhcmlhYmlsZSIsDQogICAgICBmaWxsID0gIkRpc3RyaWJ1emlvbmUgbm9ybWFsZSIpDQpgYGANCg0KVGhlIHBsb3RzIGFzIGFsc28gdGhlIHZhbHVlcyBvZiBza2V3ZW5lc3MgYW5kIEt1cnRvc2lzIHNob3cgdGhhdDogICANCg0KLSBBbGwgdGhlIGFudGhyb3BvbWV0cmljIHZhcmlhYmxlcyBhcmUgbW9yZSBwZWFrZWQgdGhhbiBhIG5vcm1hbCBkaXN0cmlidXRpb24sIHNvIHRoZSBwcm9iYWJpbGl0eSBvZiBvdXRsaWVycyBpcyBzbWFsbGVyIHRoYXQgZm9yIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggc2FtZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24uICAgDQoNCi0gVmFsdWVzIGluIHRoZSBsZWZ0IHRhaWxzIG9mIHRoZSBkaXN0cmlidXRpb25zIGFyZSBtb3JlIGxpa2VseSB0aGFuIHZhbHVlcyBpbiB0aGUgcmlnaHQgdGFpbC4gVGhpcyBjb3VsZCBiZSBkdWUgdG8gdGhlIGRhdGEgcmVsYXRpdmUgdG8gcHJlbWF0dXJlIGJpcnRocy4gICANCg0KDQpUbyBjaGVjayBpZiB0aGUgYXN5bW1ldHJ5IGlzIGR1ZSB0byB0aGUgcHJlbWF0dXJlIGJpcnRocyB3ZSBwbG90IHRoZSBkaXN0cmlidXRpb24gb2YgYmlydGhzIGJ5IGdlc3RhdGlvbmFsIHdlZWtzLiAgDQoNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YT1kYXRhc2V0KSsNCiAgZ2VvbV9iYXIoYWVzKHg9R2VzdGF6aW9uZSksDQogICAgICAgICAgIHN0YXQ9ImNvdW50IiwNCiAgICAgICAgICAgY29sPSJwaW5rIiwNCiAgICAgICAgICAgZmlsbD0icGluayIpKw0KICBsYWJzKHRpdGxlPSJEaXN0cmlidXRpb24gb2YgZ2VzdGF0aW9uYWwgYWdlIGF0IGNoaWxkYmlydGgiLA0KICAgICAgIHg9Imdlc3RhdGlvbmFsIGFnZSAod2Vla3MpIiwNCiAgICAgICB5PSJhYnNvbHV0ZSBmcmVxdWVuY3kiKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDc1MCw1MCkpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDI1LDQzLDEpKSsNCiAgdGhlbWVfY2xhc3NpYygpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE1LCBoanVzdCA9IDEpLA0KICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbihyID0gMTApKSkNCmBgYA0KDQoNCkEgZGVsaXZlcnkgaXMgY29uc2lkZXJlZCBwcmVtYXR1cmUgaWYgaXQgb2NjdXJzIGJlZm9yZSAzNyB3ZWVrcyBvZiBnZXN0YXRpb24uIEJ5IGxvb2tpbmcgYXQgdGhlIGJhcnBsb3Qgd2Ugbm90ZSB0aGVyZSBleGlzdCBkaWZmZXJlbnQgbWFueSBwcmVtYXR1cmUgYmlydGhkcyBpbiB0aGUgZGF0YXNldC4gV2UgZXhwZWN0IHRoZSBhbnRocm9wb21ldHJpYyBtZWFzdXJlbWVudHMgb2YgcHJlbWF0dXJlIG5ld2Jvcm5zIHRvIGJlIHNpZ25pZmljYW50bHkgc21hbGxlci4gIA0KDQpTbyB3ZSBmaWx0ZXIgdGhlIGRhdGEgcmVsYXRpdmUgb25seSB0byB0aGUgbm9uLXByZW1hdHVyZSBiaXJ0aHMgYW5kIHN0dWR5IHRoZWlyIHN0YXRpc3RpY3MuIA0KDQoNCmBgYHtyfQ0KcmVndWxhcl9kZWxpdmVyaWVzX2RhdGEgPC0gZGF0YXNldCAlPiUgZmlsdGVyKEdlc3RhemlvbmUgPj0gMzcpDQoNCnN0YXRpc3RpY3NfcmVndWxhcl9kZWxpdmVyaWVzIDwtIGRhdGEuZnJhbWUoDQogICAgICAgIA0KICBxdWFydGlsZV8xID0gcm91bmQoYXBwbHkocmVndWxhcl9kZWxpdmVyaWVzX2RhdGFbYygiQ3JhbmlvIiwiUGVzbyIsIkx1bmdoZXp6YSIpXSwgMiwgZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCxwcm9icz0wLjI1LCBuYW1lcz1GQUxTRSkpLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgbWVkaWFuID0gcm91bmQoYXBwbHkocmVndWxhcl9kZWxpdmVyaWVzX2RhdGFbYygiQ3JhbmlvIiwiUGVzbyIsIkx1bmdoZXp6YSIpXSwgMiwgbWVkaWFuKSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgcXVhcnRpbGVfMyA9IHJvdW5kKGFwcGx5KHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhW2MoIkNyYW5pbyIsIlBlc28iLCJMdW5naGV6emEiKV0sIDIsIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgscHJvYnM9MC43NSwgbmFtZXM9RkFMU0UpKSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIG1lYW4gPSByb3VuZChhcHBseShyZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YVtjKCJDcmFuaW8iLCJQZXNvIiwiTHVuZ2hlenphIildLCAyLCBtZWFuKSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIHNkID0gcm91bmQoYXBwbHkocmVndWxhcl9kZWxpdmVyaWVzX2RhdGFbYygiQ3JhbmlvIiwiUGVzbyIsIkx1bmdoZXp6YSIpXSwgMiwgc2QpLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgY3YgPSByb3VuZChhcHBseShyZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YVtjKCJDcmFuaW8iLCJQZXNvIiwiTHVuZ2hlenphIildLCAyLCBjdl9mdW5jdCksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBza2V3bmVzcyA9IHJvdW5kKGFwcGx5KHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhW2MoIkNyYW5pbyIsIlBlc28iLCJMdW5naGV6emEiKV0sIDIsIHNrZXduZXNzKSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGt1cnRvc2lzID0gcm91bmQoYXBwbHkocmVndWxhcl9kZWxpdmVyaWVzX2RhdGFbYygiQ3JhbmlvIiwiUGVzbyIsIkx1bmdoZXp6YSIpXSwgMiwga3VydG9zaXNfaW5kZXgpLDIpLA0KICANCiAgc3RkX2VyciA9IHJvdW5kKGFwcGx5KHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhW2MoIkNyYW5pbyIsIlBlc28iLCJMdW5naGV6emEiKV0sMixzdGQuZXJyKSwyKQ0KKQ0KDQpyb3duYW1lcyhzdGF0aXN0aWNzX3JlZ3VsYXJfZGVsaXZlcmllcykgPC0gYygiQ3JhbmlhbCBjaXJjdW1mZXJlbmNlIChtbSkiLCAiV2VpZ2h0IChncikiLCAiTGVuZ3RoIChtbSkiKQ0KDQprYWJsZShzdGF0aXN0aWNzX3JlZ3VsYXJfZGVsaXZlcmllcywgY2FwdGlvbj0iSW5kaWNlcyBvZiB3ZWlnaHQsIGxlbmd0aCBhbmQgY3JhbmlhbCBkaWFtZXRlciBvZiB0aGUgbm9uLXByZW1hdHVyZSBiaXJ0aHMiKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQoNCg0KDQojIHdlIHBsb3QgdGhlIGRlbnNpdHkgb2YgdGhlIGRpZmZlcmVudCB2YXJpYWJsZXMgYWdhaW5zdCBhIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24NCmdncGxvdCgpKw0KICBnZW9tX2RlbnNpdHkoYWVzKHg9Z2F1c3NpYW5fZGlzdHJpYnV0aW9uLCBmaWxsPSJOMDEiKSwgY29sb3I9TkEsICBhbHBoYT0uOCkrDQogIGdlb21fZGVuc2l0eShhZXMoeD1ub3JtYWxpemUocmVndWxhcl9kZWxpdmVyaWVzX2RhdGEkUGVzbyksIGNvbG9yPSJXZWlnaHQiKSwgbGluZXdpZHRoPTEuNSkrDQogIGdlb21fZGVuc2l0eShhZXMoeD1ub3JtYWxpemUocmVndWxhcl9kZWxpdmVyaWVzX2RhdGEkQ3JhbmlvKSwgY29sb3I9IkNyYW5pYWwgY2lyY3VtZmVyZW5jZSIpLCBsaW5ld2lkdGg9MS41KSsNCiAgZ2VvbV9kZW5zaXR5KGFlcyh4PW5vcm1hbGl6ZShyZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YSRMdW5naGV6emEpLCBjb2xvcj0iTGVuZ3RoIiksIGxpbmV3aWR0aD0xLjUpKw0KICBsYWJzKHRpdGxlPSJEaXN0cmlidXRpb24gb2YgdGhlIGFudGhyb3BvbWV0cmljIHZhcmlhYmxlcyBcbiByZWxhdGl2ZSB0byB0aGUgbm9uLXByZW1hdHVyZSBkZWxpdmVyaWVzIiwNCiAgICAgICB4PSJOb3JtYWxpemVkIHZhcmlhYmxlICIsDQogICAgICAgeT0iZGVuc2l0eSIpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKE4wMSA9ICJncmV5IiksICAgDQogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoTjAxID0gIk4oMCwxKSIpKSArDQogIHRoZW1lX2NsYXNzaWMoKSsNCiAgdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwYW5lbCIsDQogICAgICAgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGNvbG9yID0gTkEpKSkrDQogIGxhYnMoY29sb3IgPSAiVmFyaWFiaWxlIiwNCiAgICAgIGZpbGwgPSAiRGlzdHJpYnV6aW9uZSBub3JtYWxlIikNCmBgYA0KDQpUaGUgc2lnbmlmaWNhbnRseSBzbWFsbGVyIHZhbHVlcyBvZiBza2V3ZW5lc3Mgb2YgYWxsIHRoZSBhbnRocm9wb21ldHJpYyB2YXJpYWJsZXMgY29ycmVzcG9uZGluZyBvbmx5IHRvIHRoZSBub24tcHJlbWF0dXJlIGJpcnRocyBjb25maXJtIHRoYXQgdGhlIGFzeW1tZXRyeSB0aGF0IHdlIGhhZCBwcmV2aW91c2x5IG9ic2VydmVkIHdhcyBtYWlubHkgZHVlIHRvIHRoZSBwcmVzZW5jZSBvZiBwcmVtYXR1cmUgYmlydGhzLiBBbHNvIHRoZSB2YWx1ZXMgb2YgdGhlIGt1cnRvc2lzIGhhdmUgc2lnbmlmaWNhbmx0eSBkZWNyZWFzZWQgc3VnZ2VzdGluZyBhIG11Y2ggYmV0dGVyIG5vcm1hbCBhcHByb3hpbWF0aW9uIG9mIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGFudGhyb3BvbWV0cmljIHZhcmlhYmxlcyB3aGVuIGZpbHRlcmluZyB0aGUgZGF0YSBjb3JyZXNwb25kaW5nIHRvIHRoZSBvbmx5IG5vbi1wcmVtYXR1cmUgZGVsaXZlcmllcy4gVGhlIGxlbmd0aCBpcyB0aGUgb25seSB2YXJpYWJsZXMgdGhhdCBpcyBub3QgcmVhbGx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBUaGUgbm9uLW5vcm1hbGl0eSBvZiB0aGUgdmFyaWFibGUgTGVuZ2h0IGNvdWxkIGJlIGR1ZSB0byB0aGUgcHJlc2VuemUgb2Ygc29tZSBjb3JydXB0ZWQgZGF0YS4gDQpUbyB0aGlzIGVuZCB3ZSBzdHVkeSB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgYW50aHJvcG9tZXRyaWMgdmFyaWFibGVzLg0KDQoNCmBgYHtyfQ0KDQoNCmNhdCgiVGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50ZSBvZiB0aGUgdmFyaWFibGUgTGVuZ3RoIHdpdGggdGhlIHZhcmlibGVzIFdlaWdodCBhbmQgQ3JhbmlhbCBjaXJjdW1mZXJlbmNlIGluIG5vbiBwcmVtYXR1cmUgbmV3Ym9ybnMgaXMgZXF1YWwgdG86IFxuIiwgDQogICAgIi1jb3IoTGVuZ3RoLCBXZWlnaHQpID0gIiwgY29yKHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhJEx1bmdoZXp6YSwgcmVndWxhcl9kZWxpdmVyaWVzX2RhdGEkUGVzbykNCiAsICJcbiIsDQogICAgIi1jb3IoTGVuZ3RoLCBDcmFuaWFsIGNpcmN1bWZlcmVuY2UpID0gIiwgY29yKHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhJEx1bmdoZXp6YSwgcmVndWxhcl9kZWxpdmVyaWVzX2RhdGEkQ3JhbmlvKQ0KKQ0KYGBgDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTV9DQpzY2F0dDEgPSBnZ3Bsb3QocmVndWxhcl9kZWxpdmVyaWVzX2RhdGEsIGFlcyh4ID0gTHVuZ2hlenphLCB5ID0gUGVzbykpICsgDQogICAgICAgICAgICAgICAgZ2VvbV9wb2ludCgpKw0KICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSsNCiAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHIgPSAxMCkpKSsNCiAgICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJTY2F0dGVycGxvdCBvZiBMZW5naHQgYWdhaW5zdCBXZWlnaHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9IiBMZW5naHQobW0pIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSIgV2VpZ2h0KGdyKSIpKw0KICAgICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwMCw1MDAwLDUwMCkpKw0KICAgICAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMzAwLDYwMCw1MCkpDQoNCg0Kc2NhdHQyID0gZ2dwbG90KHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhLCBhZXMoeCA9IEx1bmdoZXp6YSwgeSA9IENyYW5pbykpICsgDQogICAgICAgICAgICAgICAgZ2VvbV9wb2ludCgpKw0KICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSsNCiAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHIgPSAxMCkpKSsNCiAgICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJTY2F0dGVycGxvdCBvZiBMZW5naHQgYWdhaW5zdCBDcmFuaWFsIGNpcmN1bWZlcmVuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9IiBMZW5naHQobW0pIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSIgQ3JhbmlhbCBjaXJjdW1mZXJlbmNlKG1tKSIpKw0KICAgICAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMzAwLDYwMCw1MCkpDQoNCmNvbWJfZmlnX3NjYXR0IDwtIHNjYXR0MSArIHNjYXR0MiArIHBsb3RfbGF5b3V0KG5jb2w9MiwgaGVpZ2h0cyA9IGMoNSksIHdpZHRocz0gYyg1LDUpKQ0KcHJpbnQoY29tYl9maWdfc2NhdHQpDQpgYGANCkZyb20gdGhlIHNjYXR0ZXJwbG90cywgaXQgY2FuIGJlIHNlZW4gdGhhdCB0aGVyZSBpcyBvbmUgb3V0bGllciBtZWFzdXJlbWVudCByZXBvcnRpbmcgYSBsZW5ndGggc21hbGxlciB0aGFuIDM1MCBtbSwgd2hpY2ggY291bGQgYmUgZHVlIHRvIGFuIGVycm9yIGluIHRoZSBkYXRhc2V0LCBzdWNoIGFzIGEgdHlwbyBpbiB0aGUgYW5ub3RhdGlvbiBvZiB0aGUgbmV3Ym9ybidzIGxlbmd0aC4gDQpTbyB3ZSBkZWNpZGUgdG8gY2xlYW4gdGhlIGRhdGFzZXQgb2YgcmVndWxhciBuZXdib3JucyBmcm9tIHRoaXMgZGF0YXBvaW50Lg0KDQpgYGB7cn0NCnJlZ3VsYXJfZGVsaXZlcmllc19kYXRhIDwtIHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhICU+JSBmaWx0ZXIoTHVuZ2hlenphID49IDM1MCkNCg0Kc3RhdGlzdGljc19yZWd1bGFyX2RlbGl2ZXJpZXMgPC0gZGF0YS5mcmFtZSgNCiAgICAgICAgDQogIHF1YXJ0aWxlXzEgPSByb3VuZChhcHBseShyZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YVtjKCJDcmFuaW8iLCJQZXNvIiwiTHVuZ2hlenphIildLCAyLCBmdW5jdGlvbih4KSBxdWFudGlsZSh4LHByb2JzPTAuMjUsIG5hbWVzPUZBTFNFKSksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBtZWRpYW4gPSByb3VuZChhcHBseShyZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YVtjKCJDcmFuaW8iLCJQZXNvIiwiTHVuZ2hlenphIildLCAyLCBtZWRpYW4pLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBxdWFydGlsZV8zID0gcm91bmQoYXBwbHkocmVndWxhcl9kZWxpdmVyaWVzX2RhdGFbYygiQ3JhbmlvIiwiUGVzbyIsIkx1bmdoZXp6YSIpXSwgMiwgZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCxwcm9icz0wLjc1LCBuYW1lcz1GQUxTRSkpLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgbWVhbiA9IHJvdW5kKGFwcGx5KHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhW2MoIkNyYW5pbyIsIlBlc28iLCJMdW5naGV6emEiKV0sIDIsIG1lYW4pLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgc2QgPSByb3VuZChhcHBseShyZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YVtjKCJDcmFuaW8iLCJQZXNvIiwiTHVuZ2hlenphIildLCAyLCBzZCksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBjdiA9IHJvdW5kKGFwcGx5KHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhW2MoIkNyYW5pbyIsIlBlc28iLCJMdW5naGV6emEiKV0sIDIsIGN2X2Z1bmN0KSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIHNrZXduZXNzID0gcm91bmQoYXBwbHkocmVndWxhcl9kZWxpdmVyaWVzX2RhdGFbYygiQ3JhbmlvIiwiUGVzbyIsIkx1bmdoZXp6YSIpXSwgMiwgc2tld25lc3MpLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAga3VydG9zaXMgPSByb3VuZChhcHBseShyZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YVtjKCJDcmFuaW8iLCJQZXNvIiwiTHVuZ2hlenphIildLCAyLCBrdXJ0b3Npc19pbmRleCksMiksDQogIA0KICBzdGRfZXJyID0gcm91bmQoYXBwbHkocmVndWxhcl9kZWxpdmVyaWVzX2RhdGFbYygiQ3JhbmlvIiwiUGVzbyIsIkx1bmdoZXp6YSIpXSwyLHN0ZC5lcnIpLDIpDQopDQoNCnJvd25hbWVzKHN0YXRpc3RpY3NfcmVndWxhcl9kZWxpdmVyaWVzKSA8LSBjKCJDcmFuaWFsIGNpcmN1bWZlcmVuY2UgKG1tKSIsICJXZWlnaHQgKGdyKSIsICJMZW5ndGggKG1tKSIpDQoNCmthYmxlKHN0YXRpc3RpY3NfcmVndWxhcl9kZWxpdmVyaWVzLCBjYXB0aW9uPSJJbmRpY2VzIG9mIHdlaWdodCwgbGVuZ3RoIGFuZCBjcmFuaWFsIGRpYW1ldGVyIG9mIHRoZSBub24tcHJlbWF0dXJlIGJpcnRocyIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQpXZSBvYnNlcnZlIHRoYXQgbm93LCBpbiB0aGUgY2xlYW5lZCBkYXRhc2V0LCBhbHNvIHRoZSB2YXJpYWJsZSBMZW5ndGggZm9sbG93cyBhcHByb3hpbWF0ZWx5IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgd2l0aCBib3RoIGt1cnRvc2lzIGFuZCBza2V3bmVzcyBjb2VmZmljaWVudHMgY2xvc2UgdG8gMC4NCg0KDQojIyMgQW5hbHlzaXMgb2Ygd2VpZ2h0LCBsZW5ndGggYW5kIGNyYW5pYWwgZGlhbWV0ZXIgb2YgdGhlIHNhbXBsZSB3aXRoIHJlc3BlY3QgdG8gdGhlIHBvcHVsYXRpb24gc3RhdGlzdGljcy4NCg0KQWNjb3JkaW5nIHRvIHRoZSBzdHVkeSBbSW50ZXJuYXRpb25hbCBzdGFuZGFyZHMgZm9yIG5ld2Jvcm4gd2VpZ2h0LA0KbGVuZ3RoLCBhbmQgaGVhZCBjaXJjdW1mZXJlbmNlIGJ5IGdlc3RhdGlvbmFsIGFnZSBhbmQNCnNleF0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvUzAxNDAtNjczNigxNCk2MDkzMi02KSwgdGhlIGJpcnRod2VpZ2h0LA0KYmlydGhsZW5ndGggYW5kIGJpcnRoIGhlYWQgY2lyY3VtZmVyZW5jZSBvZiBiYWJpZXMgYm9ybiBpbiBJdGFseSBmcm9tDQp0aGUgMzd0aCB3ZWVrIG9mIGdlc3RhdGlvbiBvbiwgaGF2ZSB0aGUgZm9sbG93aW5nIG1lYW4gYW5kIHN0YW5kYXJkDQpkZXZpYXRpb246DQoNCi0gICBiaXJ0aHdlaWdodDogTWVhbiA9IDMuMywgU0QgPSAwLjQsDQoNCi0gICBiaXJ0aGxlbmd0aDogTWVhbiA9IDQ5LjQsIFNEID0gMS43LA0KDQotICAgYmlydGggaGVhZCBjaXJjdW1mZXJlbmNlOiBNZWFuID0gMzQuMCwgU0QgPSAxLjINCg0KRnJvbSB0aGUgY2VudHJhbCBsaW1pdCB0aGVvcmVtIHdlIGtub3cgdGhhdCBnaXZlbiBhIHJhbmRvbSB2YXJpYWJsZQ0KWCB3aXRoIG1lYW4gJFxtdV8wJCBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uICRcc2lnbWEkLCB0aGUgbWVhbiBvdmVyIGENCnJhbmRvbSBzYW1wbGUgb2YgTiBwZW9wbGUgZGlzdHJpYnV0ZXMgYXMgYSByYW5kb20gdmFyaWFibGUgZm9sbG93aW5nIGENCm5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBtZWFuICRcbXVfMCQgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiAkXHNpZ21hL04kLg0KDQpTbyBmb3IgdGhlIHRocmVlIHZhcmlhYmxlcyB3ZWlnaHQsIGxlbmd0aCBhbmQgY3JhbmlhbCBjaXJjdW1mZXJlbmNlIHdlDQphc3N1bWUgYXMgbnVsbCBoeXBvdGhlc2lzIChIMCkgdGhhdCB0aGV5IGhhdmUgbWVhbiAkXG11XzA9JCAzMzAwIGdyLA0KNDkuNCBjbSBhbmQgMzQgY20gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiAkXHNpZ21hPSQgNDAwZ3IsIDEuN2NtLCAxLjJjbSwNCnJlc3BlY3RpdmVseS4gVGhlbiB3ZSB0ZXN0IHRoaXMgaHlwb3RoZXNlcyB1c2luZyBhIFotdGVzdC4gVG8gdGhpcyBlbmQNCndlIGNvbnNpZGVyIHRoZSBzdWItZGF0YXNldCBjb3JyZXNwb25kaW5nIHRvIHRoZSBiaXJ0aHMgYWZ0ZXIgdGhlIDM3dGgNCndlZWsgb2YgZ2VzdGF0aW9uLCBoYXZpbmcgbGVuZ3RoICROJC4gDQoNClRoZW4gd2UgY29tcHV0ZSB0aGUgWi10ZXN0IHZhbHVlIA0KJCRaID0gXGZyYWN7bWVhbihWYXJpYWJsZSktXG11XzB9e1xzaWdtYS9cc3FydHtOfX0uJCQNCg0KDQpXZSBjb21wdXRlIHRoZSBjb3JyZXNwb25maW5nIHAtdmFsdWVzLCBpLmUuIHRoZSBwcm9iYWJpbGl0eSBvZiBnZXR0aW5nIGEgdmFsdWUgZXF1YWwgb3INCnNtYWxsZXIgdGhhbiBtZWFuKFZhcmlhYmxlKSBieSByYW5kb21seSBzYW1wbGluZyBOIGJpcnRocy4gSWYgdGhlDQpwLXZhbHVlIGlzIHNtYWxsZXIgdGhhbiB0aGUgbGV2ZWwgb2Ygc2lnbmlmaWNhbmNlIHRoYXQgd2Ugc2V0IHRvIDAuMDUsDQp3ZSByZWplY3QgdGhlIGh5cG90aGVzaXMgSDAuDQoNCmBgYHtyfQ0Kel90ZXN0ID0gZnVuY3Rpb24oeCwgbXUwLCBzdGRldiwgYWxmYSl7DQoNCiAgeCA9IG5hLm9taXQoeCkNCiAgbXVfY2FwID0gbWVhbih4KQ0KICBuID0gbGVuZ3RoKHgpDQogIA0KICBaID0gKG11X2NhcCAtIG11MCkgLyAoc3RkZXYgLyBzcXJ0KG4pKQ0KICB2YWxvcmkuc29nbGlhID0gcW5vcm0oYyhhbGZhLzIsIDEtYWxmYS8yKSkNCiAgDQogIENJIDwtIGMobXVfY2FwK3Fub3JtKGFsZmEvMikqKHN0ZGV2L3NxcnQobikpLA0KICAgICAgICAgIG11X2NhcC1xbm9ybShhbGZhLzIpKihzdGRldi9zcXJ0KG4pKSkNCiAgICANCiAgcmV0dXJuKA0KICAgIGxpc3QobWVhbi5zYW1wbGU9IG11X2NhcCwNCiAgICAgICAgIHN0YXQudGVzdCA9IFosDQogICAgICAgICB0aHJlc2hvbGQudmFsID0gdmFsb3JpLnNvZ2xpYSwNCiAgICAgICAgIHB2YWx1ZSA9IDIqcG5vcm0oLWFicyhaKSksDQogICAgICAgICBJbnQuQ29uZi4gPSBDSQ0KICAgICAgICAgKSkNCn0NCmBgYA0KDQoNCg0KYGBge3J9DQp6X3Rlc3Rfd2VpZ2h0ID0gel90ZXN0KHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhJFBlc28sIDMzMDAsIDQwMCwgMC4wNSkNCg0Kel90ZXN0X2xlbmd0aCA9IHpfdGVzdChyZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YSRMdW5naGV6emEsIDQ5NCwgMTcsIDAuMDUpDQoNCnpfdGVzdF9jcmFuaWFsX2RpYW0gPSB6X3Rlc3QocmVndWxhcl9kZWxpdmVyaWVzX2RhdGEkQ3JhbmlvLCAzNDAsIDEyLCAwLjA1KQ0KDQoNCmNhdCgiVGhlIHAtdmFsdWVzIG9mIGxlbmd0aCwgd2VpZ2h0IGFuZCBjcmFuaWFsIGNpcmN1bWZlcmVuY2UgYXJlIGFsbCBzbWFsbGVyIHRoYW4gMC4wNSwgc28gd2UgcmVqZWN0IHRoZSBoeXBvdGhlc2lzIEgwIHRoYXQgdGhlIHRocmVlIHZhcmlhYmxlcyBhcmUgZGlzdHJpYnV0ZWQgYWNjb3JkaW5nIHRvIHRoZSBkaXN0cmlidXRpb24gb2Ygd2VpZ2h0LCBsZW5ndGggYW5kIGNyYW5pYWwgZGlhbWV0ZXIgb2YgdGhlIGl0YWxpYW4gcG9wdWxhdGlvbi4gXG4iLCANCiAgICAiLXBfdmFsdWUoV2VpZ2h0KSA9ICIsIHpfdGVzdF93ZWlnaHQkcHZhbHVlICwgIlxuIiwNCiAgICAiLXBfdmFsdWUoTGVuZ3RoKSA9ICIsIHpfdGVzdF9sZW5ndGgkcHZhbHVlICwgIlxuIiwNCiAgICAiLXBfdmFsdWUoQ3JhbmlhbCBkaWFtZXRlcikgPSAiLCB6X3Rlc3RfY3JhbmlhbF9kaWFtJHB2YWx1ZSApDQpgYGANCg0KSW4gcGFydGljdWxhciB3ZSBkaXNwbGF5IHRoZSBaLXRlc3QgdmFsdWVzIG9mIHRoZSBhbnRocm9wb21ldHJpYyB2YXJpYWJsZXMgYWdhaW5zdCB0aGUgbGV2ZWwgb2Ygc2lnbmlmaWNhbmNlIG9mIDAuMDUgb2YgdGhlIFotdGVzdC4NCg0KYGBge3J9DQpnZ3Bsb3QoKSsNCiAgZ2VvbV9kZW5zaXR5KGFlcyh4PWdhdXNzaWFuX2Rpc3RyaWJ1dGlvbiwgZmlsbD0iTjAxIiksIGNvbG9yPU5BLCAgYWxwaGE9LjgpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD16X3Rlc3Rfd2VpZ2h0JHN0YXQudGVzdCwgY29sb3I9IldlaWdodCIpLCBsaW5ld2lkdGg9MS41KSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9el90ZXN0X2xlbmd0aCRzdGF0LnRlc3QsIGNvbG9yPSJMZW5ndGgiKSwgbGluZXdpZHRoPTEuNSkrDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9el90ZXN0X2NyYW5pYWxfZGlhbSRzdGF0LnRlc3QsIGNvbG9yPSJDcmFuaWFsIGNpcmN1bWZlcmVuY2UiKSwgbGluZXdpZHRoPTEuNSkrDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9el90ZXN0X2xlbmd0aCR0aHJlc2hvbGQudmFsLCBjb2xvcj0iVGhyZXNob2xkIHA9MC4wNSIpLGxpbmV3aWR0aD0xLCBsaW5ldHlwZT0iZGFzaGVkIikrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIldlaWdodCI9ICJnb2xkMSIsICJMZW5ndGgiPSJnb2xkNCIsICJDcmFuaWFsIGNpcmN1bWZlcmVuY2UiPSJnb2xkMyIsICJUaHJlc2hvbGQgcD0wLjA1Ij0icmVkIikpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKE4wMSA9ICJncmV5IiksICAgDQogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoTjAxID0gIk4oMCwxKSIpKSArDQogIGxhYnModGl0bGU9IlogdmFsdWVzIG9mIHdlaWdodCwgbGVuZ3RoIGFuZCBjcmFuaWFsIGNpcmN1bWZlcmVuY2UiLA0KICAgICAgIHg9IiAiLA0KICAgICAgIHk9IiAiKSsNCiAgdGhlbWVfY2xhc3NpYygpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE1LCBoanVzdCA9IDEpLA0KICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbihyID0gMTApKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0iYm90dG9tIikNCmBgYA0KDQoNCiMjIyBBbmFseXNpcyBvZiB0aGUgZGlmZmVyZW5jZXMgaW4gdGhlIGFudHJob3BvbWV0cmljIHZhcmlhYmxlcyBhY3Jvc3MgdGhlIGRpZmZlcmVudCBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzLg0KDQpGaXJzdCB3ZSBkaXNwbGF5IHRoZSBkaXN0cmlidXRpb24gb2YgbmV3Ym9ybnMgYmV0d2VlbiB0aGUgdHdvIHNleGVzLCB3aGljaCByZXN1bHQgcXVpdGUgdW5pZm9ybS4NCg0KDQoNCmBgYHtyfQ0Kc2V4X2NvbG9ycyA8LSBjKCJNIiA9ICJkb2RnZXJibHVlIiwgIkYiID0gImhvdHBpbmsiKSAgDQoNCg0KZ2dwbG90KGRhdGE9ZGF0YXNldCkrDQogIGdlb21fYmFyKGFlcyh4PVNlc3NvLA0KICAgICAgICAgICAgICAgZmlsbD1TZXNzbywNCiAgICAgICAgICAgICAgIGNvbG9yPVNlc3NvKSwNCiAgICAgICAgICAgc3RhdD0iY291bnQiKSsNCiAgbGFicyh0aXRsZT0iU2V4IGRpc3RyaWJ1dGlvbiBvZiBuZXdib3JucyIsDQogICAgICAgeD0ic2V4IiwNCiAgICAgICB5PSJhYnNvbHV0ZSBmcmVxdWVuY3kiLA0KICAgICAgIGNvbG9yPSJTRVg6IiwNCiAgICAgICBmaWxsPSJTRVg6IikrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gc2V4X2NvbG9ycykrDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxNTAwLDEwMCkpKw0KICB0aGVtZV9jbGFzc2ljKCkrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTUsIGhqdXN0ID0gMSksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTApKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHIgPSAxMCkpKQ0KYGBgDQoNClNlY29uZCB3ZSBzdHVkeSB0aGUgc3RhdGlzdGljcyBvZiB0aGUgYW50aHJvcG9tZXRyaWMgdmFyaWFibGVzIGFjcm9zcyB0aGUgdHdvIHNleGVzIGFuZCBkaXNwbGF5IHRoZW0gdmlhIGEgYm94cGxvdC4gSW4gb3JkZXIgdG8gdGVzdCBsYXRlciBkaWZmZXJlbmNlcyBhY3Jvc3MgdGhlIHNleGVzIHVzaW5nIGEgdC50ZXN0IGl0IGlzIGltcG9ydGFudCB0byBjb21wYXJlIG5vcm1hbGx5IGRpc3RydWJ1dGVkIHF1YW50aXRpZXMuIEZvciB0aGlzIHJlYXNvbiwgd2UgcmVzdHJpY3Qgb3VyIHN0dWR5IG9ubHkgdG8gdGhlIG5vdC1wcmVtYXR1cmUgZGVsaXZlcmllcy4NCg0KDQpgYGB7cn0NCmN2X2Z1bmN0IDwtIGZ1bmN0aW9uKHgpIHsNCiAgcmV0dXJuKHNkKHgpIC8gbWVhbih4KSAqIDEwMCkNCn0NCg0KDQpjb25kaXRpb25hbF9kYXRhc2V0X3NleCA8LSByZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YSAlPiUgDQogIGdyb3VwX2J5KFNlc3NvKSAlPiUgDQogIHN1bW1hcmlzZShtZWFuX3Blc28gPSByb3VuZChtZWFuKFBlc28pLDIpLA0KICAgICAgICAgICAgc2RfcGVzbyA9IHJvdW5kKHNkKFBlc28pLDIpLA0KICAgICAgICAgICAgY3ZfcGVzbyA9IHJvdW5kKGN2X2Z1bmN0KFBlc28pLCAyKSwNCiAgICAgICAgICAgIHNrZXdfcGVzbyA9IHJvdW5kKHNrZXduZXNzKFBlc28pLCAyKSwNCiAgICAgICAgICAgIGt1cnRfcGVzbyA9IHJvdW5kKGt1cnRvc2lzX2luZGV4KFBlc28pLCAyKSwNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgbWVhbl9sdW5naGV6emEgPSByb3VuZChtZWFuKEx1bmdoZXp6YSksMiksDQogICAgICAgICAgICBzZF9sdW5naGV6emEgPSByb3VuZChzZChMdW5naGV6emEpLDIpLA0KICAgICAgICAgICAgY3ZfbHVuZ2hlenphID0gcm91bmQoY3ZfZnVuY3QoTHVuZ2hlenphKSwgMiksDQogICAgICAgICAgICBza2V3X2x1bmdoZXp6YSA9IHJvdW5kKHNrZXduZXNzKEx1bmdoZXp6YSksIDIpLA0KICAgICAgICAgICAga3VydF9sdW5naGV6emEgPSByb3VuZChrdXJ0b3Npc19pbmRleChMdW5naGV6emEpLCAyKSwNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgbWVhbl9jcmFuaW8gPSByb3VuZChtZWFuKENyYW5pbyksMiksDQogICAgICAgICAgICBzZF9jcmFuaW8gPSByb3VuZChzZChDcmFuaW8pLDIpLA0KICAgICAgICAgICAgY3ZfY3JhbmlvID0gcm91bmQoY3ZfZnVuY3QoQ3JhbmlvKSwgMiksDQogICAgICAgICAgICBza2V3X2NyYW5pbyA9IHJvdW5kKHNrZXduZXNzKENyYW5pbyksIDIpLA0KICAgICAgICAgICAga3VydF9jcmFuaW8gPSByb3VuZChrdXJ0b3Npc19pbmRleChDcmFuaW8pLCAyKSkNCg0KDQpjb2xuYW1lcyhjb25kaXRpb25hbF9kYXRhc2V0X3NleCkgPC0gYygic2V4IiwgIm1lYW4iLCAic2QiLCAiY3YiLCAiU2tldyIsICJrdXJ0IiAsICJtZWFuIiwgInNkIiwgImN2IiAsICJTa2V3IiwgImt1cnQiLCAgIm1lYW4iLCAic2QiLCAiY3YiLCAiU2tldyIsICJrdXJ0IikNCg0Ka2FibGUoY29uZGl0aW9uYWxfZGF0YXNldF9zZXgsIGNhcHRpb249IkluZGljZXMgb2Ygd2VpZ2h0LCBsZW5ndGggYW5kIGNyYW5pYWwgZGlhbWV0ZXIgb2Ygbm9uLXByZW1hdHVyZSBuZXdib3JucywgZGl2aWRlZCBieSBzZXgiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJjb25kZW5zZWQiLCBmdWxsX3dpZHRoID0gVFJVRSkgJT4lDQogIGFkZF9oZWFkZXJfYWJvdmUoYygiICI9MSwgIldlaWdodCIgPSA1LCAiTGVuZ3RoIiA9IDUsICJDcmFuaWFsIGNpcmN1bWZlcmVuY2UiID0gNSkpICU+JQ0KICByb3dfc3BlYygxLCBiYWNrZ3JvdW5kID0gInBpbmsiKSU+JQ0KICByb3dfc3BlYygyLCBiYWNrZ3JvdW5kID0gImxpZ2h0Ymx1ZSIpICU+JQ0KICBjb2x1bW5fc3BlYyhjKDEsNiwxMSksIGJvcmRlcl9yaWdodCA9IFRSVUUpDQpgYGANCg0KDQoNCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9Nn0NCg0KYm94X2xlbmd0aF9zZXggPC0gZ2dwbG90KGRhdGE9cmVndWxhcl9kZWxpdmVyaWVzX2RhdGEsDQogICAgICAgICAgICAgICAgICAgICBhZXMoeD1TZXNzbywNCiAgICAgICAgICAgICAgICAgICAgICAgIHk9THVuZ2hlenphLA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsbD1TZXNzbyksDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1TZXNzbykrDQogICAgICAgICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoKSsNCiAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGU9Ikxlbmd0aCBkaXRyaWJ1dGlvbiBhY2NvcmRpbmcgdG8gc2V4XG4gb2Ygbm9uIHByZW1hdHVyZSBuZXdib3JucyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHg9IiAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5PSJsZW5ndGggKGNtKSIpKw0KICAgICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBzZXhfY29sb3JzKSsNCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSsNCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGFuZWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE2LCBoanVzdD0wLjUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrDQogICAgICAgICAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgzMTAsIDU2MCwgYnkgPSAyNSkpKw0KICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIk0iPSJNYWxlIiwgIkYiPSJGZW1hbGUiKSkNCg0KDQpib3hfd2VpZ2h0X3NleCA8LSBnZ3Bsb3QoZGF0YT1yZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YSwNCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4PVNlc3NvLA0KICAgICAgICAgICAgICAgICAgICAgICAgeT1QZXNvLA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsbD1TZXNzbyksDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1TZXNzbykrDQogICAgICAgICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoKSsNCiAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGU9IldlaWdodCBkaXRyaWJ1dGlvbiBhY2NvcmRpbmcgdG8gc2V4XG4gb2Ygbm9uIHByZW1hdHVyZSBuZXdib3JucyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHg9IiAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5PSJ3ZWlnaHQgKEtnKSIpKw0KICAgICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBzZXhfY29sb3JzKSsNCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSsNCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGFuZWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE2LCBoanVzdD0wLjUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrDQogICAgICAgICAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxMDAwLCA1MDAwLCBieSA9IDQwMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDEuMCwgNS4wLCBieSA9IDAuNCkpKw0KICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIk0iPSJNYWxlIiwgIkYiPSJGZW1hbGUiKSkNCg0KDQpib3hfaGVhZF9zZXggPC0gZ2dwbG90KGRhdGE9cmVndWxhcl9kZWxpdmVyaWVzX2RhdGEsDQogICAgICAgICAgICAgICAgICAgICBhZXMoeD1TZXNzbywNCiAgICAgICAgICAgICAgICAgICAgICAgIHk9Q3JhbmlvLA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsbD1TZXNzbyksDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1TZXNzbykrDQogICAgICAgICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoKSsNCiAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGU9IkNyYW5pYWwgZGlhbWV0ZXIgZGl0cmlidXRpb24gYWNjb3JkaW5nIHRvIHNleFxuIG9mIG5vbiBwcmVtYXR1cmUgbmV3Ym9ybnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB4PSIgIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT0iZGlhbWV0ZXIgKGNtKSIpKw0KICAgICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjKCJNIj0iZG9kZ2VyYmx1ZSIsICJGIj0iaG90cGluayIpKSsNCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSsNCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGFuZWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE2LCBoanVzdD0wLjUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrDQogICAgICAgICAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyNTAsIDQwMCwgYnkgPSAyNSkpKw0KICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIk0iPSJNYWxlIiwgIkYiPSJGZW1hbGUiKSkNCg0KDQpjb21iX2ZpZ19hbnRyb3BvbWV0cmljcyA8LSBib3hfaGVhZF9zZXggKyBib3hfd2VpZ2h0X3NleCArIGJveF9sZW5ndGhfc2V4ICsgcGxvdF9sYXlvdXQobmNvbD0zLCBoZWlnaHRzID0gYyg1KSwgd2lkdGhzPSBjKDUsNSw1KSkNCnByaW50KGNvbWJfZmlnX2FudHJvcG9tZXRyaWNzKQ0KYGBgDQpUaGUgZGF0YSBzdWdnZXN0IGEgZGlmZmVyZW5jZSBpbiB0aGUgYW50aHJvcG9tZXRyaWMgdmFyaWFibGVzIGFjcm9zcyB0aGUgdHdvIHNleGVzLCB3aXRoIGhpZ2hlciB2YWx1ZXMgZm9yIGFsbCB0aGUgdmFyaWFibGVzIGluIGNhc2Ugb2YgbWFsZXMgcmF0aGVyIHRoYW4gZmVtYWxlcy4gDQoNCiMjIyBXZSB0ZXN0IHRoZSBoeXBvdGhlc2lzIHRoYXQgdGhlIGFudHJvcG9tZXRyaWMgdmFsdWVzIG9mIG1hbGVzIGFuZCBmZW1hbGVzIGFyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudA0KDQpJbiBvcmRlciB0byBwZXJmb3JtIGEgbWVhbmluZ2Z1bGwgdC10ZXN0IHRoYXQgY29tcGFyZXMgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgYW50aHJvcG9tZXRyaWMgbWVhc3VyZW1lbnRzIG9mIG1hbGVzIGFuZCBmZW1hbGVzIHdlIGZpcnN0IGhhdmUgdG8gY2hlY2sgdGhhdCB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgYW50cmhvcG9tZXRyaWMgbWVhc3VyZW1lbnRzIG9mIG1hbGVzIGFuZCBmZW1hbGVzIGFyZSBhcHByb3hpbWF0ZWxseSBub3JtYWwgYW5kIGhhdmUgc2ltaWxhciB2YXJpYW5jZXMuIA0KVGhlIHByZXZpb3VzIHRhYmxlIHN1Z2dlc3QgdGhhdCB0aGlzIHNob3VsZCBiZSB0cnVlIGlmIHdlIHJlc3RyaWN0IG91ciBzdHVkeSBvbmx5IHRvIHRoZSBub24tcHJlbWF0dXJlIGRlbGl2ZXJpZXMuIA0KV2UgcGVyZm9ybSBRLVEgdGVzdHMgYW5kIFNoYXBpcm8gV2lsayB0ZXN0cyB0byB2ZXJpZnkgdGhhdCB0aGUgdGhyZWUgdmFyaWFibGVzIGRpc3RyaWJ1dGUgYWNjb3JkaW5nIHRvIG5vcm1hbCBkaXN0cmlidXRpb25zIGZvciBib3RoIHNleGVzLiBXZSByZWNhbGwgdGhlIFEtUSBwbG90cyBkaXNwbGF5IHRoZSBvYnNlcnZlZCBxdWFudGlsZXMgb2YgdGhlIHZhcmlhYmxlcyBhZ2FpbnN0IHRoZSBxdWFudGlsZXMgb2YgYSBHYXVzc2lhbiBkaXN0cmlidXRpb24uIFNvLCBpZiB0aGUgdmFyaWFibGVzIGNvbWUgZnJvbSBhIG5vcm1hbCBkaXN0cmlidXRpb24sIHRoZSBwb2ludHMgaW4gdGhlIFEtUSBwbG90IHdpbGwgYXBwcm94aW1hdGVseSBsaWUgYWxvbmcgYSBzdHJhaWdodCBsaW5lLg0KDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTV9DQoNCm1hbGVzIDwtIHJlZ3VsYXJfZGVsaXZlcmllc19kYXRhICU+JQ0KICBmaWx0ZXIoU2Vzc289PSJNIikNCg0KZmVtYWxlcyA8LSByZWd1bGFyX2RlbGl2ZXJpZXNfZGF0YSAlPiUNCiAgZmlsdGVyKFNlc3NvPT0iRiIgJiBMdW5naGV6emE+NDAwKQ0KDQoNCiMjIFFRLXBsb3RzIG9mIHRoZSBsZW5ndGgNClFRX2xlbmd0aF9tYWxlcyA9IGdncGxvdChtYWxlcywgYWVzKHNhbXBsZSA9IEx1bmdoZXp6YSkpICsNCiAgbGFicyh0aXRsZT0iUS1RIFBsb3Qgb2YgdGhlIGxlbmd0aFxuIG9mIG1hbGUgbmV3Ym9ybnMiLA0KICAgICAgICAgICAgeD0iVGhlb3JldGljYWwgUXVhbnRpbGVzIiwNCiAgICAgICAgICAgIHk9Ik9ic2VydmVkIFF1YW50aWxlcyIpKw0KICBzdGF0X3FxKGNvbG9yID0gImRvZGdlcmJsdWUiKSArDQogIHN0YXRfcXFfbGluZShjb2xvcj0icmVkIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KUVFfbGVuZ3RoX2ZlbWFsZXMgPSBnZ3Bsb3QoZmVtYWxlcywgYWVzKHNhbXBsZSA9IEx1bmdoZXp6YSkpICsNCiAgbGFicyh0aXRsZT0iUS1RIFBsb3Qgb2YgdGhlIGxlbmd0aFxuIG9mIGZlbWFsZSBuZXdib3JucyIsDQogICAgICAgICAgICB4PSJUaGVvcmV0aWNhbCBRdWFudGlsZXMiLA0KICAgICAgICAgICAgeT0iT2JzZXJ2ZWQgUXVhbnRpbGVzIikrDQogIHN0YXRfcXEoY29sb3IgPSAiaG90cGluayIpICsNCiAgc3RhdF9xcV9saW5lKGNvbG9yPSJibGFjayIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCiMjIFFRX3Bsb3RzIG9mIHRoZSB3ZWlnaHQNClFRX3dlaWdodF9tYWxlcyA9IGdncGxvdChtYWxlcywgYWVzKHNhbXBsZSA9IFBlc28pKSArDQogIGxhYnModGl0bGU9IlEtUSBQbG90IG9mIHRoZSB3ZWlnaHRcbiBvZiBtYWxlIG5ld2Jvcm5zIiwNCiAgICAgICAgICAgIHg9IlRoZW9yZXRpY2FsIFF1YW50aWxlcyIsDQogICAgICAgICAgICB5PSJPYnNlcnZlZCBRdWFudGlsZXMiKSsNCiAgc3RhdF9xcShjb2xvciA9ICJkb2RnZXJibHVlIikgKw0KICBzdGF0X3FxX2xpbmUoY29sb3I9InJlZCIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNClFRX3dlaWdodF9mZW1hbGVzID0gZ2dwbG90KGZlbWFsZXMsIGFlcyhzYW1wbGUgPSBQZXNvKSkgKw0KICBsYWJzKHRpdGxlPSJRLVEgUGxvdCBvZiB0aGUgd2VpZ2h0XG4gb2YgZmVtYWxlIG5ld2Jvcm5zIiwNCiAgICAgICAgICAgIHg9IlRoZW9yZXRpY2FsIFF1YW50aWxlcyIsDQogICAgICAgICAgICB5PSJPYnNlcnZlZCBRdWFudGlsZXMiKSsNCiAgc3RhdF9xcShjb2xvciA9ICJob3RwaW5rIikgKw0KICBzdGF0X3FxX2xpbmUoY29sb3I9ImJsYWNrIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KUVFfY3JhbmlhbF9tYWxlcyA9IGdncGxvdChtYWxlcywgYWVzKHNhbXBsZSA9IENyYW5pbykpICsNCiAgbGFicyh0aXRsZT0iUS1RIFBsb3Qgb2YgdGhlIGNyYW5pYWwgY2lyY3VtZmVyZW5jZVxuIG9mIG1hbGUgbmV3Ym9ybnMiLA0KICAgICAgICAgICAgeD0iVGhlb3JldGljYWwgUXVhbnRpbGVzIiwNCiAgICAgICAgICAgIHk9Ik9ic2VydmVkIFF1YW50aWxlcyIpKw0KICBzdGF0X3FxKGNvbG9yID0gImRvZGdlcmJsdWUiKSArDQogIHN0YXRfcXFfbGluZShjb2xvcj0icmVkIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KUVFfY3JhbmlhbF9mZW1hbGVzID0gZ2dwbG90KGZlbWFsZXMsIGFlcyhzYW1wbGUgPSBDcmFuaW8pKSArDQogIGxhYnModGl0bGU9IlEtUSBQbG90IG9mIHRoZSBjcmFuaWFsIGNpcmN1bWZlcmVuY2VcbiBvZiBmZW1hbGUgbmV3Ym9ybnMiLA0KICAgICAgICAgICAgeD0iVGhlb3JldGljYWwgUXVhbnRpbGVzIiwNCiAgICAgICAgICAgIHk9Ik9ic2VydmVkIFF1YW50aWxlcyIpKw0KICBzdGF0X3FxKGNvbG9yID0gImhvdHBpbmsiKSArDQogIHN0YXRfcXFfbGluZShjb2xvcj0iYmxhY2siKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQpjb21iX1FRIDwtIFFRX2xlbmd0aF9tYWxlcyArIFFRX2xlbmd0aF9mZW1hbGVzICsNCiAgICAgICAgICAgICAgICAgIFFRX3dlaWdodF9tYWxlcyArIFFRX3dlaWdodF9mZW1hbGVzICsNCiAgICAgICAgICAgICAgICAgIFFRX2NyYW5pYWxfbWFsZXMgKyBRUV9jcmFuaWFsX2ZlbWFsZXMgKw0KICAgICAgICAgICAgICAgICAgcGxvdF9sYXlvdXQobmNvbD0yLCBoZWlnaHRzID0gYyg1LDUsNSksIHdpZHRocz0gYyg1LDUpKQ0KDQpwcmludChjb21iX1FRKQ0KDQoNCnNoYXB0ZXN0TE0gPSBzaGFwaXJvLnRlc3QobWFsZXMkTHVuZ2hlenphKQ0Kc2hhcHRlc3RMRiA9IHNoYXBpcm8udGVzdChmZW1hbGVzJEx1bmdoZXp6YSkNCnNoYXB0ZXN0V00gPSBzaGFwaXJvLnRlc3QobWFsZXMkUGVzbykNCnNoYXB0ZXN0V0YgPSBzaGFwaXJvLnRlc3QoZmVtYWxlcyRQZXNvKQ0Kc2hhcHRlc3RDTSA9IHNoYXBpcm8udGVzdChtYWxlcyRDcmFuaW8pDQpzaGFwdGVzdENGID0gc2hhcGlyby50ZXN0KGZlbWFsZXMkQ3JhbmlvKQ0KDQpjYXQoIlRoZSBtYXhpbXVtIFNoYXBpcm8tV2lsayBzdGF0aXN0aWNzIG9mIHRoZSA2IG5vcm1hbGl0eSB0ZXN0cyBhYm91dCBkaXN0cmlidXRpb24gb2Ygd2VpZ2h0LCBsZW5ndGggYW5kIGNyYW5pYWwgY2lyY3VtZmVyZW5jZSBhY3Jvc3MgdGhlIHR3byBzZXhlcyBpczoiLCBtaW4oc2hhcHRlc3RMTSRzdGF0aXN0aWMsIHNoYXB0ZXN0TEYkc3RhdGlzdGljLCBzaGFwdGVzdFdNJHN0YXRpc3RpYywgc2hhcHRlc3RXRiRzdGF0aXN0aWMsIHNoYXB0ZXN0Q00kc3RhdGlzdGljLCBzaGFwdGVzdENGJHN0YXRpc3RpYyksICJcbiIpDQoNCmNhdCgiVGhlIG1pbmltdW0gU2hhcGlyby1XaWxrIHAudmFsdWUgb2YgdGhlIDYgbm9ybWFsaXR5IHRlc3RzIGFib3V0IGRpc3RyaWJ1dGlvbiBvZiB3ZWlnaHQsIGxlbmd0aCBhbmQgY3JhbmlhbCBjaXJjdW1mZXJlbmNlIGFjcm9zcyB0aGUgdHdvIHNleGVzIGlzOiIsIG1pbihzaGFwdGVzdExNJHAudmFsdWUsIHNoYXB0ZXN0TEYkcC52YWx1ZSwgc2hhcHRlc3RXTSRwLnZhbHVlLCBzaGFwdGVzdFdGJHAudmFsdWUsIHNoYXB0ZXN0Q00kcC52YWx1ZSwgc2hhcHRlc3RDRiRwLnZhbHVlKSkNCmBgYA0KDQpGcm9tIHRoZSBRLVEgcGxvdHMgYW5kIHRoZSBTaGFwaXJvLVdpbGsgdGVzdHMgd2UgY2FuIGFyZ3VlIHRoYXQgdGhlIGFudGhyb3BvbWV0cmljIHZhcmlhYmxlcywgZXZlbiBpZiBub3QgZXhhY3RseSBkaXN0cmlidXRlZCBhY2NvcmRpbmcgdG8gbm9ybWFsIGRpc3RyaWJ1dGlvbnMsIGFyZSByZWFsbHkgY2xvc2UgdG8gbm9ybWFsIGRpc3RyaWJ1dGlvbnMuIFNvIHdlIGNhbiBwZXJmb3JtIGEgdC50ZXN0IHRvIHZlcmlmeSB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBmb2xsb3dlZCBieSBtYWxlcyBhbmQgZmVtYWxlcyBpcyB0aGUgc2FtZS4NCg0KYGBge3J9DQp0dGVzdF9sZW5ndGggPSB0LnRlc3QobWFsZXMkTHVuZ2hlenphLCBmZW1hbGVzJEx1bmdoZXp6YSwgIA0KICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCANCiAgICAgICAgICAgICAgICAgbXUgPSAwLCANCiAgICAgICAgICAgICAgICAgdmFyLmVxdWFsID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgY29uZi5sZXZlbCA9IDAuOTUsDQogICAgICAgICAgICAgICAgIHBhaXJlZCA9IEZBTFNFKSANCg0KdHRlc3Rfd2VpZ2h0ID0gdC50ZXN0KG1hbGVzJFBlc28sIGZlbWFsZXMkUGVzbywgIA0KICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCANCiAgICAgICAgICAgICAgICAgbXUgPSAwLCANCiAgICAgICAgICAgICAgICAgdmFyLmVxdWFsID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgY29uZi5sZXZlbCA9IDAuOTUsDQogICAgICAgICAgICAgICAgIHBhaXJlZCA9IEZBTFNFKSANCg0KdHRlc3RfY3Jhbml1bSA9IHQudGVzdChtYWxlcyRDcmFuaW8sIGZlbWFsZXMkQ3JhbmlvLCAgDQogICAgICAgICAgICAgICAgIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIsIA0KICAgICAgICAgICAgICAgICBtdSA9IDAsIA0KICAgICAgICAgICAgICAgICB2YXIuZXF1YWwgPSBUUlVFLA0KICAgICAgICAgICAgICAgICBjb25mLmxldmVsID0gMC45NSwNCiAgICAgICAgICAgICAgICAgcGFpcmVkID0gRkFMU0UpIA0KDQpjYXQoIlRoZSBwLXZhbHVlcyBvZiB0aGUgdC10ZXN0cyBhYm91dCBsZW5ndGgsIHdlaWdodCBhbmQgY3JhbmlhbCBjaXJjdW1mZXJlbmNlIGRpc3RyaWJ1dGlvbiBjb21wYXJpc29uIGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXMgYXJlOiBcbiIsIA0KICAgICItcF92YWx1ZShXZWlnaHQpID0gIiwgdHRlc3Rfd2VpZ2h0JHAudmFsdWUgLCAiXG4iLA0KICAgICItcF92YWx1ZShMZW5ndGgpID0gIiwgdHRlc3RfbGVuZ3RoJHAudmFsdWUgLCAiXG4iLA0KICAgICItcF92YWx1ZShDcmFuaWFsIGRpYW1ldGVyKSA9ICIsIHR0ZXN0X2NyYW5pdW0kcC52YWx1ZSApDQoNCmBgYA0KVGhlIHZlcnkgc21hbGwgcC12YWx1ZXMgb2YgdGhlIHRocmVlIHQudGVzdHMgc2hvdyB0aGF0IHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgc3RhdGlzdGljYWwgZGlmZmVyZW5jZSBpbiB0aGUgbWVhbiBvZiB0aGUgYW50aHJvcG9tZXRyaWMgdmFyaWFibGVzIGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXMuIEluIHBhcnRpY3VsYXIgd2UgY2FuIHJlZnVzZSB0aGUgbnVsbCBoeXBvdGhlc2lzIEgwIGFuZCBhc3NlcnQgdGhhdCB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgYW50aHJvcG9tZXRyaWMgbWVhc3VyZW1lbnRzIGZvbGxvd2VkIGJ5IG1hbGVzIGFuZCBmZW1hbGVzIGFyZSBkaWZmZXJlbnQuDQoNCg0KDQojIyBBbmFseXNpcyBvZiBjZXNhcmVhbiBkZWxpdmVyaWVzDQoNCk5vdyB3ZSBhbmFseXplIHRoZSBudW1iZXIgb2YgY2VzYXJlYW4gZGVsaXZlcmllcyBhY3Jvc3MgdGhlIGRpZmZlcmVudCBob3NwaXRhbHMuDQpGaXJzdCB3ZSBzdHVkeSB0aGUgdGhlIGFic29sdXRlIGFuZCByZWxhdGl2ZSBmcmVxdWVuY3kgb2YgZWFjaCBob3NwaXRhbC4gDQoNCmBgYHtyfQ0KI2NyZWF0ZSBhIGNvbmRpdGlvbmFsIGRhdGFzZXQgd2l0aCB0aGUgbnVtYmVyIG9mIGRlbGl2ZXJpZXMgYW5kIGNlc2FyZWFuIGRlbGl2ZXJpZXMgcGVyIGhvc3BpdGFsDQpjb25kaXRpb25hbF9kYXRhc2V0X29zcGVkYWxlIDwtIA0KICBkYXRhc2V0ICU+JSANCiAgZ3JvdXBfYnkoT3NwZWRhbGUpICU+JSAgDQogIHN1bW1hcmlzZShjZXNhcmVvID0gc3VtKFRpcG8ucGFydG8gPT0gIkNlcyIsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBuYXR1cmFsZSA9IHN1bShUaXBvLnBhcnRvID09ICJOYXQiLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgcGFydGk9IHN1bSgpKQ0KYGBgDQoNCmBgYHtyfQ0KRnJlcV9hc3NfaG9zcCA9IHRhYmxlKGRhdGFzZXRbIk9zcGVkYWxlIl0pDQpGcmVxX3JlbF9ob3NwID0gdGFibGUoZGF0YXNldFsiT3NwZWRhbGUiXSkvTl9vYnNlcnZhdGlvbnMNCkZyZXFfaG9zcCA9IGNiaW5kKEZyZXFfYXNzX2hvc3AsRnJlcV9yZWxfaG9zcCkNCnJvd25hbWVzKEZyZXFfaG9zcCkgPC0gYygiSG9zcGl0YWwxIiwiSG9zcGl0YWwyIiwiSG9zcGl0YWwzIikNCmNvbG5hbWVzKEZyZXFfaG9zcCkgPC0gYygiQWJzb2x1dGUgZnJlcXVlbmN5IiwiUmVsYXRpdmUgZnJlcXVlbmN5IikNCmthYmxlKHQoRnJlcV9ob3NwKSwgY2FwdGlvbiA9ICdEZWxpdmVyaWVzIGRpc3RyaWJ1dGlvbiBhY3Jvc3MgaG9zcGl0YWxzJykgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKQ0KYGBgDQpXZSBoYXZlIG9ic2VydmVkIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGVsaXZlcmllcyBhY3Jvc3MgdGhlIHRocmVlIGhvc3BpdGFscyBpcyBlc3NlbnRpYWxseSB1bmlmb3JtLg0KDQpOZXh0IHdlIHVzZSBhIGJveHBsb3QgdG8gZGlzcGxheSB0aGUgcGVyY2VudGFnZSBvZiBjZXNhcmVhbiBkZWxpdmVyaWVzIGluIGVhY2ggaG9zcGl0YWwuDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0NCg0KaG9zcGl0YWxzPWMoIm9zcDEiID0gIkhvc3BpdGFsMSIsICJvc3AyIj0iSG9zcGl0YWwyIiwgIm9zcDMiPSJIb3NwaXRhbDMiKQ0KDQpkYXRhc2V0JFRpcG8ucGFydG8gPC0gZmFjdG9yKGRhdGFzZXQkVGlwby5wYXJ0bywgbGV2ZWxzID0gYygiTmF0IiwgIkNlcyIpKQ0KDQpiYXJfY2VzYXJlYW5faG9zcGl0YWwgPSAgZ2dwbG90KGRhdGE9ZGF0YXNldCkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fYmFyKGFlcyh4PU9zcGVkYWxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbD1UaXBvLnBhcnRvKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb249ImZpbGwiKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZT0iUGVyY2VudGFnZSBvZiBjZXNhcmVhbiBjaGlsZGJpcnRocyBieSBob3NwaXRhbHMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9IiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT0iUGVyY2VudGFnZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbD0idHlwZSBvZiBkZWxpdmVyeToiKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjKCJDZXMiPSJyZWQiLCAiTmF0Ij0iaXZvcnkyIiksIGxhYmVscyA9IGMoIkNlcyI9ICJDZXNhcmVhbiIsICJOYXQiPSJOYXR1cmFsIikpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGFuZWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTQsIGhqdXN0PTAuNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMSwgYnkgPSAwLjEpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWhvc3BpdGFscykNCg0KDQpwcmludChiYXJfY2VzYXJlYW5faG9zcGl0YWwpDQpgYGANClRoZSBib3hwbG90IHNob3cgdGhhdCBpbiBhbGwgdGhlIHRocmVlIGhvc3BpdGFscyB0aGUgcGVyY2VudGFnZSBvZiBjZXNhcmVhbiBkZWxpdmVyaWVzIGlzIGFwcHJveGltYXRlbHkgb2YgMzAlLiAgSW4gcGFydGljdWxhciwgdGhlIG51bWJlciBvZiBjZXNhcmVhbiBkZWxpdmVyaWVzIHNlZW1zIHRvIGJlIG1hcmdpbmFsbHkgbG93ZXIgaW4gdGhlIEhvc3BpdGFsMyB3aXRoIHJlc3BlY3QgdG8gSG9zcGl0YWwxIGFuZCBIb3NwaXRhbDIuDQoNCg0KIyMjIE5leHQgd2UgdGVzdCB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBjZXNhcmVhbiBkZWxpdmVyaWVzIGlzIHRoZSBzYW1lIGFuZCBzbyB1bmlmb3JtIGFjcm9zcyB0aGUgdGhyZWUgaG9zcGl0YWxzDQoNCldlIGZpcnN0IHVzZSBhIFBlYXJzb27igJlzIENoaS1zcXVhcmVkIHRlc3QgdG8gZXhhbWluZSB0aGUgaHlwb3RoZXNpcyB0aGF0DQp0aGUgcHJvcG9ydGlvbiBvZiBjZXNhcmVhbiBkZWxpdmVyaWVzIGlzIGVxdWFsIGFjcm9zcyB0aGUgaG9zcGl0YWxzLiBJdA0KY29tcGFyZXMgdGhlIG9ic2VydmVkIGZyZXF1ZW5jaWVzIG9mIGNlc2FyZWFuIGFuZCBuYXR1cmFsIGRlbGl2ZXJpZXMgaW4NCmVhY2ggaG9zcGl0YWwgd2l0aCB0aGUgZXhwZWN0ZWQgZnJlcXVlbmNpZXMgY2FsY3VsYXRlZCB1bmRlciB0aGUgbnVsbA0KaHlwb3RoZXNpcyBvZiB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBvZiBjZXNhcmVhbiBkZWxpdmVyaWVzIGFjcm9zcw0KaG9zcGl0YWxzLCBsaXRlcmFsbHk6DQokJEV4cGVjdGVkXF9GcmVxXF9DZXMoSG9zcCkgPSBQcm9iKENlc2FyZWFuKSogTnVtYmVyXF9EZWxpdmVyaWVzKEhvc3ApICQkDQp3aGVyZSAkUHJvYihDZXNhcmVhbik9TlxfdG90KENlc2FyZWFuKS9OXF90b3QoZGVsaXZlcmllcykkLiBUaGUgdGVzdA0KYXNzZXNzZXMgd2hldGhlciB0aGUgb2JzZXJ2ZWQgZGlmZmVyZW5jZXMgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQNCmJ5IHByb3ZpZGluZyBhIGNoaS1zcXVhcmVkIHN0YXRpc3RpYyBhbmQgYSBwLXZhbHVlIHRvIHN1cHBvcnQgb3IgcmVqZWN0DQp0aGUgbnVsbCBoeXBvdGhlc2lzLg0KDQpgYGB7cn0NCiMgY3JlYXRlIGNvbnRpbmdlbmN5IHRhYmxlIGJld3R3ZWVuIGhvc3BpdGFscyBhbmQga2luZCBvZiBkZWxpdmVyeQ0KdGFibGVfZGVsaXZlcnlfaG9zcGl0YWwgPSB0YWJsZShPc3BlZGFsZSwgVGlwby5wYXJ0bykNCg0KI1RoZSBQZWFyc29u4oCZcyBDaGktc3F1YXJlZCB0ZXN0IGlzIHBlcmZvcm1lZCANCmNoaXNxX3Rlc3QgPSBjaGlzcS50ZXN0KHRhYmxlX2RlbGl2ZXJ5X2hvc3BpdGFsKQ0KY2F0KCJUaGUgcC12YWx1ZSBvZiB0aGUgUGVhcnNvbidzIENoaS1zcXVhcmVkIHRlc3QgaXMiICwgY2hpc3FfdGVzdCRwLnZhbHVlKQ0KYGBgDQoNCjwhLS0gIyBkYXRhc2V0JFRpcG8ucGFydG8ubnVtID0gaWZlbHNlKFRpcG8ucGFydG89PSJOYXQiLDEsMCkgLS0+DQo8IS0tICMgIC0tPg0KPCEtLSAjICAtLT4NCjwhLS0gIyBwYWlyd2lzZS50LnRlc3QoZGF0YXNldCRUaXBvLnBhcnRvLm51bSwgT3NwZWRhbGUsIC0tPg0KPCEtLSAjICAgICAgICAgICAgICAgICBwYWlyZWQgPSBGLCAtLT4NCjwhLS0gIyAgICAgICAgICAgICAgICAgcG9vbC5zZCA9IFQsIC0tPg0KPCEtLSAjICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSAibm9uZSIpIC0tPg0KDQpCYXNlZCBvbiB0aGUgcC12YWx1ZSBvZiB0aGUgUGVhcnNvbidzIENoaS1zcXVhcmVkIHdlIGNhbiBub3QgcmVqZWN0IHRoZSBudWxsLWh5cG90aGVzaXMuDQoNClRoZSB0ZXN0IENoaS1zcXVhcmVkIHRoYXQgd2UgaGF2ZSBwZXJmb3JtZWQgaXMgYmFzZWQgb24gdGhlIGFzc3VtcHRpb24NCnRoYXQgZm9yIHN1ZmZpY2llbnRseSBtYW55IG9ic2VydmF0aW9ucyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZQ0KZnJlcXVlbmNpZXMgb2YgY2VzYXJlYW4gZGVsaXZlcmllcyBhdCBlYWNoIGhvc3BpdGFsIGlzIGNsb3NlIHRvIGEgbm9ybWFsDQpkaXN0cmlidXRpb24sIGJlY2F1c2Ugb2YgdGhlIGNlbnRyYWwgbGltaXQgdGhlb3JlbS4gSG93ZXZlciwgaW4gdGhpcw0KY2FzZSwgd2Uga25vdyB0aGF0IHRoZSBudW1iZXIgb2YgY2VzYXJlYW4gZGVsaXZlcmllcyBhdCB0aGUgJGkkLXRoDQpob3NwaXRhbCBmb2xsb3dzIGEgYmlub21pYWwgZGlzdHJpYnV0aW9uICRCKHBfaSkkLiBTbyB3ZSBjYW4gYWxzbw0KcGVyZm9ybSBhIGJpbm9taWFsIHRlc3QgZm9yIGVhY2ggaG9zcGl0YWwgdG8gZXhhbWluZSB0aGUgaHlwb3RoZXNpcyB0aGF0DQokcF9pPVByb2IoQ2VzYXJlYW4pJCBmb3IgZWFjaCBob3NwaXRhbC4gJFByb2IoQ2VzYXJlYW4pJCBhcyBkZWZpbmVkDQphYm92ZSBpcyBhc3N1bWVkIGFzIGFuIGFjY3VyYXRlIGFwcHJveGltYXRpb24gb2YgcHJvYmFiaWxpdHkgb2YgY2VzYXJlYW4gZGVsaXZlcnkgaWYgdGhlIGRpc3RyaWJ1dGlvbiBpcyB1bmlmb3JtIGFjcm9zcyB0aGUgaG9zcGl0YWxzLCBpbiBwYXJ0aWN1bGFyIHNpbmNlIHRoZSBkaXN0cmlidXRpb24gb2YgZGVsaXZlcmllcyBwZXIgaG9zcGl0YWwgaXMgcXVpdGUgdW5pZm9ybSB0aGVyZSBpcyBubyBuZWVkIHRvIHVzZSBhIHdlaWdodGVkIGZvcm11bGEgZm9yIHRoZSBwcm9iYWJpbGl0eSAkUHJvYihDZXNhcmVhbikkLiBXZSByZXBvcnQgdGhlIHRoZSAkcCQtdmFsdWUgYW5kIHRoZSBjb25maWRlbmNlIGludGVydmFsIG9mIHRoaXMgdGVzdCBmb3IgZWFjaCBob3NwaXRhbC4NCg0KYGBge3J9DQojIGZpcnN0IHdlIGNyZWF0ZSBhIHRhYmxlIHdpdGggdGhlIHRvdGFsIG51bWJlciBvZiBkZWxpdmVyaWVzIGFuZCBjZXNhcmVhbiBkZWxpdmVyaWVzIG9ic2VydmVkIGF0IGVhY2ggaG9zcGl0YWwuDQoNCnN1Yl9kYXRhc2V0ID0gc3Vic2V0KGRhdGFzZXQsIE9zcGVkYWxlPT0ib3NwMSIpDQpOX2Nlc19ob3NwID0gc3VtKHN1Yl9kYXRhc2V0JFRpcG8ucGFydG89PSJDZXMiKQ0KTl9kZWxpdmVyaWVzX2hvc3AgPSBucm93KHN1Yl9kYXRhc2V0KQ0KDQpGcmVxX2Nlc19ob3NwID0gdGFibGUoT3NwZWRhbGVbVGlwby5wYXJ0bz09IkNlcyJdKQ0KQ2VzX2hvc3AgPSBjYmluZChGcmVxX2Fzc19ob3NwLEZyZXFfY2VzX2hvc3ApDQpDZXNfaG9zcCA9IGFzLmRhdGEuZnJhbWUoQ2VzX2hvc3ApDQoNCnJvd25hbWVzKENlc19ob3NwKSA8LSBjKCJIb3NwaXRhbF8xIiwgIkhvc3BpdGFsXzIiLCAiSG9zcGl0YWxfMyIpDQoNCiMgTmV4dCB3ZSBjb21wdXRlIFByb2IoY2VzYXJlYW4pIHRoYXQgc2hvdWxkIGJlIGEgZ29vZCBhcHByb3hpbWF0aW9uIG9mIHRoZSBwcm9iYWJpbGl0eSBvZiBvYmVydmluZyBhIGNlc2FyZWFuIGRlbGl2ZXJ5IGFzc3VtaW5nIHRoaXMgaXMgdW5pZm9ybSBhY3Jvc3MgdGhlIHRocmVlIGhvc3BpdGFscy4NCg0KcHJvYl9jZXNhcmVhbiA9IHN1bShUaXBvLnBhcnRvPT0iQ2VzIikvTl9vYnNlcnZhdGlvbnMNCg0KIyBMYXN0IHdlIHBlcmZvcm0gYSBiaW5vbWlhbCB0ZXN0IGZvciBlYWNoIGhvc3BpdGFsDQpwX3ZhbHVlcyA8LSBudW1lcmljKG5yb3coQ2VzX2hvc3ApKQ0KY29uZl9pbnQgPC0gbnVtZXJpYyhucm93KENlc19ob3NwKSkNCg0KZm9yKGkgaW4gc2VxX2xlbihucm93KENlc19ob3NwKSkpew0KICB0ZXN0IDwtIGJpbm9tLnRlc3QoQ2VzX2hvc3AkRnJlcV9jZXNfaG9zcFtpXSwgQ2VzX2hvc3AkRnJlcV9hc3NfaG9zcFtpXSwgcCA9IHByb2JfY2VzYXJlYW4sIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpDQogIHBfdmFsdWVzW2ldIDwtIHRlc3QkcC52YWx1ZQ0KICBjb25mX2ludFtpXSA8LSBwYXN0ZTAoIigiLCByb3VuZCh0ZXN0JGNvbmYuaW50WzFdLDIpLCAiLCIsIHJvdW5kKHRlc3QkY29uZi5pbnRbMl0sMiksIikiKSAgDQp9DQoNCkNlc19ob3NwJHBfdmFsdWUgPC0gcF92YWx1ZXMNCkNlc19ob3NwJGNvbmZfaW50IDwtIGNvbmZfaW50DQoNCmthYmxlKHQoQ2VzX2hvc3BbLCBjKCJwX3ZhbHVlIiwgImNvbmZfaW50IildKSwgY2FwdGlvbiA9ICdQLXZhbHVlcyBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIHRoZSBiaW5vbWlhbCBvdXRjb21lcyBvZiBlYWNoIGhvc3BpdGFsLDFuIGNhbGN1bGF0ZWQgdW5kZXIgdGhlIGFzc3VtcHRpb24gb2YgYSBiaW5vbWlhbCBkaXN0cmlidXRpb24gd2l0aCBhIHVuaWZvcm0gcHJvYmFiaWxpdHlcbiBvZiBjZXNhcmVhbiBkZWxpdmVyaWVzIGFjcm9zcyBhbGwgaG9zcGl0YWxzLicpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLCBwb3NpdGlvbj0ibGVmdCIpDQpgYGANCkFsc28gaW4gdGhpcyBjYXNlIHRoZSBwLXZhbHVlIG9mIHRoZSBiaW5vbWlhbCB0ZXN0cyBkbyBub3QgYWxsb3cgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgYXNzZXJ0aW5nIHRoYXQgdGhlIG51bWJlciBvZiBkZWxpdmVyaWVzIGFjcm9zcyB0aGUgdGhyZWUgaG9zcGl0YWxzIGlzIHVuaWZvcm0uDQoNCg0KIyMgTmV4dCB3ZSBhbmFseXplIHRoZSBmcmVxdWVuY3kgb2Ygc21va2luZyBtb3RoZXJzLg0KDQoNCmBgYHtyfQ0KRnJlcV9yZWxfc21va2VyID0gc3VtKGRhdGFzZXQkRnVtYXRyaWNpID09IDEpL05fb2JzZXJ2YXRpb25zDQoNCmNhdCgiVGhlIHBlcmNlbnRhZ2Ugb2Ygc21va2luZyBtb3RoZXJzIGlzOiIsIHBhc3RlMChGcmVxX3JlbF9zbW9rZXIsIiUiKSkNCmBgYA0KTW9yZW92ZXIgd2UgaW52ZXN0aWdhdGUgaWYgdGhlIHNtb2tlIGluZmx1ZW5jZSBzb21lIG9mIHRoZSBvdGhlciB2YXJpYWJsZXMsIGluY2x1ZGluZyB3ZWlnaHQsIGxlbmd0aCBhbmQgQ3JhbmlhbCBjaXJjdW1mZXJlbmNlIGFuZCBnZXN0YXRpb25hbCBhZ2UuDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9DQoNCmJveHBsb3Rfc21va2luZ18xPSBnZ3Bsb3QoZGF0YT1kYXRhc2V0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9RnVtYXRyaWNpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9UGVzbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsPUZ1bWF0cmljaSkpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KCkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJXZWlnaHQgZGlzdHJpYnV0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD0iICIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9IndlaWdodCAoa2cpIikrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGMoIjAiPSJncmVlbiIsICIxIj0iZ3JleSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiPSAiTm9uLXNtb2tlciIsICIxIj0iU21va2VyIikpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwYW5lbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTYsIGhqdXN0PTAuNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzZXEoMSw1LDAuNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxMDAwLCA1MDAwLCBieSA9IDUwMCkpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygiTm9uLXNtb2tlciIsICJTbW9rZXIiKSkNCg0KDQpib3hwbG90X3Ntb2tpbmdfMiA9IGdncGxvdChkYXRhPWRhdGFzZXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1GdW1hdHJpY2ksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1MdW5naGV6emEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsPUZ1bWF0cmljaSkpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KCkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJMZW5ndGggZGlzdHJpYnV0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD0iICIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ikxlbmd0aCAoY20pIikrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGMoIjAiPSJncmVlbiIsICIxIj0iZ3JleSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiPSAiTm9uLXNtb2tlciIsICIxIj0iU21va2VyIikpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwYW5lbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTYsIGhqdXN0PTAuNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMzAwLDYwMCw1MCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDMwLCA2MCwgNSkpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygiTm9uLXNtb2tlciIsICJTbW9rZXIiKSkNCg0KDQpib3hwbG90X3Ntb2tpbmdfMyA9IGdncGxvdChkYXRhPWRhdGFzZXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1GdW1hdHJpY2ksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DcmFuaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsPUZ1bWF0cmljaSkpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KCkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJDcmFuaWFsIGNpcmN1bWZlcmVuY2UgZGlzdHJpYnV0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD0iICIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9IkNyYW5pYWwgY2lyY3VtZmVyZW5jZSAoY20pIikrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGMoIjAiPSJncmVlbiIsICIxIj0iZ3JleSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiPSAiTm9uLXNtb2tlciIsICIxIj0iU21va2VyIikpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwYW5lbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTYsIGhqdXN0PTAuNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzZXEoMjUsNDAsNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgyNTAsIDQwMCwgYnkgPSA1MCkpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygiTm9uLXNtb2tlciIsICJTbW9rZXIiKSkNCg0KDQoNCmJveHBsb3Rfc21va2luZ180ID0gZ2dwbG90KGRhdGE9ZGF0YXNldCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PUZ1bWF0cmljaSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUdlc3RhemlvbmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsPUZ1bWF0cmljaSkpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KCkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJHZXN0YXRpb25hbCB0aW1lIGRpc3RyaWJ1dGlvbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9IiAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSJHZXN0YXRpb25hbCB0aW1lIikrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGMoIjAiPSJncmVlbiIsICIxIj0iZ3JleSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiPSAiTm9uLXNtb2tlciIsICIxIj0iU21va2VyIikpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwYW5lbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTYsIGhqdXN0PTAuNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMjYsIDQyLCBieSA9IDIpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIk5vbi1zbW9rZXIiLCAiU21va2VyIikpDQoNCmNvbWJfc21va2UgPC0gYm94cGxvdF9zbW9raW5nXzEgKyBib3hwbG90X3Ntb2tpbmdfMiArIGJveHBsb3Rfc21va2luZ18zICsgYm94cGxvdF9zbW9raW5nXzQgKyAgICBwbG90X2xheW91dChuY29sPTIsIGhlaWdodHMgPSBjKDUsNSksIHdpZHRocz0gYyg1LDUpKQ0KDQpwcmludChjb21iX3Ntb2tlKQ0KDQpgYGANClRoZSBib3hwbG90IG1heSBzdWdnZXN0IGEgZGlmZmVyZW5jZSBpbiB0aGUgbWVhc3VyZW1lbnRzIGFuZCBnZXN0YXRpb25hbCB0aW1lIGJldHdlZW4gc21va2luZyBhbmQgbm9uIHNtb2tpbmcgbW90aGVycy4gV2UgdGVzdCB0aGlzIGh5cG90aGVzaXMgdXNpbmcgYSB0LnRlc3QuDQoNCg0KYGBge3J9DQpTbW9rZXJzX2RhdGEgPC0gZGF0YXNldCAlPiUNCiAgZmlsdGVyKEZ1bWF0cmljaT09IjEiKQ0KDQpOb3Rfc21va2Vyc19kYXRhIDwtIGRhdGFzZXQgJT4lDQogIGZpbHRlcihGdW1hdHJpY2k9PSIwIikNCg0KdHRlc3Rfc21va2Vfd2VpZ2h0ID0gdC50ZXN0KFNtb2tlcnNfZGF0YSRQZXNvLCBOb3Rfc21va2Vyc19kYXRhJFBlc28sICANCiAgICAgICAgICAgICAgICAgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIiwgDQogICAgICAgICAgICAgICAgIG11ID0gMCwgDQogICAgICAgICAgICAgICAgIHZhci5lcXVhbCA9IFRSVUUsDQogICAgICAgICAgICAgICAgIGNvbmYubGV2ZWwgPSAwLjk1LA0KICAgICAgICAgICAgICAgICBwYWlyZWQgPSBGQUxTRSkgDQoNCnR0ZXN0X3Ntb2tlX2xlbmd0aCA9IHQudGVzdChTbW9rZXJzX2RhdGEkTHVuZ2hlenphLCBOb3Rfc21va2Vyc19kYXRhJEx1bmdoZXp6YSwgIA0KICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCANCiAgICAgICAgICAgICAgICAgbXUgPSAwLCANCiAgICAgICAgICAgICAgICAgdmFyLmVxdWFsID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgY29uZi5sZXZlbCA9IDAuOTUsDQogICAgICAgICAgICAgICAgIHBhaXJlZCA9IEZBTFNFKSANCg0KDQp0dGVzdF9zbW9rZV9jcmFuaXVtID0gdC50ZXN0KFNtb2tlcnNfZGF0YSRDcmFuaW8sIE5vdF9zbW9rZXJzX2RhdGEkQ3JhbmlvLCAgDQogICAgICAgICAgICAgICAgIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIsIA0KICAgICAgICAgICAgICAgICBtdSA9IDAsIA0KICAgICAgICAgICAgICAgICB2YXIuZXF1YWwgPSBUUlVFLA0KICAgICAgICAgICAgICAgICBjb25mLmxldmVsID0gMC45NSwNCiAgICAgICAgICAgICAgICAgcGFpcmVkID0gRkFMU0UpIA0KDQp0dGVzdF9zbW9rZV9nZXN0YXRpb24gPSB0LnRlc3QoU21va2Vyc19kYXRhJEdlc3RhemlvbmUsIE5vdF9zbW9rZXJzX2RhdGEkR2VzdGF6aW9uZSwgIA0KICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCANCiAgICAgICAgICAgICAgICAgbXUgPSAwLCANCiAgICAgICAgICAgICAgICAgdmFyLmVxdWFsID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgY29uZi5sZXZlbCA9IDAuOTUsDQogICAgICAgICAgICAgICAgIHBhaXJlZCA9IEZBTFNFKSANCg0KY2F0KCJUaGUgcC12YWx1ZXMgb2YgdGhlIHQtdGVzdHMgYWJvdXQgbGVuZ3RoLCB3ZWlnaHQsIGNyYW5pYWwgY2lyY3VtZmVyZW5jZSBhbmQgZ2VzdGF0aW9uIHRpbWUgZGlzdHJpYnV0aW9uIGNvbXBhcmlzb24gYmV0d2VlbiBzbW9raW5nIGFuZCBub24tc21va2luZyBtb3RoZXJzIGFyZTogXG4iLCANCiAgICAiLXBfdmFsdWUoV2VpZ2h0KSA9ICIsIHR0ZXN0X3Ntb2tlX3dlaWdodCRwLnZhbHVlICwgIlxuIiwNCiAgICAiLXBfdmFsdWUoTGVuZ3RoKSA9ICIsIHR0ZXN0X3Ntb2tlX2xlbmd0aCRwLnZhbHVlICwgIlxuIiwNCiAgICAiLXBfdmFsdWUoQ3JhbmlhbCBkaWFtZXRlcikgPSAiLCB0dGVzdF9zbW9rZV9jcmFuaXVtJHAudmFsdWUsICJcbiIsDQogICAgIi1wX3ZhbHVlKENyYW5pYWwgZGlhbWV0ZXIpID0gIiwgdHRlc3Rfc21va2VfZ2VzdGF0aW9uJHAudmFsdWUpDQpgYGANClRoZSB0LnRlc3RzIGRvIG5vdCBhbGxvdyB1cyB0byByZWplY3QgdGhlIGh5cG90aGVzaXMgdGhhdCB0aGUgZ2VzdGF0aW9uYWwgdGltZSBhbmQgYW50cm9wb21ldHJpYyBtZWFzdXJtZW50cyBvZiBuZXdib3JucyBhcmUgc3RhdGlzdGljYWxseSBkaWZmZXJlbnQgYWNjb3JkaW5nIHRvIHNtb2tpbmcgYW5kIG5vdC1zbW9raW5nIG1vdGhlcnMuDQoNCg0KIyMgTmV4dCB3ZSBhbmFseXplIHRoZSBudW1iZXIgb2YgZGVsaXZlcmllcyBhbmQgcmVsYXRpb24gd2l0aCB0aGUgYWdlIG9mIHRoZSBtb3RoZXJzLg0KDQpGaXJzdCB3ZSBleHBsb3JlIHRoZSB2YXJpYWJsZSBudW1iZXIgb2YgZGVsaXZlcmllcy4NCg0KYGBge3J9DQpGcmVxX2Fic19OLmRlbGl2ZXJpZXMgPSB0YWJsZShkYXRhc2V0WyJOLmdyYXZpZGFuemUiXSkgDQpGcmVxX3JlbF9OLmRlbGl2ZXJpZXMgPSB0YWJsZShkYXRhc2V0WyJOLmdyYXZpZGFuemUiXSkvTl9vYnNlcnZhdGlvbnMNCg0KRnJlcV9OLmRlbGl2ZXJpZXM9ZGF0YS5mcmFtZShOLmdyYXZpZGFuemUgPSBuYW1lcyhGcmVxX2Fic19OLmRlbGl2ZXJpZXMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGcmVxX2FicyA9IGFzLm51bWVyaWMoRnJlcV9hYnNfTi5kZWxpdmVyaWVzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRnJlcV9yZWwgPSBwYXN0ZShyb3VuZChGcmVxX3JlbF9OLmRlbGl2ZXJpZXMsMiksIiUiKSkNCg0KRnJlcV9OLmRlbGl2ZXJpZXMkTi5ncmF2aWRhbnplIDwtIGZhY3RvcihGcmVxX04uZGVsaXZlcmllcyROLmdyYXZpZGFuemUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1hcy5jaGFyYWN0ZXIoc29ydChhcy5udW1lcmljKHVuaXF1ZShGcmVxX04uZGVsaXZlcmllcyROLmdyYXZpZGFuemUpKSkpKQ0KDQoNCmdncGxvdChkYXRhPUZyZXFfTi5kZWxpdmVyaWVzKSsNCiAgZ2VvbV9iYXIoYWVzKHg9Ti5ncmF2aWRhbnplLCB5PUZyZXFfYWJzKSwNCiAgICAgICAgICAgc3RhdD0iaWRlbnRpdHkiLA0KICAgICAgICAgICBjb2w9ImFxdWFtYXJpbmUiLA0KICAgICAgICAgICBmaWxsPSJhcXVhbWFyaW5lIikrDQogIGxhYnModGl0bGU9Ik51bWJlciBvZiBwcmV2aW91cyBwcmVnbmFuY2llcyIsDQogICAgICAgeD0iIiwNCiAgICAgICB5PSJhYnNvbHV0ZSBmcmVxdWVuY3kiKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEyMDAsMjAwKSkrDQogIGdlb21fdGV4dChhZXMoeD1OLmdyYXZpZGFuemUsIHk9RnJlcV9hYnMrNTAsIGxhYmVsID0gRnJlcV9yZWwpKSsNCiAgdGhlbWVfY2xhc3NpYygpKw0KICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbihyID0gMTApKSkNCmBgYA0KDQpXZSBvYnNlcnZlIHRoYXQgbW9zdCBvZiBkZWxpdmVyaWVzIGNvcnJlc3BvbmQgdG8gZmlyc3QgZGVsaXZlcmllcyBhbmQgdGhhdCBsZXNzIHRoYW4gMTAlIG9mIHRoZSBtb3RoZXJzIGhhdmUgNCBjaGlsZHJlbiBvciBtb3JlLg0KDQoNCk5leHQgd2UgaW52ZXN0aWdhdGUgaWYgdGhlcmUgaXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBudW1iZXIgb2YgY2hpbGRyZW4gYW5kIHRoZSBhZ2Ugb2YgdGhlIG1vdGhlci4gVG8gdGhpcyBlbmQgd2Ugc3BsaXQgdGhlIGRhdGFzZXQgaW4gY2xhc3NlcyBhY2NvcmRpbmcgdG8gdGhlIE51bWJlciBvZiBkZWxpdmVyaWVzIGFuZCB5ZWFycyBvZiB0aGUgbW90aGVyIGFuZCB3ZSBkaXNwbGF5IHRoZSBkc3RyaWJ1dGlvbiBhY2NvcmRpbmcgdG8gdGhlIGNyb3NzIGNsYXNzZXMuDQoNCmBgYHtyfQ0KZGF0YXNldCROLmdyYXZpZGFuemVfQ0wgPC0gY3V0KGRhdGFzZXQkTi5ncmF2aWRhbnplLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKDAsMSwyLDMsMTAwKSwgDQogICAgICAgICAgICAgICAgICAgICByaWdodD1GQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiMCIsICIxIiwiMiIsIjMrIikpDQoNCg0KZGF0YXNldCRBbm5pLm1hZHJlX0NMIDwtIGN1dChkYXRhc2V0JEFubmkubWFkcmUsIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzPWMoMTEsMjAsMjYsMzIsMzgsNDYpKQ0KDQpkYXRhc2V0JE4uZ3JhdmlkYW56ZV9DTCA8LSBjdXQoZGF0YXNldCROLmdyYXZpZGFuemUsIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzPWMoMCwxLDIsMywxMDApLCANCiAgICAgICAgICAgICAgICAgICAgIHJpZ2h0PUZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCIwIiwiMSIsIjIiLCIzKyIpKQ0KDQpjb250X3RhYmxlX3llYXJfTi5kZWxpdmVyeSA9IHRhYmxlKGRhdGFzZXQkQW5uaS5tYWRyZV9DTCwgZGF0YXNldCROLmdyYXZpZGFuemVfQ0wpDQoNCmdncHVicjo6Z2diYWxsb29ucGxvdChkYXRhPWFzLmRhdGEuZnJhbWUoY29udF90YWJsZV95ZWFyX04uZGVsaXZlcnkpLA0KICAgICAgICAgICAgICAgICAgICAgIGZpbGw9ImtoYWtpIikNCmBgYA0KDQo8IS0tICMgIC0tPg0KPCEtLSAjICAtLT4NCjwhLS0gIyBmcmVxX2Fzc19hZ2UgPC0gdGFibGUoZGF0YXNldCRBbm5pLm1hZHJlX0NMKSAtLT4NCjwhLS0gIyAgLS0+DQo8IS0tICMgY291bnQgPC0gc3VtKChkYXRhc2V0JEFubmkubWFkcmUgPiAxMCkgJiAoZGF0YXNldCRBbm5pLm1hZHJlIDw9IDQ2KSkgLS0+DQo8IS0tICMgIC0tPg0KPCEtLSAjIGZyZXFfcmVsX2FnZSA8LSByb3VuZChmcmVxX2Fzc19hZ2UvY291bnQsMykgLS0+DQo8IS0tICMgIC0tPg0KPCEtLSAjIGZyZXFfYWdlPWFzLmRhdGEuZnJhbWUoY2JpbmQoZnJlcV9hc3NfYWdlLCBmcmVxX3JlbF9hZ2UpKSAtLT4NCjwhLS0gIyAgLS0+DQo8IS0tICMga2FibGUoZnJlcV9hZ2UsIGNhcHRpb249IkRpc3RyaWJ1dGlvbiBvZiB0aGUgZGVsaXZlcmllcyBmb3IgY2xhc3NlcyBvZiBhZ2UiKSAlPiUgLS0+DQo8IS0tICMgICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLCBwb3NpdGlvbj0iY2VudGVyIikgLS0+DQoNCg0KPCEtLSBnZ3Bsb3QoZGF0YSA9IHN1YnNldChkYXRhc2V0LCAhaXMubmEoQW5uaS5tYWRyZV9DTCkpKSsgLS0+DQo8IS0tICAgZ2VvbV9iYXIoYWVzKHg9QW5uaS5tYWRyZV9DTCksIC0tPg0KPCEtLSAgICAgICAgICAgIHN0YXQ9ImNvdW50IiwgLS0+DQo8IS0tICAgICAgICAgICAgY29sPSJraGFraSIsIC0tPg0KPCEtLSAgICAgICAgICAgIGZpbGw9ImtoYWtpIikrIC0tPg0KPCEtLSAgIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiB0aGUgbW90aGVyIGFnZSIsIC0tPg0KPCEtLSAgICAgICAgeD0iQWdlIiwgLS0+DQo8IS0tICAgICAgICB5PSJhYnNvbHV0ZSBmcmVxdWVuY3kiKSsgLS0+DQo8IS0tICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEyMDAsMjAwKSkrIC0tPg0KPCEtLSAgIHRoZW1lX2NsYXNzaWMoKSsgLS0+DQo8IS0tICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxMCkpLCAtLT4NCjwhLS0gICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4ociA9IDEwKSkpIC0tPg0KDQoNCkFzIGV4cGVjdGVkIHdlIG9ic2VydmUgdGhhdCBhbiBpbmNyZWFzaW5nIG51bWJlciBvZiBjaGlsZHJlbiB1c3VhbGx5IGNvcnJlc3BvbmQgdG8gb2xkZXIgbW90aGVycy4gV2UgdGVzdCB0aGUgaHlwb3RoZXNpcyB0aGUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBudW1iZXIgb2YgY2hpbGRlciBpcyBub3QgdW5pZm9ybSBhY3Jvc3MgdGhlIGFnZXMgdmlhIGEgUGVhcnNvbiBjaGktc3F1YXJlZCB0ZXN0Lg0KDQpgYGB7cn0NCmNoaXNxX3Rlc3QgPSBjaGlzcS50ZXN0KGNvbnRfdGFibGVfeWVhcl9OLmRlbGl2ZXJ5KQ0KY2F0KCJUaGUgcC12YWx1ZSBvZiB0aGUgUGVhcnNvbidzIENoaS1zcXVhcmVkIHRlc3QgaXMiICwgY2hpc3FfdGVzdCRwLnZhbHVlKSANCmBgYA0KDQpUaGUgUGVhcnNvbidzIENoaSBzcXVhcmVkIHRlc3QgY29uZmlybXMgdGhlIGh5cG90aGVzaXMgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIG51bWJlciBvZiBkZWxpdmVyaWVzIHBlciBhZ2UgaXMgbm90IHVuaWZvcm0uIA0KDQojIyBDcmVhdGlvbiBvZiBhIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIHRoZSB3ZWlnaHQgb2YgdGhlIG5ld2Jvcm4uDQpXZSBzdGFydCBzdHVkeWluZyB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gdGhlIGRpZmZlcmVudCB2YXJpYWJsZXMgYW5kIHRoZSB2YXJpYWJsZSB3ZWlnaHQuIEZpcnN0IHdlIGRpc3BsYXkgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgcXVhbnRpdGF0aXZlIHZhcmlhYmxlIGFuZCB0aGUgdmFyaWFibGUgd2VpZ2h0Lg0KDQpgYGB7cn0NCiMgcGFuZWwuY29yIDwtIGZ1bmN0aW9uKHgsIHksIGRpZ2l0cyA9IDIsIHByZWZpeCA9ICIiLCBjZXguY29yLCAuLi4pDQojIHsNCiMgICAjdXNyIDwtIHBhcigidXNyIik7IG9uLmV4aXQocGFyKHVzcikpDQojICAgI3Bhcih1c3IgPSBjKDAsIDEsIDAsIDEpKQ0KIyAgIHIgPC0gKGNvcih4LCB5KSkNCiMgICB0eHQgPC0gZm9ybWF0KGMociwgMSksIGRpZ2l0cyA9IGRpZ2l0cylbMV0NCiMgICB0eHQgPC0gcGFzdGUwKHByZWZpeCwgdHh0KQ0KIyAgIGlmKG1pc3NpbmcoY2V4LmNvcikpIGNleC5jb3IgPC0gMC44L3N0cndpZHRoKHR4dCkNCiMgICB0ZXh0KDAuNSwgMC41LCB0eHQsIGNleCA9IDEuNSkNCiMgfQ0KDQpwYW5lbC5jb3IgPC0gZnVuY3Rpb24oeCwgeSwgZGlnaXRzID0gMiwgcHJlZml4ID0gIiIsIGNleC5jb3IsIC4uLikNCnsNCiAgciA8LSBjb3IoeCwgeSwgdXNlID0gImNvbXBsZXRlLm9icyIpDQogIHR4dCA8LSBmb3JtYXQoYyhyLCAxKSwgZGlnaXRzID0gZGlnaXRzKVsxXQ0KICB0eHQgPC0gcGFzdGUwKHByZWZpeCwgdHh0KQ0KICANCiAgdXNyIDwtIHBhcigidXNyIikgIyBsZWdnaSBjb29yZGluYXRlIGNvcnJlbnRpDQogIHhfcG9zIDwtIG1lYW4odXNyWzE6Ml0pICAjIGNlbnRybyBhc3NlIHgNCiAgeV9wb3MgPC0gbWVhbih1c3JbMzo0XSkgICMgY2VudHJvIGFzc2UgeQ0KICANCiAgaWYobWlzc2luZyhjZXguY29yKSkgY2V4LmNvciA8LSAxMC9zdHJ3aWR0aCh0eHQpDQogIHRleHQoeF9wb3MsIHlfcG9zLCB0eHQsIGNleCA9IDEuNSwgLi4uKQ0KfQ0KDQoNCiNjb3JyZWxhemlvbmkNCnBhaXJzKGRhdGFzZXRbLCBjKCJBbm5pLm1hZHJlIiwiTi5ncmF2aWRhbnplIiwgIkdlc3RhemlvbmUiLCAiUGVzbyIsICJMdW5naGV6emEiLCAiQ3JhbmlvIildLCBsb3dlci5wYW5lbD1wYW5lbC5jb3IsIHVwcGVyLnBhbmVsPXBhbmVsLnNtb290aCkNCmBgYA0KDQpUaGUgY29ycmVsYXRpb24gbWF0cml4IHN1Z2dlc3QgYSBtZWRpdW0gdG8gaGlnaCBjb3JyZWxhdGlvbiBiZXR3ZWVuIFdlaWdodCBhbmQgTGVuZ3RoL0NyYW5pdW0gY2lyY3VtZmVyZW5jZSBhbmQgZ2VzdGF0aW9uIHRpbWUuIERpZmZlcmVudGx5LCB0aGUgd2VpZ2h0IHNlZW1zIG5vdCB0byBiZSBjb3JyZWxhdGVkIHRvIHRoZSBudW1iZXIgb2YgZGVsaXZlcmllcyBhbmQgYWdlIG9mIHRoZSBtb3RoZXIuIEFkZGl0aW9uYWxseSB3ZSBoYXZlIGFscmVhZHkgb2JzZXJ2ZWQgdGhhdCB0aGVyZSBpcyBub3QgYSBzaWduaWZpY2FudCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB3ZWlnaHQgb2YgdGhlIG5ld2Jvcm4gYW5kIHRoZSBmYWN0IHRoYXQgdGhlIG1vdGhlciBpcyBhIHNtb2tlci4gRGlmZmVyZW50bHkgd2UgaGF2ZSBvYnNlcnZlZCBhIHN0cm9uZyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBzZXggb2YgdGhlIG5ld2Jvcm4gYW5kIGl0cyB3ZWlnaHQuIA0KDQpUaGUgc2NhdHRlciBwbG90cyBhbHNvIHN1Z2dlc3QgYSBwb3NzaWJsZSBub25saW5lYXIgZGVwZW5kYW5jZSBvZiB0aGUgd2VpZ2h0IG9mIHRoZSBuZXdib3JucyB3aXRoIHJlc3BlY3QgdG8gZ2VzdGF0aW9uIHRpbWUgYW5kIHBvc3NpYmx5IExlbmd0aCBhbmQgY3Jhbml1bSBjaXJjdW1mZXJlbmNlLg0KDQpFdmVuIGlmIHRoaXMgaXMgbm90IG9ic2VydmFibGUgZnJvbSB0aGUgY29ycmVsYXRpb24gbWF0cml4LCB0aGUgbGl0ZXJhdHVyZSBzdWdnZXN0IHRoYXQgdGhlcmUgY291bGQgYmUgYSBkaWZmZXJlbmNlIGluIHRoZSB3ZWlnaHQgb2YgdGhlIG5ld2Jvcm5zIGJldHdlZW4gdGhlIGZpcnN0IGNoaWxkIGFuZCB0aGUgc3Vic2VxdWVudCBvbmVzIChzZWUgW0ludGVybmF0aW9uYWwgc3RhbmRhcmRzIGZvciBuZXdib3JuIHdlaWdodCwgbGVuZ3RoLCBhbmQgaGVhZCBjaXJjdW1mZXJlbmNlIGJ5IGdlc3RhdGlvbmFsIGFnZSBhbmQgc2V4XShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9TMDE0MC02NzM2KDE0KTYwOTMyLTYpKSwgZm9yIHRoaXMgcmVhc29uIHdlIHNwbGl0IHRoZSBkYXRhc2V0IGFjY29yZGluZyB0byB0aGUgTnVtYmVyIG9mIGRlbGl2ZXJ5IGNsYXNzZXMgIjAiIGFuZCAiMSsiIGFuZCB1c2UgdGhpcyBhcyBhIHF1YWxpdGF0aXZlIHZhcmlhYmxlIGluIHRoZSBpbnZlc3RpZ2F0aW9uIG9mIGEgZ29vZCByZWdyZXNzaW9uIG1vZGVsIGZvIHRoZSB3ZWlnaHQgb2YgdGhlIG5ld2Jvcm5zLg0KDQpgYGB7cn0NCmRhdGFzZXQkTi5ncmF2aWRhbnplX0NMIDwtIGN1dChkYXRhc2V0JE4uZ3JhdmlkYW56ZSwgDQogICAgICAgICAgICAgICAgICAgICBicmVha3M9YygwLDEsMTAwKSwgDQogICAgICAgICAgICAgICAgICAgICByaWdodD1GQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiMCIsIjErIikpDQpgYGANCg0KDQo8IS0tIGdncGxvdChkYXRhPWRhdGFzZXQsIC0tPg0KPCEtLSAgICAgICAgYWVzKHg9Ti5ncmF2aWRhbnplX0NMLCAtLT4NCjwhLS0gICAgICAgICAgICB5PVBlc28sIC0tPg0KPCEtLSAgICAgICAgICAgIGZpbGw9Ti5ncmF2aWRhbnplX0NMKSkrIC0tPg0KPCEtLSAgICAgICAgZ2VvbV9ib3hwbG90KGNvbG9yPSJibGFjayIpKyAtLT4NCjwhLS0gICAgICAgIGxhYnModGl0bGU9IldlaWdodCBkaXN0cmlidXRpb24gYWNjb3JkaW5nIHRvIE51bWJlciBvZiBkZWxpdmVyaWVzIiwgLS0+DQo8IS0tICAgICAgICAgICAgIHg9IiAiLCAtLT4NCjwhLS0gICAgICAgICAgICAgeT0id2VpZ2h0IChrZykiKSsgLS0+DQo8IS0tICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGMoIjAiPSJhcXVhbWFyaW5lIiwgIjErIj0iYXF1YW1hcmluZTMiKSkrIC0tPg0KPCEtLSAgICAgICAgdGhlbWVfY2xhc3NpYygpKyAtLT4NCjwhLS0gICAgICAgIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGFuZWwiLCAtLT4NCjwhLS0gICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiwgaGp1c3Q9MC41KSwgLS0+DQo8IS0tICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksIC0tPg0KPCEtLSAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLCAtLT4NCjwhLS0gICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLCAtLT4NCjwhLS0gICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCAtLT4NCjwhLS0gICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrIC0tPg0KPCEtLSAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNlcSgxLDUsMC41KSwgLS0+DQo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxMDAwLCA1MDAwLCBieSA9IDUwMCkpKyAtLT4NCjwhLS0gICAgICAgICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIjFzdCIsICIybmQiLCAiM3JkKyIpKSAtLT4NCg0KDQoNCjwhLS0gYGBge3J9IC0tPg0KPCEtLSBwYWlyd2lzZS50LnRlc3QoZGF0YXNldCRQZXNvLCBkYXRhc2V0JE4uZ3JhdmlkYW56ZV9DTCwgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiKSAgLS0+DQo8IS0tIGBgYCAtLT4NCg0KDQpXZSBpbnZlc3RpYWd0ZSB0aGUgYmVzdCBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB1c2luZyBhIHN0ZXB3aXNlIHNlbGVjdGlvbiBwcm9jZWR1cmUuIFdlIHN0YXJ0IGZyb20gdGhlIGZ1bGwgbW9kZWwgZnJvbSB3aGljaCB3ZSBvbWl0IHRoZSB2YXJpYWJsZXMgSG9zcGl0YWwgYW5kIEtpbmQgb2YgZGVsaXZlcnkgc2luY2UgdGhlcmUgaXMgbm8gcmVhc29uIHdoeSB0aGVzZSB2YXJpYWJsZXMgc2hvdWxkIGluZmx1ZW5jZSB0aGUgd2VpZ2h0IG9mIHRoZSBuZXdib3JuLiBUaGVuIHdlIHN1YnRyYWN0IG9yIGFkZCBiYWNrIHRoZSB2YXJpYWJsZXMgdGhhdCBzZWVtcyBsZXNzIGluZmx1ZW50aWFsLiBGaW5hbGx5IHdlIHNlbGVjdCB0aGUgYmVzdCBtb2RlbCBiYXNlZCBvbiB0aGUgQklDIG1ldHJpY3MuICANCg0KYGBge3J9DQptb2RfdG90PC1sbShQZXNvIH4gQW5uaS5tYWRyZSArIE4uZ3JhdmlkYW56ZV9DTCArIEZ1bWF0cmljaSArIEdlc3RhemlvbmUgKyBMdW5naGV6emEgKyBDcmFuaW8gKyBTZXNzbywgZGF0YT1kYXRhc2V0KQ0Kc3VtbWFyeShtb2RfdG90KQ0KYGBgDQpUaGUgdmFyaWFibGVzICJhZ2UiLCAiTi5kZWxpdmVyaWVzIiBhbmQgInNtb2tpbmciIHNlZWVtIHRvIGJlIHRoZSBsZXNzIHNpZ25pZmljYW50LiBTbyB3ZSBzdGFydCByZW1vdmluZyB0aGUgdmFyaWFibGUgImFnZSIgZnJvbSB0aGUgbW9kZWwuDQoNCmBgYHtyfQ0KbW9kMTwtbG0oUGVzbyB+ICBOLmdyYXZpZGFuemVfQ0wgKyBGdW1hdHJpY2kgKyBHZXN0YXppb25lICsgTHVuZ2hlenphICsgQ3JhbmlvICsgU2Vzc28sIGRhdGE9ZGF0YXNldCkNCnN1bW1hcnkobW9kMSkNCmBgYA0KY2F0KCJBZnRlciByZW1vdmluZyB0aGUgdmFyaWFibGUgXCJhZ2VcIiB0aGUgdmFyaWFibGVzIFwiTi5kZWxpdmVyaWVzXCIgYW5kIFwic21va2luZ1wiIGFyZSBzdGlsbCBub3Qgc2lnbmlmaWNhbnQuXG4iICkNCmNhdCgiU28gd2UgcmVtb3ZlIHRoZSB2YXJpYWJsZSBcInNtb2tpbmdcIiBmcm9tIHRoZSBtb2RlbC5cbiIgKQ0KDQoNCmBgYHtyfQ0KbW9kMjwtbG0oUGVzbyB+IE4uZ3JhdmlkYW56ZV9DTCArIEdlc3RhemlvbmUgKyBMdW5naGV6emEgKyBDcmFuaW8gKyBTZXNzbywgZGF0YT1kYXRhc2V0KQ0Kc3VtbWFyeShtb2QyKQ0KYGBgDQoNCg0KQWZ0ZXIgcmVtb3ZpbmcgdGhlIHZhcmlhYmxlIHNtb2tpbmcgdGhlIHZhcmlhYmxlcyBOLmRlbGl2ZXJpZXMgaXMgc3RpbGwgbGl0dGxlIHNpZ25pZmljYW50Lg0KU28gd2UgcmVtb3ZlIGFsc28gdGhpcyB2YXJpYWJsZSBmcm9tIHRoZSBtb2RlbC4NCg0KDQpgYGB7cn0NCm1vZDM8LWxtKFBlc28gfiBHZXN0YXppb25lICsgTHVuZ2hlenphICsgQ3JhbmlvICsgU2Vzc28sIGRhdGE9ZGF0YXNldCkNCnN1bW1hcnkobW9kMykNCmBgYA0KDQoNCkluIHRoZSBmaW5hbCBtb2RlbCBhbGwgdGhlIHJlbWFpbmluZyB2YXJpYWJsZXMgc2VlbSB2ZXJ5IHNpZ25pZmljYW50IHNvIHdlIGRvbid0IHJlbW92ZSBhbnkgZnVydGhlciB2YXJpYWJsZS4NCldlIGFsc28gbm90ZSB0aGF0IHRoZSBhZGp1c3RlZCBSLXNxdWFyZWQgaGFzIHJlbWFpbmVkIHVuY2hhbmdlZCBhZnRlciByZW1vdmluZyB0aGUgdmFyaWFibGVzICJhZ2UiIGFuZCAic21va2luZyIgd2hpbGUgaGFzIG9ubHkgc2xpZ2h0bHkgcmVkdWNlZCB3aGVuIHJlbW92aW5nIHRoZSB2YXJpYWJsZSAiTi5kZWxpdmVyaWVzIi4NCk5leHQgd2UgdGVzdCB0aGUgZGlmZmVyZW50IG1vZGVscyB0aGF0IHdlIGhhdmUgY29uc2lkZXJlZCBieSBsb29raW5nIGF0IHRoZSBhbmFseXNpcyBvZiB2YXJpYW5jZSBiZXR3ZWVuIGVhY2ggbW9kZWwgYW5kIHRoZSBzdWJzZXF1ZW50IG9uZSBhbmQgdGhlbiB3ZSBsb29rIGF0IHRoZSBCSUMgdmFsdWUgb2YgdGhlIGZvdXIgbW9kZWxzLg0KDQoNCmBgYHtyfQ0Ka2FibGUoYW5vdmEobW9kX3RvdCwgbW9kMSwgbW9kMiwgbW9kMyksIGNhcHRpb249IkFuYWx5c2lzIG9mIFZhcmlhbmNlIG9mIGVhY2ggbW9kZWwgd2l0aCByZXNwZWN0IHRvIHRoZSBwcmV2aW91cyBvbmUiKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KDQpUaGUgYW5hbHlzaXMgb2YgdmFyaWFuY2UgYmV0d2VlbiBlYWNoIG1vZGVsIGFuZCB0aGUgc3Vic2VxdWVudCBvbmUgc2hvd3MgdGhhdCBldmVyeSB0aW1lIHdlIGhhdmUgcmVtb3ZlZCBhIHZhcmlhYmxlIHRoZSByZXNpZHVhbCBzdW0gb2Ygc3F1YXJlcyBoYXMgcmVkdWNlZCwgaG93ZXZlciB0aGUgcmVkdWN0aW9uIGhhcyBiZWVuIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgb25seSBvbmNlIHRoYXQgd2UgaGF2ZSByZW1vdmVkIGFsbCB0aGUgdGhyZWUgdmFyaWFibGVzLg0KDQoNCmBgYHtyfQ0Ka2FibGUoQklDKG1vZF90b3QsIG1vZDEsIG1vZDIsIG1vZDMpLCBjYXB0aW9uPSJCYXllc2lhbiBJbmZvcm1hdGlvbiBDcml0ZXJpb24gKEJJQykgb2YgdGhlIGZvdXIgbW9kZWxzIGNvbnNpZGVyZWQiKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KDQpJbmNsdWRpbmcgb25seSBsaW5lYXIgdGVybXMgaW4gdGhlIHZhcmlhYmxlcyB3ZSBmaW5kIHRoYXQgdGhlIGJlc3QgbW9kZWwsIGFjY29yZGluZyB0byB0aGUgQklDIHZhbHVlcywgaXMgdGhlIG9uZSB0aGF0IHByZWRpY3RzIHRoZSB3ZWlnaHQgb2YgdGhlIG5ld2Jvcm4gYmFzZWQgb25seSBvbiB0aGUgdmFyaWFibGVzIExlbmd0aCwgQ3JhbmlhbCBjaXJjdW1mZXJlbmNlLCBzZXggYW5kIGdlc3RhdGlvbiB0aW1lLCBmb2xsb3dlZCBjbG9zZWx5IGJ5IHRoZSBtb2RlbCB0aGF0IGluY2x1ZGVkIGFsc28gdGhlIGRlcGVuZGVuY2UgdXBvbiB0aGUgbnVtYmVyIG9mIGRlbGl2ZXJpZXMuDQoNCk5leHQgd2Ugc3RhcnQgZnJvbSB0aGUgYmVzdCBtb2RlbCB0aGF0IHdlIGZvdW5kIGFuZCBjb25zaWRlciBpZiB0byBpbmNsdWRlIGFsc28gbm9ubGluZWFyIHRlcm1zIGluIHRoZSB2YXJpYWJsZXMuIA0KSW4gcGFydGljdWxhciB3ZSBub3RlIHRoYXQgdGhlIHRoZSB3ZWlndGggc2hvdWxkIGJlIHByb3BvcnRpb25hbCB0byB0aGUgdm9sdW1lIG9mIHRoZSBib2R5IGFuZCB0aGF0IHRoZSB2b2x1bWUgbGlrZWx5IGRlcGVuZHMgb24gY3ViaWMgdGVybXMgaW4gdGhlIHZhcmlhYmxlcyBsZW5ndGggYW5kIGNyYW5pYWwgY2lyY3VtZmVyZWNlLiBJbmRlZWQgaWYgd2UgdGhpbmsgYWJvdXQgdGhlIGJvZHkgYXMgYSBjeWxpbmRlciBvciBwYXJhbGxlbGVwaXBlZG9uIHdlIGNvdWxkIHdyaXRlIGl0cyB2b2x1bWUgaW4gdGVybXMgb2YgJGxlbmd0aFx0aW1lcyhjcmFuaWFsXF9jaXJjdW1mZXJlbmNlKV4yJCBvciAkbGVuZ3RoXjJcdGltZXMgY3JhbmlhbFxfY2lyY3VtZmVyZW5jZSQuIA0KDQpBZGRpdGlvbmFsbHkgdGhlIHNjYXR0ZXJwbG90cyBzdWdnZXN0IGEgcG9zc2libGUgbm9ubGluZWFyIGRlcGVuZGVuY2Ugb2YgdGhlIHdlaWdodCBvbiB0aGUgZ2VzdGF0aW9uYWwgYWdlLiBBcyBhIGZpcnN0IHN0ZXAgd2Ugc3R1ZHkgdGhlIGNvcnJlbGF0aW9uIG9mIHNvbWUgbm9ubGluZWFyIHRlcm1zIGJldHdlZW4gZWFjaCBvdGhlciBhbmQgd2l0aCB0aGUgdmFyaWFibGUgd2VpZ2h0LiANCg0KYGBge3J9DQpkYXRhc2V0JEdlc3RhemlvbmUyIDwtIChkYXRhc2V0JEdlc3RhemlvbmUpXjINCmRhdGFzZXQkbG9nR2VzdGF6aW9uZSA8LSBsb2coZGF0YXNldCRHZXN0YXppb25lKQ0KDQpwYWlycyhkYXRhc2V0WywgYygiUGVzbyIsICJHZXN0YXppb25lIiwgIkdlc3RhemlvbmUyIiwNCiAgICAgICAgICAgICAgICAibG9nR2VzdGF6aW9uZSIpXSwgbG93ZXIucGFuZWw9cGFuZWwuY29yLCB1cHBlci5wYW5lbD1wYW5lbC5zbW9vdGgpDQoNCmRhdGFzZXQkTHVuZ2hlenphMiA8LSAoZGF0YXNldCRMdW5naGV6emEpXjINCmRhdGFzZXQkTHVuZ2hlenphMnhDcmFuaW8gPC0gKGRhdGFzZXQkTHVuZ2hlenphKV4yKihkYXRhc2V0JENyYW5pbykNCmRhdGFzZXQkQ3JhbmlvMiA8LSAoZGF0YXNldCRDcmFuaW8pXjINCmRhdGFzZXQkTHVuZ2hlenpheENyYW5pbzIgPC0gZGF0YXNldCRMdW5naGV6emEqKGRhdGFzZXQkQ3JhbmlvKV4yDQoNCnBhaXJzKGRhdGFzZXRbLCBjKCJQZXNvIiwiTHVuZ2hlenphIiwgIkx1bmdoZXp6YTIiLCAiTHVuZ2hlenphMnhDcmFuaW8iLCANCiAgICAgICAgICAgICAgICAiQ3JhbmlvIiwgIkNyYW5pbzIiLCAiTHVuZ2hlenpheENyYW5pbzIiKV0sIGxvd2VyLnBhbmVsPXBhbmVsLmNvciwgdXBwZXIucGFuZWw9cGFuZWwuc21vb3RoKQ0KYGBgDQoNCkR1ZSB0byB0aGUgcmVhbHRpdmVseSBzbWFsbCByYW5nZSBpbnRlcnZhbHMgb2YgdGhlIHZhcmlhYmxlcyB3ZSBub3RlIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gYWxsIHRoZSB2YXJpYWJsZXMgR2VzdGF0aW9uIHRpbWUsIExlbmd0aCBhbmQgQ3JhbmlhbCBjaXJjdW1mZXJlbmNlIHdpdGggdGhlaXIgcXVhZHJhdGljIHZlcnNpb24sIGFzIGFsc28gYmV0d2VlbiBnZXN0YXRpb24gdGltZSBhbmQgaXRzIGxvZ2FyaXRobSwgaXMgMSB1cCB0byBhIHNlY29uZCBlcnJvciBhcHByb3hpbWF0aW9uLiBTbyBpdCBkb2Vzbid0IG1ha2Ugc2Vuc2UgdG8gaW5jbHVkZSB0aGVzZSB0ZXJtcyBpbiB0aGUgbW9kZWwgc2luY2Ugd2UgY2FuIG5vdCBleHBlY3QgdGhlbSB0byBwZXJmb3JtIHNpZ25pZmljYW50bHkgYmV0dGVyIHRoYW4gdGhlIGxpbmVhciB0ZXJtcy4NCg0KVGhlIHNpdHVhdGlvbiBpcyBzbGlnaHRseSBkaWZmZXJlbnQgZm9yIHRoZSBjdWJpYyB0ZXJtcyBtaXhlZCBpbiBsZW5ndGggYW5kIGNyYW5pYWwgY2lyY3VtZmVyZW5jZS4gSW5kZWVkLCBldmVuIGlmIHRoZXkgaGF2ZSBoaWdoIGNvcnJlbGF0aW9ucyB3aXRoIHRoZSB2YXJpYWJsZXMgbGVuZ3RoIGFuZCBjcmFuaWFsIGNpcmN1bWZlcmVuY2UgdGhleSBhbHNvIGhhdmUgaGlnaGVyIGNvcnJlbGF0aW9ucyB3aXRoIHRoZSB2YXJpYWJsZSB3ZWlnaHQgd2l0aCByZXNwZWN0IHRvIHRoZSBsaW5lYXIgdGVybXMuIFNvIHdlIHRyeSB0byBpbmNsdWRlIHRoZXNlIHRlcm1zIGluIHRoZSBtb2RlbC4NCg0KDQpgYGB7cn0NCnRvdF9ub25fbGluX21vZCA8LSBsbShQZXNvIH4gTi5ncmF2aWRhbnplX0NMICsgR2VzdGF6aW9uZSArIEx1bmdoZXp6YSArIENyYW5pbyArIEx1bmdoZXp6YTJ4Q3JhbmlvICsgTHVuZ2hlenpheENyYW5pbzIgKyBTZXNzbywgZGF0YT1kYXRhc2V0KQ0KDQpub25saW5fbW9kID0gTUFTUzo6c3RlcEFJQyh0b3Rfbm9uX2xpbl9tb2QsIGRpcmVjdGlvbj0iYm90aCIsIGs9bG9nKE5fb2JzZXJ2YXRpb25zKSkNCg0Kc3VtbWFyeShub25saW5fbW9kKQ0KDQprYWJsZShCSUMobW9kMywgbm9ubGluX21vZCksIGNhcHRpb249IkJheWVzaWFuIEluZm9ybWF0aW9uIENyaXRlcmlvbiAoQklDKSBvZiB0aGUgbGluZWFyIG1vZGVsIHZzIHRoZSBub25saW5lYXIgb25lIikgJT4lDQogIGthYmxlX3N0eWxpbmcoKQ0KDQpgYGANClRoZSBtb2RlbCBzZWxlY3RlZCBieSB0aGUgc3RlcHdpc2UgbWV0aG9kIGJ5IHRha2luZyBpbnRvIGFjY291bnQgZm9yIGFsbCB0aGUgcG9zc2libGUgbm9ubGluZWFyIHRlcm1zIHRoYXQgd2UgaGF2ZSBwcmV2aW91c2x5IGNvbnNpZGVyZWQgYXMgYSBCYXllc2lhbiBJbmZvcm1hdGlvbiBDcml0ZXJpb24gKEJJQykgdmFsdWUgc2lnbmlmaWNhbnRseSBzbWFsbGVyIHRoYW4gdGhlIGJlc3QgbW9kZWwgdGhhdCBpcyBsaW5lYXIgaW4gYWxsIHRoZSB2YXJpYWJsZXMuIA0KDQpOZXh0IHdlIGNvbXB1dGUgdGhlIHZhcmlhbmNlIGluZmxhdGlvbiBmYWN0b3JzIG9mIHRoZSBzZWxlY3RlZCBtb2RlbC4gDQoNCmBgYHtyfQ0KDQprYWJsZShjYXI6OnZpZihub25saW5fbW9kKSwgY2FwdGlvbj0iVmFyaWFuY2UgSW5mbGF0aW9uIGZhY3RvcnMgb2YgdGhlIG5vbmxpbmVhciBtb2RlbCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCg0KYGBgDQpBcyBleHBlY3RlZCB0aGUgbW9kZWwgaGFzIGV4dHJlbWVseSBoaWdoIHZhcmlhbmNlIGluZmxhY3Rpb24gZmFjdG9yIGR1ZSB0byB0aGUgaGlnaCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMgYmV0d2VlbiB0aGUgdmFyaWFibGVzLiBTaW5jZSB0aGUgaGlnaCB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9ycyBtYWtlIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgdW5zdGFibGUgYW5kIHVucmVsaWFibGUsIHdlIHByZWZlciB0byBkaXNjYXJkIHRoZSBsYXN0IG1vZGVsLg0KDQpIb3dldmVyIHdlIGhhdmUgbGVhcm50IHRoYXQgdGhlIGluY2x1c2lvbiBvZiBub25saW5lYXIgdGVybXMgY2FuIGltcHJvdmUgdGhlIG1vZGVsLiBTbywgbmV4dCwgd2UgdHJ5IHRvIHVwZGF0ZSB0aGUgbGFzdCBtb2RlbCBieSByZW1vdmluZyB2YXJpYWJsZXMgdGhhdCBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQgdG8gc2VlIGlmIHdlIGNhbiBnZXQgYSBtb2RlbCB0aGF0IGlzIG1vcmUgYWNjdXJhdGUgdGhhbiB0aGUgbGluZWFyIG1vZGVsIG1vZDMgd2l0aG91dCBoYXZpbmcgaGlnaCB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9ycy4gSW4gcGFydGljdWxhciB3ZSBoaWdobGlnaHQgdGhhdCBhIG1vZGVsIGV4cHJlc3NpbmcgdGhlIHdlaWdodCBsaW5lYXJseSB3aXRoIHJlc3BlY3QgdG8gYSB2b2x1bWUgd291bGQgYmUgcGh5c2ljYWxseSBtdWNoIG1vcmUgbWVhbmluZ2Z1bGwgdGhhbiBvbmUgZXNwcmVzc2luZyB0aGUgd2VpZ2h0IGxpbmVhcmx5IHdpdGggcmVzcGVjdCB0byBsZW5ndGhzLiBGb3IgdGhlc2UgcmVhc29ucyB3ZSBvcHQgZm9yIHJlbW92aW5nIGZyb20gdGhlIG1vZGVsIHRoZSB0d28gbGluZWFyIHZhcmlhYmxlcyAibGVuZ3RoIiBhbmQgImNyYW5pYWxfY2lyY3VtZmVyZW5jZSINCg0KYGBge3J9DQpub25saW5fbW9kMiA8LSB1cGRhdGUobm9ubGluX21vZCwgLiB+IC4gLSBMdW5naGV6emEgLSBDcmFuaW8pDQoNCnN1bW1hcnkobm9ubGluX21vZDIpDQoNCmthYmxlKGNhcjo6dmlmKG5vbmxpbl9tb2QyKSwgY2FwdGlvbj0iVmFyaWFuY2UgSW5mbGF0aW9uIGZhY3RvcnMgb2YgdGhlIG5vbmxpbmVhciBtb2RlbCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQpBZnRlciByZW1vdmluZyB0aGUgdmFyaWFibGVzIGxlbmd0aCBhbmQgY3JhbmlhbCBjaXJjdW1mZXJlbmNlIHRoZSB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9yIGlzIHN0aWxsIGhpZ2ggZm9yIHRoZSB0d28gY3ViaWMgdmFyaWFibGVzLiBGb3IgdGhpcyByZWFzb24gd2UgcmVtb3ZlIGZyb20gdGhlIG1vZGVsIGFsc28gdGhlIHZhcmlhYmxlICRMdW5naGV6emFcdGltZXMgQ3JhbmlvXjIkIHdoaWNoIHJlc3VsdHMgdGhlIGxlc3MgaW5mbHVlbnRpYWwuIA0KDQpgYGB7cn0NCm5vbmxpbl9tb2QzIDwtIHVwZGF0ZShub25saW5fbW9kMiwgLiB+IC4gLSBMdW5naGV6emF4Q3JhbmlvMikNCg0Kc3VtbWFyeShub25saW5fbW9kMykNCg0Ka2FibGUoY2FyOjp2aWYobm9ubGluX21vZDMpLCBjYXB0aW9uPSJWYXJpYW5jZSBJbmZsYXRpb24gZmFjdG9ycyBvZiB0aGUgbm9ubGluZWFyIG1vZGVsIikgJT4lDQogIGthYmxlX3N0eWxpbmcoKQ0KDQprYWJsZShCSUMobW9kMiwgbm9ubGluX21vZCwgbm9ubGluX21vZDIsIG5vbmxpbl9tb2QzKSwgY2FwdGlvbj0iQmF5ZXNpYW4gaW5mb3JtYXRpb24gZmFjdG9yIG9mIHRoZSBsaW5lYXIgbW9kZSB2cyBub25saW5lYXIgb25lcyIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCg0KDQpgYGANCg0KVGhlIGZpbmFsIG1vZGVsIHByZWRpY3RzIHRoZSB3ZWlnaHQgb2YgdGhlIG5ldyBib3JuIGJhc2VkIG9uIGdlc3RhdGlvbiB0aW1lLCBzcXVhcmVkIGxlbmd0aCB0aW1lcyBjcmFuaXVtIGNpcmN1bWZlcmVuY2UsIHNleCBhbmQgbnVtYmVyIG9mIGRlbGl2ZXJpZXMuIFRoZSBtb2RlbCBoYXMgYSBCSUMgdmFsdWUgbGFyZ2VyIHRoYW4gdGhlIGJlc3QgbW9kZWwgd2hpY2ggaW5jbHVkZWQgYWxsIHRoZSBwb3NzaWJsZSBub25saW5lYXIgdGVybXMgYnV0IHNtYWxsZXIgdGhhbiB0aGUgYmVzdCBtb2RlbCB0aGF0IGluY2x1ZGVkIG9ubHkgbGluZWFyIHRlcm1zIGluIHRoZSB2YXJpYWJsZXMuIE1vcmVvdmVyLCBkaWZmZXJlbnRseSBmcm9tIHRoZSBiZXN0IG1vZGVsIHRoYXQgaW5jbHVkZWQgYWxsIHRoZSBwb3NzaWJsZSBub25saW5lYXIgdGVybXMsIHRoZSBtb2RlbCAibm9ubGluX21vZDMiIGhhcyBhbGwgdGhlIHZhcmlhbmNlIGluZmxhdGlvbiBmYWN0b3JzIHNtYWxsZXIgdGhhbiA1Lg0KDQpXZSBwb2ludCBvdXQgdGhhdCB0aGUgbW9kZWwgIm5vbmxpbl9tb2QzIiwgaW5jbHVkaW5nIHRoZSBtaXhlZCB0ZXJtICRsZW5ndGheMlx0aW1lcyBjcmFuaWFsX2NpcmN1bWZlcmVjZSQgYnV0IG5vdCB0aGUgbGluZWFyIHRlcm1zIGluIHRoZSB2YXJpYWJsZXMgJGxlbmd0aCQgYWQgJGNyYW5pYWxfY2lyY3VtZmVyZWNlJCwgbWF5IGJyZWFrIHRoZSBwcmluY2lwbGUgb2YgbWFyZ2luYWxpdHkuIEhvd2V2ZXIgd2UgaGlnaGxpZ2h0IHRoYXQgdGhlIG1vZGVsIGlzIGFsc28gcGh5c2ljYWxseSBtb3JlIG1lYW5pbmdmdWxsIHRoYXQgb25lIGluY2x1ZGluZyB0aGUgbGluZWFyIHRlcm1zIGluIHRoZSB2YXJpYWJsZXMgJGxlbmd0aCQgYW5kICRjcmFuaWFsX2NpcmN1bWZlcmVuY2UkLg0KRm9yIHRoZXNlIHJlYXNvbnMgd2UgYWNjZXB0IHRoaXMgbW9kZWwgYW5kIGFuYWx5emUgaXQuDQpXZSBzdGFydCBhbmFseXppbmcgaXRzIGNvZWZmaWNpZW50cyANCg0KYGBge3J9DQprYWJsZShjb2VmKG5vbmxpbl9tb2QzKSwgY2FwdGlvbj0iQ29lZmZpY2llbnRzIG9mIGZpbmFsIG5vbmxpbmVhciBtb2RlbCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KVGhlIGNvZWZmaWNpZW50cyBzYXkgdGhhdCBmb3IgZWFjaCB1bml0IGluY3JlbWVudCBpbiB0aGUgZ2VzdGF0aW9uIHRpbWUgKDEgd2Vlaykgd2Ugb2JzZXJ2ZSBhbiBpbmNyZW1lbnQgb2YgYXBwcm94aW1hdGVseSA0MGdyIGluIHRoZSB3ZWlndGggb2YgdGhlIG5ld2Jvcm4uIFNpbWlsYXJseSBmb3IgZWFjaCAxbW1eMyBpbmNyZW1lbnQgaW4gdGhlIHZvbHVtZSB0ZXJtICgkTGVuZ3RoXjIgXHRpbWVzIENyYW5pYWxfY2lyY2Z1bWZlcmVuY2UkKSB3ZSByZWdpc3RlciBhbiBpbmNyZW1lbnQgb2YgJDMuNSoxMF4tNSQgKGdyKSBpbiB0aGUgd2VpZ2h0IG9mIHRoZSBuZXdib3JuLiBGaW5hbGx5IHdlIG9ic2VydmUgdGhhdCB0aGUgbWFsZXMgd2lsbCByZWdpc3RlciBhcHByb3hpbWF0ZWx5IDdnciBtb3JlIHRoYW4gZmVtYWxlcyBhbmQgY2hpbGQgYWZ0ZXIgdGhlIGZpcnN0IG9uZSB3ZWlnaHQgYXBwcm94aW1hdGVseSA0Z3IgbW9yZSB0aGFuIGEgZmlyc3QgY2hpbGQuDQoNCk5leHQgd2UgYW5hbHl6ZSB0aGUgcmVzaWR1YWxzLCBvdXRsaWVycyBhbmQgbGV2ZXJhZ2VzIG9mIHRoZSBtb2RlbC4NCg0KDQpgYGB7cn0NCnBhcihtZnJvdz1jKDIsMikpDQpwbG90KG5vbmxpbl9tb2QzKQ0KDQpsbXRlc3Q6OmJwdGVzdChub25saW5fbW9kMykNCmxtdGVzdDo6ZHd0ZXN0KG5vbmxpbl9tb2QzKQ0Kc2hhcGlyby50ZXN0KG5vbmxpbl9tb2QzJHJlc2lkdWFscykNCmBgYA0KDQpUaGUgYW5hbHlzaXMgc2hvd3MgdGhhdCB0aGVyZSBpcyBubyBhdXRvY29ycmVsYXRpb24gb2YgdGhlIHJlc2lkdWFscyAocC12YWx1ZSBvZiB0aGUgRHVyYmluLVdhdHNvbiB0ZXN0ID4gMC4wNSkuIEhvd2V2ZXIgd2Ugb2JzZXJ2ZSB0aGF0IHRoZSByZXNpZHVhbHMgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCAocC12YWx1ZSBvZiB0aGUgU2hhcGlyby1XaWxrIHRlc3QgPDAuMDUpIGFuZCB0aGF0IHRoZXJlIGlzIG5vIGhldGVyb3NjZWRhc3RpY2l0eSAocC12YWx1ZSBvZiB0aGUgQnJldXNjaC1QYWdhbiA8IDAuMDUpLiBBZGRpdGlvbmFsbHkgd2Ugb2JzZXJ2ZSB0aGF0IHRoZXJlIGFyZSBzb21lIGhpZ2hseSBpbmZsdWVudGlhbCBvdXRsaWVyIGRhdGFwb2ludHMgaGF2aW5nIENvb2sgZGlzdGFuY2UgY2xvc2UgdG8gMC41Lg0KDQpTbyB3ZSBpbnZlc3RpZ2F0ZSBkZWVwZXIgdGhlIGxldmVyYWdlcyBhbmQgb3V0bGllcnMuIFdlIGNvbnNpZGVyIGxldmVyYWdlcyB0aGUgcG9pbnRzIGhhdmluZyBsZXZlcmFnZSB2YWx1ZSBsYXJnZXIgdGhhbiB0aGUgdGhyZXNob2xkLiBUaGlzIGlzIHNldCBlcXVhbCB0byAzIHRpbWVzIHRoZSBsZXZlcmFnZSBtZWFuLCBpLmUuIHRoZSBudW1iZXIgb2YgcGFyYW1ldGVycyBvZiB0aGUgbW9kZWwgb3ZlciB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiB0aGUgZGF0YXNldC4gTW9yZW92ZXIgdGhlIG91dGxpZXJzIGFyZSBpZGVudGlmaWVkIGJ5IGEgQm9uZmVycm9uaSB0ZXN0IG9uIHRoZSBzdHVkZW50aXplZCByZXNpZHVhbHMgb2YgdGhlIG1vZGVsLg0KDQpgYGB7cn0NCg0KI2xldmVyYWdlDQpsZXY8LWhhdHZhbHVlcyhub25saW5fbW9kMykNCnBsb3QobGV2KQ0KcDwtc3VtKGxldikNCm48LWxlbmd0aChsZXYpDQpzb2dsaWE9MypwL24NCmFibGluZShoPXNvZ2xpYSxjb2w9MikNCnRpdGxlKG1haW4gPSAiTGV2ZXJhZ2UgdmFsdWVzIG9mIG1vZGVsIG1vZDEiKQ0KbGV2ZXJhZ2VzPXdoaWNoKGxldj5zb2dsaWEpDQpjYXQoIlRoZXJlIGFyZSIsIGxlbmd0aChsZXZlcmFnZXMpLCAibGV2ZXJhZ2VzXG4iKQ0KDQojb3V0bGllcnMNCnBsb3QocnN0dWRlbnQobm9ubGluX21vZDMpKQ0KYWJsaW5lKGg9YygtMiwyKSkNCnRpdGxlKG1haW4gPSAiU3R1ZGVudGl6ZWQgUmVzaWR1YWxzIG9mIG1vZGVsIG1vZDEiKQ0KDQoNCmNhdCgiVGhlIG91dGxpZXJzIGFyZTpcbiIpDQpjYXI6Om91dGxpZXJUZXN0KG5vbmxpbl9tb2QzKQ0KDQoNCiNkaXN0YW56YSBkaSBjb29rDQpjb29rPC1jb29rcy5kaXN0YW5jZShub25saW5fbW9kMykNCnBsb3QoY29vayx5bGltID0gYygwLDEpKSANCnRpdGxlKG1haW4gPSAiQ29vayBkaXN0YW5jZSBvZiByZXNpZHVhbHMgb2YgbW9kZWwgbW9kMSIpDQpgYGANCg0KV2Ugbm90ZSB0aGF0IHRoZSBtb3N0IGluZmx1ZW50aWFsIG91dGxpZXIsIHRoZSBkYXRhcG9pbnQgMTU0OSwgd2l0aCBhIENvb2sgZGlzdGFuY2UgYXJvdW5kIDAuMiwgY291bGQgaGF2ZSBhIHJlbGV2YW50IGVmZmVjdCBvbiB0aGUgZXN0aW1hdGUgb2YgdGhlIGNvZWZmaWNpZW50cyBvZiB0aGUgbW9kZWwgYnV0IG5vdCBkcmFzdGljYWwuIEJ5IGludmVzdGlnYXRpbmcgdGhpcyBkYXRhcG9pbnQgd2UgZmluZCB0aGF0IHRoaXMgaXMgdGhlIHNhbWUgZGF0YXBvaW50IHRoYXQgd2UgaGF2ZSBhbHJlYWR5IG1ldCBiZWZvcmUgd2hpY2ggaGFzIGEgbGVuZ3RoIG11Y2ggbG93ZXIgdGhhbiBleHBlY3RlZCwgcHJvYmFibHkgZm9yIGEgdHlwbyBpbiBpdHMgdHJhbnNwb3NpdGlvbi4NCg0KDQpgYGB7cn0NCmthYmxlKHQoZGF0YXNldFsxNTQ5LF0pLCBjYXB0aW9uPSJPdXRsaWVyIGRhdGFwb2ludCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCg0KYGBgDQoNCg0KTmV4dCB3ZSBldmFsdWF0ZSB0aGUgcXVhbGl0eSBvZiB0aGUgbW9kZWwgaW4gdGVybXMgb2YgdGhlICRSXjIkIGFuZCBSTVNFIG1ldHJpY3MuDQpgYGB7cn0NCiMgUl4yIDoNCnN1bW1hcnlfbW9kIDwtIHN1bW1hcnkobm9ubGluX21vZDMpDQpSMiA8LSBzdW1tYXJ5X21vZCRyLnNxdWFyZWQNCmNhdCgiVGhlIFJeMiB2YWx1ZSBvZiB0aGUgbW9kZWwgaXMgZXF1YWwgdG8iLCBSMiwgIiwgc28gdGhlIG1vZGVsIGlzIGV4cGxhaW5pbmcgYWJvdXQgNzMlIG9mIHRoZSB2YXJpYW5jZSBvZiB0aGUgdmFyaWFibGUgV2VpZ2h0LiBcbiIpDQoNCiMgUk1TRToNCnByZWRpY3Rpb25zIDwtIHByZWRpY3Qobm9ubGluX21vZDMsIG5ld2RhdGEgPSBkYXRhc2V0KQ0KcmVzaWR1YWxzIDwtIGRhdGFzZXQkUGVzbyAtIHByZWRpY3Rpb25zDQpSTVNFIDwtIHNxcnQobWVhbihyZXNpZHVhbHNeMikpDQpwZXJSTVNFPVJNU0UvbWVhbihkYXRhc2V0JFBlc28pDQpjYXQoIlRoZSBSTVNFIHZhbHVlIG9mIHRoZSBtb2RlbCBpcyBlcXVhbCB0byIsIFJNU0UsICIuXG4iKSANCmNhdCgiVGhpcyBtZWFucyB0aGF0IHRoZSBtb2RlbCBoYXMgYSBtZWFuIGVycm9yIG9mIHByZWRpY3Rpb24gb2YiICwgcGFzdGUwKHJvdW5kKHBlclJNU0UsMiksIiUiKSwid2l0aCByZXNwZWN0IHRvIHRoZSBtZWFuIG9mIHRoZSB2YXJpYWJsZSB3ZWlnaHQuXG4iKQ0KY2F0KCJNb3Jlb3ZlciB0aGlzIG1lYW5zIHRoYXQgdGhlIHZhcmlhbmNlIG9mIHRoZSBwcmVkaWN0aW9uIGVycm9ycyBvZiB0aGUgbW9kZWwgaXMgYWJvdXQiLCByb3VuZChSTVNFL3NkKGRhdGFzZXQkUGVzbyksMiksICJvZiB0aGUgdmFyaWFuY2Ugb2YgdGhlIHZhcmlhYmxlIHdlaWdodCIpDQpgYGANCiMjIFVzaW5nIHRoZSBtb2RlbCB0byBtYWtlIHByZWRpY3Rpb25zDQpBc3N1bWUgdG8gaGF2ZSBhIGZlbWFsZSBiYWJ5IHRoYXQgd2lsbCBiZSBkZWxpdmVyZWQgYXQgdGhlIDM5dGggd2VlayBhbmQgd2hvc2UgbW90aGVyIGhhcyBhbHJlYWR5IGRlbGl2ZXJlZCB0d28gY2hpbGRyZW4uIFRoZW4gd2UgY2FuIHByZWRpY3QgaGVyIHdlaWdodC4gDQpGb3IgdGhlIG5ldyBiYWJ5IHdlIGFzc3VtZSBhIGxlbmd0aCBhbmQgY3JhbmlhbCBjaXJjdW1mZXJlbmNlIGVxdWFsIHRvIHRoZSBtZWFuIHdlaWdodCBhbmQgY3JhbmlhbCBjaXJjdW1mZXJlbmUgb2YgZmVtYWxlIG5ld2Jvcm5zIGF0IHRoZSAzOXRoIGdlc3RhdGlvbiB3ZWVrLg0KDQoNCmBgYHtyfQ0KbGVuZ3RoPSBtZWFuKHN1YnNldChkYXRhc2V0LCBTZXNzbyA9PSAiRiIgJiBHZXN0YXppb25lPT0zOSkkTHVuZ2hlenphKQ0KY3Jhbml1bT0gbWVhbihzdWJzZXQoZGF0YXNldCwgU2Vzc28gPT0gIkYiICYgR2VzdGF6aW9uZT09MzkpJENyYW5pbykNCg0KbmV3X2RhdGEgPC0gZGF0YS5mcmFtZSgiTi5ncmF2aWRhbnplIiA9IGMoMiksDQogICAgICAgICAgICAgICAgICAgICAgICJHZXN0YXppb25lIj1jKDM5KSwNCiAgICAgICAgICAgICAgICAgICAgICAgIkx1bmdoZXp6YSI9YyhsZW5ndGgpLA0KICAgICAgICAgICAgICAgICAgICAgICAiQ3JhbmlvIj1jKGNyYW5pdW0pLA0KICAgICAgICAgICAgICAgICAgICAgICAiU2Vzc28iPWMoIkYiKQ0KICAgICAgICAgICAgICAgICAgICAgICApDQoNCm5ld19kYXRhJEx1bmdoZXp6YTJ4Q3JhbmlvID0gKG5ld19kYXRhJEx1bmdoZXp6YSleMioobmV3X2RhdGEkQ3JhbmlvKQ0KbmV3X2RhdGEkQ3JhbmlvMiA8LSAobmV3X2RhdGEkQ3JhbmlvKV4yDQpuZXdfZGF0YSROLmdyYXZpZGFuemVfQ0wgPC0gY3V0KG5ld19kYXRhJE4uZ3JhdmlkYW56ZSwgDQogICAgICAgICAgICAgICAgICAgICBicmVha3M9YygwLDEsMTAwKSwgDQogICAgICAgICAgICAgICAgICAgICByaWdodD1GQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiMCIsIjErIikpDQoNCg0Kd2VpZ2h0X3ByZWRpY3Rpb24gPC0gcm91bmQocHJlZGljdChub25saW5fbW9kMywgbmV3ZGF0YSA9IG5ld19kYXRhKSkNCg0KDQpjYXQoIlRoZSByZWdyZXNzaW9uIG1vZGVsIHByZWRpY3RzIGEgd2VpZ2h0IGVxdWFsIHRvIiwgcGFzdGUwKHdlaWdodF9wcmVkaWN0aW9uLCJnciIpLCAiLlxuIikgDQpgYGANCg0KDQojIyBGaW5hbGx5IHdlIGRpc3BsYXkgdGhlIHJlbGF0aW9ucyBjYXB0dXJlZCBpbiB0aGUgbW9kZWwuDQoNCjwhLS0gYGBge3J9IC0tPg0KDQo8IS0tIGdncGxvdChkYXRhPWRhdGFzZXRfY2xlYW4sIC0tPg0KPCEtLSAgICAgICAgYWVzKHggPSBMdW5naGV6emEsICAtLT4NCjwhLS0gICAgICAgICAgICB5ID0gQ3JhbmlvLCAgLS0+DQo8IS0tICAgICAgICAgICAgY29sb3IgPSBQZXNvKSkgKyAtLT4NCjwhLS0gICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDMuNSkgKyAtLT4NCjwhLS0gICAgICAgIGxhYnModGl0bGUgPSAiV2VpZ2h0IGFzIGEgZnVuY3Rpb24gb2YgTGVuZ3RoIGFuZCBDcmFuaWFsIGNpcmN1bWZlcmVuY2UiLCAtLT4NCjwhLS0gICAgICAgICAgICAgeCA9ICJMZW5ndGgiLCAtLT4NCjwhLS0gICAgICAgICAgICAgeSA9ICJDcmFuaWFsIGNpcmN1bWZlcmVuY2UiLCAgLS0+DQo8IS0tICAgICAgICAgICAgIGNvbG9yID0gIldlaWdodCIpKyAtLT4NCjwhLS0gICAgICAgdGhlbWVfY2xhc3NpYygpKyAtLT4NCjwhLS0gICAgICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxMCkpLCAtLT4NCjwhLS0gICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHIgPSAxMCkpKSAtLT4NCg0KPCEtLSBgYGAgLS0+DQogDQoNCkZpcnN0IHdlIGRpc3BsYXkgaG93IHRoZSB3ZWlnaHQgaXMgZGlzdHJpYnV0ZWQgYWNjb3JkaW5nIHRvIHRoZSBzZXggYW5kIG51bWJlciBvZiBkZWxpdmVyaWVzIHdpdGggcmVzcGVjdCB0byB0aGUgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyBpbiB0aGUgbW9kZWwsIGkuZS4gJGdlc3RhdGlvblxfdGltZSQgYW5kICQobGVuZ3RoKV4yXHRpbWVzIGNyYW5pYWxcX2NpcmN1bWZlcmVuY2UkLg0KDQoNCmBgYHtyLCBmaWcud2lkdGg9MTEuNSwgZmlnLmhlaWdodD01fQ0KDQpwbG90X2Zpbl8xID0gZ2dwbG90KGRhdGE9ZGF0YXNldCkrDQogICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHg9R2VzdGF6aW9uZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9UGVzbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbD1TZXNzbykscG9zaXRpb24gPSAiaml0dGVyIikrDQogICAgICAgICAgICAgICAgICAgIGdlb21fc21vb3RoKGFlcyh4PUdlc3RhemlvbmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVBlc28sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9U2Vzc28pLCBzZT1GLCBtZXRob2QgPSAibG0iKSsNCiAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBzZXhfY29sb3JzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiTSI9ICJNYWxlIiwgIkYiPSJGZW1hbGUiKSkrDQogICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJXZWlnaHQgYXMgYSBmdW5jdGlvbiBvZiBHZXN0YXRpb24gdGltZSIsDQogICAgICAgICAgICAgICAgICAgICAgICB4ID0gImdlc3RhdGlvbiB0aW1lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAid2VpZ2h0IChncikiKSsNCiAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKw0KICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbihyID0gMTApKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpDQoNCg0KbGVnZW5kIDwtIGFzX2dncGxvdChnZXRfbGVnZW5kKHBsb3RfZmluXzEpKQ0KDQpwbG90X2Zpbl8xID0gZ2dwbG90KGRhdGE9ZGF0YXNldCkrDQogICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHg9R2VzdGF6aW9uZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9UGVzbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbD1TZXNzbykscG9zaXRpb24gPSAiaml0dGVyIikrDQogICAgICAgICAgICAgICAgICAgIGdlb21fc21vb3RoKGFlcyh4PUdlc3RhemlvbmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVBlc28sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9U2Vzc28pLCBzZT1GLCBtZXRob2QgPSAibG0iKSsNCiAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBzZXhfY29sb3JzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiTSI9ICJNYWxlIiwgIkYiPSJGZW1hbGUiKSkrDQogICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJXZWlnaHQgYXMgYSBmdW5jdGlvbiBvZiBHZXN0YXRpb24gdGltZSIsDQogICAgICAgICAgICAgICAgICAgICAgICB4ID0gImdlc3RhdGlvbiB0aW1lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAid2VpZ2h0IChncikiKSsNCiAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKw0KICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbihyID0gMTApKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQoNCiBwbG90X2Zpbl8zID0gZ2dwbG90KGRhdGE9ZGF0YXNldCkrDQogICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHg9THVuZ2hlenphMnhDcmFuaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVBlc28sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9U2Vzc28pKSsNCiAgICAgICAgICAgICAgICAgICAgZ2VvbV9zbW9vdGgoYWVzKHg9THVuZ2hlenphMnhDcmFuaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVBlc28sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9U2Vzc28pLCBzZT1GLCBtZXRob2QgPSAibG0iKSsNCiAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBzZXhfY29sb3JzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiTSI9ICJNYWxlIiwgIkYiPSJGZW1hbGUiKSkrDQogICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiV2VpZ2h0IGFzIGEgZnVuY3Rpb24gb2YgXG4gTGVuZ3ReMiB4IGNyYW5pYWwgY2lyY3VtZmVyZW5jZSIsDQogICAgICAgICAgICAgICAgICAgICAgICB4ID0gIkxlbmd0XjIgeCBjcmFuaWFsIGNpcmN1bWZlcmVuY2UgKG1tXjMpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAid2VpZ2h0IChncikiKSsNCiAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKw0KICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbihyID0gMTApKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQogIA0KICANCmNvbWJfZmluIDwtIHBsb3RfZmluXzEgKyBwbG90X2Zpbl8zICsgbGVnZW5kICsgcGxvdF9sYXlvdXQobmNvbD0zLCBoZWlnaHRzID0gYyg1KSwgd2lkdGhzPSBjKDUsNSwxLjUpKQ0KDQpwcmludChjb21iX2ZpbikNCmBgYA0KDQoNCg0KYGBge3IsIGZpZy53aWR0aD0xMS41LCBmaWcuaGVpZ2h0PTV9DQoNCnBsb3RfZmluXzEgPSBnZ3Bsb3QoZGF0YT1kYXRhc2V0KSsNCiAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChhZXMoeD1HZXN0YXppb25lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1QZXNvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sPU4uZ3JhdmlkYW56ZV9DTCkscG9zaXRpb24gPSAiaml0dGVyIikrDQogICAgICAgICAgICAgICAgICAgIGdlb21fc21vb3RoKGFlcyh4PUdlc3RhemlvbmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVBlc28sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9Ti5ncmF2aWRhbnplX0NMKSwgc2U9RiwgbWV0aG9kID0gImxtIikrDQogICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJXZWlnaHQgYXMgYSBmdW5jdGlvbiBvZiBHZXN0YXRpb24gdGltZSIsDQogICAgICAgICAgICAgICAgICAgICAgICB4ID0gImdlc3RhdGlvbiB0aW1lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAid2VpZ2h0IChncikiLA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiTsKwIHByZXZpb3VzIGRlbGl2ZXJpZXMiKSsNCiAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKw0KICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIG1hcmdpbiA9IG1hcmdpbihyID0gMTApKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpDQoNCg0KbGVnZW5kIDwtIGFzX2dncGxvdChnZXRfbGVnZW5kKHBsb3RfZmluXzEpKQ0KDQpwbG90X2Zpbl8xID0gZ2dwbG90KGRhdGE9ZGF0YXNldCkrDQogICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHg9R2VzdGF6aW9uZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9UGVzbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbD1OLmdyYXZpZGFuemVfQ0wpLHBvc2l0aW9uID0gImppdHRlciIpKw0KICAgICAgICAgICAgICAgICAgICBnZW9tX3Ntb290aChhZXMoeD1HZXN0YXppb25lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1QZXNvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sPU4uZ3JhdmlkYW56ZV9DTCksIHNlPUYsIG1ldGhvZCA9ICJsbSIpKw0KICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiV2VpZ2h0IGFzIGEgZnVuY3Rpb24gb2YgR2VzdGF0aW9uIHRpbWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJnZXN0YXRpb24gdGltZSIsDQogICAgICAgICAgICAgICAgICAgICAgICB5ID0gIndlaWdodCAoZ3IpIikrDQogICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSsNCiAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxMCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4ociA9IDEwKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KICANCiBwbG90X2Zpbl8zID0gZ2dwbG90KGRhdGE9ZGF0YXNldCkrDQogICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHg9THVuZ2hlenphMnhDcmFuaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVBlc28sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9Ti5ncmF2aWRhbnplX0NMKSkrDQogICAgICAgICAgICAgICAgICAgIGdlb21fc21vb3RoKGFlcyh4PUx1bmdoZXp6YTJ4Q3JhbmlvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1QZXNvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sPU4uZ3JhdmlkYW56ZV9DTCksIHNlPUYsIG1ldGhvZCA9ICJsbSIpKw0KICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIldlaWdodCBhcyBhIGZ1bmN0aW9uIG9mIFxuIExlbmd0XjIgeCBjcmFuaWFsIGNpcmN1bWZlcmVuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJMZW5ndF4yIHggY3JhbmlhbCBjaXJjdW1mZXJlbmNlIChtbV4zKSIsDQogICAgICAgICAgICAgICAgICAgICAgICB5ID0gIndlaWdodCAoZ3IpIikrDQogICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSsNCiAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxMCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBtYXJnaW4gPSBtYXJnaW4ociA9IDEwKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KICANCiAgDQpjb21iX2ZpbiA8LSBwbG90X2Zpbl8xICsgcGxvdF9maW5fMyArIGxlZ2VuZCArIHBsb3RfbGF5b3V0KG5jb2w9MywgaGVpZ2h0cyA9IGMoNSksIHdpZHRocz0gYyg1LDUsMS41KSkNCg0KcHJpbnQoY29tYl9maW4pDQpgYGANCg0KVGhlIHBsb3RzIGNvbmZpcm0gdGhhdCB0aGUgd2VpZ2h0IGluY3JlYXNlcyB3aGlsZSBpbmNyZWFzaW5nIGFsbCB0aGUgb3RoZXIgdmFyaWFibGVzIGluIHRoZSBtb2RlbC4gTW9yZW92ZXIgd2Ugb2JzZXJ2ZSB0aGF0IHRoZSB3ZWlnaHQgb2JzZXJ2ZWQgaW4gbWFsZXMgaXMgYWx3YXlzIGhpZ2hlciB0aGFuIHRoZSB3ZWlnaHQgb2JzZXJ2ZWQgaW4gZmVtYWxlcy4gRGlmZmVyZW50bHkgdGhlIGRpZmZlcmVuY2UgaW4gd2VpZ2h0IGJldHdlZW4gZmlyc3QgY2hpbGRyZW4gYW5kIG5vdCBmaXJzdCBjaGlsZHJlbiBpcyBvbmx5IG9ic2VydmFibGUgd2hlbiB2YXJ5aW5nIHRoZSB2YXJpYWJsZSBnZXN0YXRpb24gdGltZS4gSW4gdGhpcyBjYXNlIHdlIG9ic2VydmUgdGhhdCB0aGUgd2VpZ2h0IG9mIGZpcnN0IGNoaWxkcmVuIGlzIHNsaWdodGx5IHNtYWxsZXIgdGhhbiB0aGUgd2VpZ2h0IG9mIG5vdCBmaXJzdCBjaGlsZHJlbi4gVGhlIG9ic2VydmF0aW9ucyBhcmUgaW4gYWdyZWVtZW50cyB3aXRoIHRoZSBkaXNjdXNzaW9uIGFib3V0IHRoZSAkXGJldGEkIGNvZWZmaWNpZW50cyBvZiB0aGUgbW9kZWwuIA0KDQo=