Loading packages and
creating in the data set
We’ll start by loading the tidyverse:
Since the variance of the slope, \(b_1\), depends on \(S_{XX}\):
\[S_{XX} =
\sum_{i=1}^n(X_i-\bar{X})^2\]
We need to keep the \(X_i\) the same
throughout the simulation for each iteration. We’ll keep it simple and
let \(x_i = 2i\) with \(i = 1, ..., 10\)
X <- 2*(1:10)
X
## [1] 2 4 6 8 10 12 14 16 18 20
The \(S_{XX}\) is:
# S_XX = sum (X_i - X_bar)^2
S_XX <- sum((X - mean(X))^2)
S_XX
## [1] 330
When performing a simulation, we need to create a model to generate
our data. The population model for our simulation is:
\[Y_i = 20 + 40X_i + \varepsilon_i \\
\varepsilon_i \sim N(0, 660)\]
For each simulation we run, we’ll generate \(Y_i\) using the model above
Theoretical
distribution for \(b_1\)
According to the slides we saw in class, as long as
\[Y_i \sim N(\beta_0 + \beta_1 X_i,
\sigma^2)\]
are are independent, then the distribution of \(b_1\) is:
\[b_1 \sim N\left(\beta_1,
\frac{\sigma^2}{S_{XX}}\right)\]
Since we control the population, we know the distribution \(b_1\) for our example should follow:
\[b_1 \sim N\left(40,
\frac{660}{330}\right)\]
Simulating 10,000
samples of n = 10
We’ll generate 10,000 samples of 10 \(Y_i\) values each based on the model stated
above, which is theoretically akin to taking a random sample from a
population.
From each sample, we’ll save the following info:
- The sample
- \(b_0\)
- \(b_1\)
- \(SSE\)
# Simulation and sample sizes
m <- 1e5
sample_size <- 10
# Setting the parameters of the model
beta0 <- 20; beta1 <- 40; sigma2_e <- 660
# Data frame to save the result:
sim_df <-
data.frame(
sample = 1:m,
b0 = -100,
b1 = -100,
SSE = -1
)
Before we conduct the full simulation, let’s generate one sample and
calculate the stats needed as an example:
### Let's generate a random sample for sake of showing how:
set.seed(4210)
# The response from the model:
Y_loop <- beta0 + beta1 * X +
# Random error term
rnorm(sample_size, mean = 0, sd = sqrt(sigma2_e))
# Find b1:
b1_loop <-
# S_XY
sum((X - mean(X))*(Y_loop - mean(Y_loop))) / S_XX
# Finding b0:
b0_loop <- mean(Y_loop) - b1_loop * mean(X)
# Calculating y_hat
Y_hat_loop <- b0_loop + b1_loop * X
# Residuals:
res_loop <- Y_loop - Y_hat_loop
# SSE:
SSE_loop <- sum(res_loop^2)
# Now we'll save the results in the first row
sim_df[1, 2:ncol(sim_df)] <- c(b0_loop, b1_loop, SSE_loop)
tibble(sim_df)
## # A tibble: 100,000 × 4
## sample b0 b1 SSE
## <int> <dbl> <dbl> <dbl>
## 1 1 23.5 39.8 1657.
## 2 2 -100 -100 -1
## 3 3 -100 -100 -1
## 4 4 -100 -100 -1
## 5 5 -100 -100 -1
## 6 6 -100 -100 -1
## 7 7 -100 -100 -1
## 8 8 -100 -100 -1
## 9 9 -100 -100 -1
## 10 10 -100 -100 -1
## # ℹ 99,990 more rows
Now we’ll add the remaining sample stats to the data frame:
# Performing the simulation:
for (i in 2:m){
# The response from the model:
Y_loop <- beta0 + beta1 * X +
# Random error term
rnorm(sample_size, mean = 0, sd = sqrt(sigma2_e))
# Find b1:
b1_loop <- sum((X - mean(X))*(Y_loop - mean(Y_loop))) / S_XX
# Finding b0:
b0_loop <- mean(Y_loop) - b1_loop * mean(X)
# Calculating y_hat
Y_hat_loop <- b0_loop + b1_loop * X
# Residuals:
res_loop <- Y_loop - Y_hat_loop
# SSE:
SSE_loop <- sum(res_loop^2)
# Now we'll save the results in the first row
sim_df[i, 2:ncol(sim_df)] <- c(b0_loop, b1_loop, SSE_loop)
}
tibble(sim_df)
## # A tibble: 100,000 × 4
## sample b0 b1 SSE
## <int> <dbl> <dbl> <dbl>
## 1 1 23.5 39.8 1657.
## 2 2 16.1 41.0 3318.
## 3 3 28.9 38.7 5290.
## 4 4 57.0 37.9 2793.
## 5 5 24.6 40.2 2391.
## 6 6 19.8 39.6 4262.
## 7 7 13.7 40.4 2323.
## 8 8 40.0 38.4 3262.
## 9 9 10.3 40.1 3662.
## 10 10 -6.51 41.2 4166.
## # ℹ 99,990 more rows
Distribution of \(b_1\)
Let’s create a histogram of our simulated slopes and superimpose a
Normal curve on it.
Reminder: If the theory is correct, then:
\[b_1 \sim N\left(40,
\frac{660}{330}\right)\]
ggplot(
data = sim_df,
mapping = aes(
x = b1
)
) +
geom_histogram(
# Need to swap from count to density on the y-axis to place a normal curve
mapping = aes(y = after_stat(density)),
bins = 40,
fill = 'steelblue',
color = 'white'
) +
# Adding the Normal curve:
stat_function(
fun = dnorm,
args = list(mean = beta1, sd = sqrt(sigma2_e/S_XX)),
color = 'red',
linewidth = 1,
alpha = 0.5
) +
theme_bw() +
labs(
title = 'Histogram of simulated slopes'
) +
scale_y_continuous(
expand = c(0, 0, 0.05, 0)
)

Histogram looks pretty accurate!
What about the test statistics and p-values? Do they ‘line up’ with
what the theory says?
Result: If \(H_0\)
is true, then the p-value is a random variable that follows a uniform
distribution between 0 and 1:
\[\text{p-val} | H_0 \sim
\text{Uniform}(0, 1)\]
Type I error rate:
\(\sigma^2\) known
So if we calculate the test statistic and p-value for all of our
simulated samples, then 5% of our samples should give us a p-value below
0.05 (or whatever significance level you choose)
\[P(\text{p-val} < \alpha) =
\alpha\]
# Finding the p-values:
sim_df <-
sim_df |>
mutate(
# Test statistic
test_stat = (b1 - beta1) / sqrt(sigma2_e/S_XX),
# Now p-value for Beta1 =\= 40
p_val_sigma = 2*pnorm(abs(test_stat), lower.tail = F)
)
sim_df |>
dplyr::select(sample, b1, test_stat, p_val_sigma) |>
tibble()
## # A tibble: 100,000 × 4
## sample b1 test_stat p_val_sigma
## <int> <dbl> <dbl> <dbl>
## 1 1 39.8 -0.138 0.890
## 2 2 41.0 0.693 0.488
## 3 3 38.7 -0.937 0.349
## 4 4 37.9 -1.50 0.134
## 5 5 40.2 0.164 0.870
## 6 6 39.6 -0.259 0.795
## 7 7 40.4 0.255 0.799
## 8 8 38.4 -1.17 0.244
## 9 9 40.1 0.0506 0.960
## 10 10 41.2 0.849 0.396
## # ℹ 99,990 more rows
Let’s plot them and calculate the probability of rejecting a true
\(H_0\):
# Calculating the probability of a type 1 error
prob_type1_alpha_5 <- mean(sim_df$p_val_sigma < 0.05)
# How wide to make each bin
binwidth = 0.01
ggplot(
data = sim_df,
mapping = aes(
x = p_val_sigma,
fill = if_else(p_val_sigma < 0.05, 'tomato', 'steelblue')
)
) +
geom_histogram(
# Need to swap from count to density on the y-axis to place a normal curve
mapping = aes(y = after_stat(count) / (m * binwidth)),
breaks = seq(0, 1, binwidth),
#fill = 'steelblue',
color = 'white'
) +
# Adding the Uniform 'curve':
stat_function(
fun = dunif,
args = list(min = 0, max = 1),
color = 'red',
linewidth = 1,
alpha = 0.5
) +
# Adding the probability of Type 1
labs(
title = 'Distribution of p-values when Ho is true and sigma is known',
subtitle = paste('When alpha = 5% the chance of Type I error is',
scales::percent(prob_type1_alpha_5)),
caption = paste('Results from a simulation of', scales::comma(m),
'simulations each with a sample size of', sample_size),
x = 'P-value',
y = 'Density'
) +
theme_bw() +
scale_fill_identity() +
scale_y_continuous(
expand = c(0, 0, 0.05, 0)
)

The distribution above assumes we know what \(\sigma^2\) is, which we usually don’t. What
happens if we swap \(\sigma^2\) with
the MSE?
Type I error rate:
\(\sigma^2\)
unknown
Instead of using the standard deviation of \(b_1\), we’ll have to use the standard
error:
\[SE(b_1) =
\sqrt{\frac{MSE}{S_{XX}}}\]
We can calculate the \(MSE\) for
each sample by:
\[MSE = \frac{SSE}{n-2}\]
So let’s find the Standard error, test stat, and p-value using the
\(MSE\):
\[z = \frac{b_1 -
\beta_{1,0}}{\sqrt{\frac{MSE}{S_{XX}}}}\]
# Finding the p-values:
sim_df <-
sim_df |>
mutate(
MSE = SSE / (sample_size - 2),
# Test statistic using mse
test_stat_mse = (b1 - beta1) / sqrt(MSE/S_XX),
# Now p-value for Beta1 =\= 40
p_val_mse = 2*pnorm(abs(test_stat_mse), lower.tail = F)
)
sim_df |>
dplyr::select(sample, b1, MSE, test_stat_mse, p_val_mse) |>
tibble()
## # A tibble: 100,000 × 5
## sample b1 MSE test_stat_mse p_val_mse
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 39.8 207. -0.246 0.806
## 2 2 41.0 415. 0.874 0.382
## 3 3 38.7 661. -0.936 0.349
## 4 4 37.9 349. -2.06 0.0396
## 5 5 40.2 299. 0.244 0.807
## 6 6 39.6 533. -0.289 0.773
## 7 7 40.4 290. 0.384 0.701
## 8 8 38.4 408. -1.48 0.138
## 9 9 40.1 458. 0.0607 0.952
## 10 10 41.2 521. 0.956 0.339
## # ℹ 99,990 more rows
Plot of the test
statistic using MSE instead of \(\sigma^2\)
The histogram of the test statistic is shown below. Does it look like
the Standard Normal distribution fit the histogram?
gg_test_stat_mse_hist <-
ggplot(
# There are a few extreme values, so we'll only look at -5 < z < 5
data = sim_df |>
filter(between(test_stat_mse, -5, 5)),
mapping = aes(
x = test_stat_mse
)
) +
geom_histogram(
# Need to swap from count to density on the y-axis to place a normal curve
mapping = aes(y = after_stat(density)),
bins = 40,
fill = 'steelblue',
color = 'white'
) +
theme_bw() +
labs(
title = paste('Histogram of', scales::comma(m), 'test statistics for the slope'),
subtitle = 'Calculated using the MSE',
x = 'Test statistics'
) +
scale_y_continuous(
expand = c(0, 0, 0.05, 0)
) +
scale_x_continuous(
breaks = -5:5
)
gg_test_stat_mse_hist +
# Adding the Normal curve:
stat_function(
fun = dnorm,
args = list(mean = 0, sd = 1),
color = 'red',
linewidth = 1,
alpha = 0.5
) +
labs(
caption = 'Standard Normal Distribution Overlayed on the Histogram'
)

The Normal curve looks close, but the middle bars are consistently
below the line while the tails are above the line. That typically
indicates that a wider distribution is needed instead of a Normal
distribution.
Let’s check the p-values as well!
Plot of the
p-values using MSE and Normal distribution
Again, plotting them and calculate the probability of rejecting a
true \(H_0\) assuming the test
statistic follows a Standard Normal:
# Calculating the probability of a type 1 error
prob_type1_alpha_5_mse <- mean(sim_df$p_val_mse < 0.05)
# Creating the graph
ggplot(
data = sim_df,
mapping = aes(
x = p_val_mse,
fill = if_else(p_val_mse < 0.05, 'tomato', 'steelblue'),
# group = 1
)
) +
geom_histogram(
# Need to swap from count to density on the y-axis to place a normal curve
mapping = aes(y = after_stat(count) / (m * binwidth)),
breaks = seq(0, 1, binwidth),
color = 'white'
) +
# Adding the Uniform 'curve':
stat_function(
fun = dunif,
args = list(min = 0, max = 1),
color = 'red',
linewidth = 1,
alpha = 0.5
) +
# Adding the probability of Type 1
labs(
title = 'Distribution of p-values when H0 is true, using a Normal with sigma unknown',
subtitle = paste('alpha = 5% and Type I probability is',
scales::percent(prob_type1_alpha_5_mse)),
caption = paste('Results from a simulation of', scales::comma(m),
'simulations each with a sample size of', sample_size),
x = 'P-value',
y = 'Density'
) +
theme_bw() +
scale_fill_identity() +
scale_y_continuous(
expand = c(0, 0, 0.05, 0)
)

Our chance of a Type I error is almost twice the significance level!
Why?
P-value using a
t-distribution
Like what you did waaaay back in your introductory stats class, when
you replace \(\sigma^2\) with its
sample statistic equivalent, the test statistic is no longer Normally
distributed.

Instead, the test stat will follow a **t-distribution* with degrees
of freedom equal to the denominator of the formula to calculate \(\hat{\sigma}^2\):
\[\hat{\sigma}^2 = \sqrt{\frac{SSE}{n -
2}}\]
So if we use \(MSE\) in place of
\(\sigma^2\), then the test statistic
will follow a t-distribution with \(n -
2\) degrees of freedom!
Histogram of the
test statistic with a t-distribution
gg_test_stat_mse_hist +
# Adding the Normal curve:
stat_function(
fun = dt,
args = list(df = sample_size - 2),
color = 'red',
linewidth = 1,
alpha = 0.5
) +
labs(
caption = paste('t-distribution with', sample_size - 2,
'df overlayed on the histogram')
)

The t-distribution fits great!
Histogram of
p-values using MSE and t-distribution
The code chunk below will calculate the p-value using the
t-distribution with df = 8:
# Finding the p-values:
sim_df <-
sim_df |>
mutate(
# Now p-value for Beta1 =\= 40 using a t-distribution
t_p_val = 2*pt(abs(test_stat_mse), df = sample_size - 2, lower.tail = F)
)
sim_df |>
dplyr::select(sample, b1, MSE, test_stat_mse, t_p_val) |>
tibble()
## # A tibble: 100,000 × 5
## sample b1 MSE test_stat_mse t_p_val
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 39.8 207. -0.246 0.812
## 2 2 41.0 415. 0.874 0.407
## 3 3 38.7 661. -0.936 0.377
## 4 4 37.9 349. -2.06 0.0735
## 5 5 40.2 299. 0.244 0.813
## 6 6 39.6 533. -0.289 0.780
## 7 7 40.4 290. 0.384 0.711
## 8 8 38.4 408. -1.48 0.176
## 9 9 40.1 458. 0.0607 0.953
## 10 10 41.2 521. 0.956 0.367
## # ℹ 99,990 more rows
Again, plotting the p-values calculated above and calculate the
probability of rejecting a true \(H_0\)
assuming the test statistic follows a t-distribution:
# Calculating the probability of a type 1 error
prob_type1_alpha_5_t <- mean(sim_df$t_p_val < 0.05)
# Graph
ggplot(
data = sim_df,
mapping = aes(
x = t_p_val,
fill = if_else(t_p_val < 0.05, 'tomato', 'steelblue'),
# group = 1
)
) +
geom_histogram(
# Need to swap from count to density on the y-axis to place a normal curve
mapping = aes(y = after_stat(count) / (m * binwidth)),
breaks = seq(0, 1, binwidth),
color = 'white'
) +
# Adding the Uniform 'curve':
stat_function(
fun = dunif,
args = list(min = 0, max = 1),
color = 'red',
linewidth = 1,
alpha = 0.5
) +
# Adding the probability of Type 1
labs(
title = 'Distribution of p-values when Ho is true, using MSE, and t-distribution',
subtitle = paste('alpha = 5% and Type I probability is',
scales::percent(prob_type1_alpha_5_t)),
caption = paste('Results from a simulation of', scales::comma(m),
'simulations each with a sample size of', sample_size),
x = 'P-value',
y = 'Density'
) +
theme_bw() +
scale_fill_identity() +
scale_y_continuous(
expand = c(0, 0, 0.05, 0)
)

Now it matches!
LS0tDQp0aXRsZTogIkRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxlIHNsb3BlIg0KYXV0aG9yOiAiQ2hhcHRlciAyIg0KZGF0ZTogIlNUQSA0MjEwIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGZpZ193aWR0aDogOA0KICAgIGZpZ19oZWlnaHQ6IDYNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIyBMb2FkaW5nIHBhY2thZ2VzIGFuZCBjcmVhdGluZyBpbiB0aGUgZGF0YSBzZXQNCg0KV2UnbGwgc3RhcnQgYnkgbG9hZGluZyB0aGUgYHRpZHl2ZXJzZWA6DQoNCmBgYHtyIHBhY2thZ2UsIGluY2x1ZGU9RiwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9DQojIFBhY2thZ2VzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQpTaW5jZSB0aGUgdmFyaWFuY2Ugb2YgdGhlIHNsb3BlLCAkYl8xJCwgZGVwZW5kcyBvbiAkU197WFh9JDoNCg0KJCRTX3tYWH0gPSBcc3VtX3tpPTF9Xm4oWF9pLVxiYXJ7WH0pXjIkJA0KDQpXZSBuZWVkIHRvIGtlZXAgdGhlICRYX2kkIHRoZSBzYW1lIHRocm91Z2hvdXQgdGhlIHNpbXVsYXRpb24gZm9yIGVhY2ggaXRlcmF0aW9uLiBXZSdsbCBrZWVwIGl0IHNpbXBsZSBhbmQgbGV0ICR4X2kgPSAyaSQgd2l0aCAkaSA9IDEsIC4uLiwgMTAkDQoNCmBgYHtyIHBvcF9kZn0NClggPC0gMiooMToxMCkNCg0KWA0KYGBgDQoNClRoZSAkU197WFh9JCBpczoNCg0KYGBge3IgU19YWH0NCiMgU19YWCA9IHN1bSAoWF9pIC0gWF9iYXIpXjINClNfWFggPC0gc3VtKChYIC0gbWVhbihYKSleMikNClNfWFgNCmBgYA0KDQpXaGVuIHBlcmZvcm1pbmcgYSBzaW11bGF0aW9uLCB3ZSBuZWVkIHRvIGNyZWF0ZSBhIG1vZGVsIHRvIGdlbmVyYXRlIG91ciBkYXRhLiBUaGUgcG9wdWxhdGlvbiBtb2RlbCBmb3Igb3VyIHNpbXVsYXRpb24gaXM6DQoNCiQkWV9pID0gMjAgKyA0MFhfaSArIFx2YXJlcHNpbG9uX2kgXFwgXHZhcmVwc2lsb25faSBcc2ltIE4oMCwgNjYwKSQkDQoNCkZvciBlYWNoIHNpbXVsYXRpb24gd2UgcnVuLCB3ZSdsbCBnZW5lcmF0ZSAkWV9pJCB1c2luZyB0aGUgbW9kZWwgYWJvdmUNCg0KIyMgVGhlb3JldGljYWwgZGlzdHJpYnV0aW9uIGZvciAkYl8xJA0KDQpBY2NvcmRpbmcgdG8gdGhlIHNsaWRlcyB3ZSBzYXcgaW4gY2xhc3MsIGFzIGxvbmcgYXMNCg0KJCRZX2kgXHNpbSBOKFxiZXRhXzAgKyBcYmV0YV8xIFhfaSwgXHNpZ21hXjIpJCQNCg0KYXJlIGFyZSBpbmRlcGVuZGVudCwgdGhlbiB0aGUgZGlzdHJpYnV0aW9uIG9mICRiXzEkIGlzOg0KDQokJGJfMSBcc2ltIE5cbGVmdChcYmV0YV8xLCBcZnJhY3tcc2lnbWFeMn17U197WFh9fVxyaWdodCkkJA0KDQpTaW5jZSB3ZSBjb250cm9sIHRoZSBwb3B1bGF0aW9uLCB3ZSBrbm93IHRoZSBkaXN0cmlidXRpb24gJGJfMSQgZm9yIG91ciBleGFtcGxlIHNob3VsZCBmb2xsb3c6DQoNCiQkYl8xIFxzaW0gTlxsZWZ0KDQwLCBcZnJhY3s2NjB9ezMzMH1ccmlnaHQpJCQNCg0KIyMgU2ltdWxhdGluZyAxMCwwMDAgc2FtcGxlcyBvZiBuID0gMTANCg0KV2UnbGwgZ2VuZXJhdGUgMTAsMDAwIHNhbXBsZXMgb2YgMTAgJFlfaSQgdmFsdWVzIGVhY2ggYmFzZWQgb24gdGhlIG1vZGVsIHN0YXRlZCBhYm92ZSwgd2hpY2ggaXMgdGhlb3JldGljYWxseSBha2luIHRvIHRha2luZyBhIHJhbmRvbSBzYW1wbGUgZnJvbSBhIHBvcHVsYXRpb24uDQoNCkZyb20gZWFjaCBzYW1wbGUsIHdlJ2xsIHNhdmUgdGhlIGZvbGxvd2luZyBpbmZvOg0KDQoxKSAgVGhlIHNhbXBsZQ0KMikgICRiXzAkDQozKSAgJGJfMSQNCjQpICAkU1NFJA0KDQpgYGB7ciBzaW1fZGZ9DQojIFNpbXVsYXRpb24gYW5kIHNhbXBsZSBzaXplcw0KbSA8LSAxZTUNCnNhbXBsZV9zaXplIDwtIDEwDQoNCiMgU2V0dGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgbW9kZWwNCmJldGEwIDwtIDIwOyBiZXRhMSA8LSA0MDsgc2lnbWEyX2UgPC0gNjYwDQoNCiMgRGF0YSBmcmFtZSB0byBzYXZlIHRoZSByZXN1bHQ6DQpzaW1fZGYgPC0gDQogIGRhdGEuZnJhbWUoDQogICAgc2FtcGxlID0gMTptLA0KICAgIGIwID0gLTEwMCwNCiAgICBiMSA9IC0xMDAsDQogICAgU1NFID0gLTENCiAgKQ0KYGBgDQoNCkJlZm9yZSB3ZSBjb25kdWN0IHRoZSBmdWxsIHNpbXVsYXRpb24sIGxldCdzIGdlbmVyYXRlIG9uZSBzYW1wbGUgYW5kIGNhbGN1bGF0ZSB0aGUgc3RhdHMgbmVlZGVkIGFzIGFuIGV4YW1wbGU6DQoNCmBgYHtyIHNhbXBsZV8xfQ0KIyMjIExldCdzIGdlbmVyYXRlIGEgcmFuZG9tIHNhbXBsZSBmb3Igc2FrZSBvZiBzaG93aW5nIGhvdzoNCnNldC5zZWVkKDQyMTApDQojIFRoZSByZXNwb25zZSBmcm9tIHRoZSBtb2RlbDoNCllfbG9vcCA8LSBiZXRhMCArIGJldGExICogWCArIA0KICAgICAgICAgICMgUmFuZG9tIGVycm9yIHRlcm0NCiAgICAgICAgICBybm9ybShzYW1wbGVfc2l6ZSwgbWVhbiA9IDAsIHNkID0gc3FydChzaWdtYTJfZSkpDQoNCiMgRmluZCBiMToNCmIxX2xvb3AgPC0gDQogICMgU19YWQ0KICBzdW0oKFggLSBtZWFuKFgpKSooWV9sb29wIC0gbWVhbihZX2xvb3ApKSkgLyBTX1hYDQoNCiMgRmluZGluZyBiMDoNCmIwX2xvb3AgPC0gbWVhbihZX2xvb3ApIC0gYjFfbG9vcCAqIG1lYW4oWCkNCg0KIyBDYWxjdWxhdGluZyB5X2hhdA0KWV9oYXRfbG9vcCA8LSBiMF9sb29wICsgYjFfbG9vcCAqIFgNCg0KIyBSZXNpZHVhbHM6DQpyZXNfbG9vcCA8LSBZX2xvb3AgLSBZX2hhdF9sb29wDQoNCiMgU1NFOg0KU1NFX2xvb3AgPC0gc3VtKHJlc19sb29wXjIpDQoNCiMgTm93IHdlJ2xsIHNhdmUgdGhlIHJlc3VsdHMgaW4gdGhlIGZpcnN0IHJvdw0Kc2ltX2RmWzEsIDI6bmNvbChzaW1fZGYpXSA8LSBjKGIwX2xvb3AsIGIxX2xvb3AsIFNTRV9sb29wKQ0KDQoNCnRpYmJsZShzaW1fZGYpDQpgYGANCg0KTm93IHdlJ2xsIGFkZCB0aGUgcmVtYWluaW5nIHNhbXBsZSBzdGF0cyB0byB0aGUgZGF0YSBmcmFtZToNCg0KYGBge3IgYWRkX3NhbXBsZXN9DQojIFBlcmZvcm1pbmcgdGhlIHNpbXVsYXRpb246DQpmb3IgKGkgaW4gMjptKXsNCiAgIyBUaGUgcmVzcG9uc2UgZnJvbSB0aGUgbW9kZWw6DQogIFlfbG9vcCA8LSBiZXRhMCArIGJldGExICogWCArIA0KICAgICAgICAgICAgIyBSYW5kb20gZXJyb3IgdGVybQ0KICAgICAgICAgICAgcm5vcm0oc2FtcGxlX3NpemUsIG1lYW4gPSAwLCBzZCA9IHNxcnQoc2lnbWEyX2UpKQ0KICANCiAgIyBGaW5kIGIxOg0KICBiMV9sb29wIDwtIHN1bSgoWCAtIG1lYW4oWCkpKihZX2xvb3AgLSBtZWFuKFlfbG9vcCkpKSAvIFNfWFgNCiAgDQogICMgRmluZGluZyBiMDoNCiAgYjBfbG9vcCA8LSBtZWFuKFlfbG9vcCkgLSBiMV9sb29wICogbWVhbihYKQ0KICANCiAgIyBDYWxjdWxhdGluZyB5X2hhdA0KICBZX2hhdF9sb29wIDwtIGIwX2xvb3AgKyBiMV9sb29wICogWA0KICANCiAgIyBSZXNpZHVhbHM6DQogIHJlc19sb29wIDwtIFlfbG9vcCAtIFlfaGF0X2xvb3ANCiAgDQogICMgU1NFOg0KICBTU0VfbG9vcCA8LSBzdW0ocmVzX2xvb3BeMikNCiAgDQogICMgTm93IHdlJ2xsIHNhdmUgdGhlIHJlc3VsdHMgaW4gdGhlIGZpcnN0IHJvdw0KICBzaW1fZGZbaSwgMjpuY29sKHNpbV9kZildIDwtIGMoYjBfbG9vcCwgYjFfbG9vcCwgU1NFX2xvb3ApDQp9DQoNCnRpYmJsZShzaW1fZGYpDQpgYGANCg0KIyMgRGlzdHJpYnV0aW9uIG9mICRiXzEkDQoNCkxldCdzIGNyZWF0ZSBhIGhpc3RvZ3JhbSBvZiBvdXIgc2ltdWxhdGVkIHNsb3BlcyBhbmQgc3VwZXJpbXBvc2UgYSBOb3JtYWwgY3VydmUgb24gaXQuDQoNClJlbWluZGVyOiBJZiB0aGUgdGhlb3J5IGlzIGNvcnJlY3QsIHRoZW46DQoNCiQkYl8xIFxzaW0gTlxsZWZ0KDQwLCBcZnJhY3s2NjB9ezMzMH1ccmlnaHQpJCQNCg0KYGBge3J9DQpnZ3Bsb3QoDQogIGRhdGEgPSBzaW1fZGYsDQogIG1hcHBpbmcgPSBhZXMoDQogICAgeCA9IGIxDQogICkNCikgKyANCiAgZ2VvbV9oaXN0b2dyYW0oDQogICAgIyBOZWVkIHRvIHN3YXAgZnJvbSBjb3VudCB0byBkZW5zaXR5IG9uIHRoZSB5LWF4aXMgdG8gcGxhY2UgYSBub3JtYWwgY3VydmUNCiAgICBtYXBwaW5nID0gYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwNCiAgICBiaW5zID0gNDAsDQogICAgZmlsbCA9ICdzdGVlbGJsdWUnLA0KICAgIGNvbG9yID0gJ3doaXRlJw0KICApICsgDQogICMgQWRkaW5nIHRoZSBOb3JtYWwgY3VydmU6DQogIHN0YXRfZnVuY3Rpb24oDQogICAgZnVuID0gZG5vcm0sDQogICAgYXJncyA9IGxpc3QobWVhbiA9IGJldGExLCBzZCA9IHNxcnQoc2lnbWEyX2UvU19YWCkpLA0KICAgIGNvbG9yID0gJ3JlZCcsDQogICAgbGluZXdpZHRoID0gMSwNCiAgICBhbHBoYSA9IDAuNQ0KICApICsgDQogIHRoZW1lX2J3KCkgICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICdIaXN0b2dyYW0gb2Ygc2ltdWxhdGVkIHNsb3BlcycNCiAgKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgZXhwYW5kID0gYygwLCAwLCAwLjA1LCAwKQ0KICApDQogIA0KYGBgDQoNCkhpc3RvZ3JhbSBsb29rcyBwcmV0dHkgYWNjdXJhdGUhDQoNCldoYXQgYWJvdXQgdGhlIHRlc3Qgc3RhdGlzdGljcyBhbmQgcC12YWx1ZXM/IERvIHRoZXkgJ2xpbmUgdXAnIHdpdGggd2hhdCB0aGUgdGhlb3J5IHNheXM/DQoNCioqUmVzdWx0Kio6IElmICRIXzAkIGlzIHRydWUsIHRoZW4gdGhlIHAtdmFsdWUgaXMgYSByYW5kb20gdmFyaWFibGUgdGhhdCBmb2xsb3dzIGEgdW5pZm9ybSBkaXN0cmlidXRpb24gYmV0d2VlbiAwIGFuZCAxOg0KDQokJFx0ZXh0e3AtdmFsfSB8IEhfMCBcc2ltIFx0ZXh0e1VuaWZvcm19KDAsIDEpJCQNCg0KIyMjIFR5cGUgSSBlcnJvciByYXRlOiAkXHNpZ21hXjIkIGtub3duDQoNClNvIGlmIHdlIGNhbGN1bGF0ZSB0aGUgdGVzdCBzdGF0aXN0aWMgYW5kIHAtdmFsdWUgZm9yIGFsbCBvZiBvdXIgc2ltdWxhdGVkIHNhbXBsZXMsIHRoZW4gNSUgb2Ygb3VyIHNhbXBsZXMgc2hvdWxkIGdpdmUgdXMgYSBwLXZhbHVlIGJlbG93IDAuMDUgKG9yIHdoYXRldmVyIHNpZ25pZmljYW5jZSBsZXZlbCB5b3UgY2hvb3NlKQ0KDQokJFAoXHRleHR7cC12YWx9IDwgXGFscGhhKSA9IFxhbHBoYSQkDQoNCmBgYHtyIHBfdmFsX3NpbV9zaWdtYV9rbm93bn0NCiMgRmluZGluZyB0aGUgcC12YWx1ZXM6DQpzaW1fZGYgPC0gDQogIHNpbV9kZiB8Pg0KICBtdXRhdGUoDQogICAgIyBUZXN0IHN0YXRpc3RpYw0KICAgIHRlc3Rfc3RhdCA9IChiMSAtIGJldGExKSAvIHNxcnQoc2lnbWEyX2UvU19YWCksDQogICAgIyBOb3cgcC12YWx1ZSBmb3IgQmV0YTEgPVw9IDQwDQogICAgcF92YWxfc2lnbWEgPSAyKnBub3JtKGFicyh0ZXN0X3N0YXQpLCBsb3dlci50YWlsID0gRikNCiAgKQ0KDQpzaW1fZGYgfD4NCiAgZHBseXI6OnNlbGVjdChzYW1wbGUsIGIxLCB0ZXN0X3N0YXQsIHBfdmFsX3NpZ21hKSB8Pg0KICB0aWJibGUoKQ0KYGBgDQoNCkxldCdzIHBsb3QgdGhlbSBhbmQgY2FsY3VsYXRlIHRoZSBwcm9iYWJpbGl0eSBvZiByZWplY3RpbmcgYSB0cnVlICRIXzAkOg0KDQpgYGB7ciBwX3ZhbF9wbG90LCB3YXJuaW5nID0gRn0NCiMgQ2FsY3VsYXRpbmcgdGhlIHByb2JhYmlsaXR5IG9mIGEgdHlwZSAxIGVycm9yDQpwcm9iX3R5cGUxX2FscGhhXzUgPC0gbWVhbihzaW1fZGYkcF92YWxfc2lnbWEgPCAwLjA1KQ0KDQojIEhvdyB3aWRlIHRvIG1ha2UgZWFjaCBiaW4NCmJpbndpZHRoID0gMC4wMQ0KDQpnZ3Bsb3QoDQogIGRhdGEgPSBzaW1fZGYsDQogIG1hcHBpbmcgPSBhZXMoDQogICAgeCA9IHBfdmFsX3NpZ21hLA0KICAgIGZpbGwgPSBpZl9lbHNlKHBfdmFsX3NpZ21hIDwgMC4wNSwgJ3RvbWF0bycsICdzdGVlbGJsdWUnKQ0KICApDQopICsgDQogIGdlb21faGlzdG9ncmFtKA0KICAgICMgTmVlZCB0byBzd2FwIGZyb20gY291bnQgdG8gZGVuc2l0eSBvbiB0aGUgeS1heGlzIHRvIHBsYWNlIGEgbm9ybWFsIGN1cnZlDQogICAgbWFwcGluZyA9IGFlcyh5ID0gYWZ0ZXJfc3RhdChjb3VudCkgLyAobSAqIGJpbndpZHRoKSksDQogICAgYnJlYWtzID0gc2VxKDAsIDEsIGJpbndpZHRoKSwNCiAgICAjZmlsbCA9ICdzdGVlbGJsdWUnLA0KICAgIGNvbG9yID0gJ3doaXRlJw0KICApICsgDQogICMgQWRkaW5nIHRoZSBVbmlmb3JtICdjdXJ2ZSc6DQogIHN0YXRfZnVuY3Rpb24oDQogICAgZnVuID0gZHVuaWYsDQogICAgYXJncyA9IGxpc3QobWluID0gMCwgbWF4ID0gMSksDQogICAgY29sb3IgPSAncmVkJywNCiAgICBsaW5ld2lkdGggPSAxLA0KICAgIGFscGhhID0gMC41DQogICkgKyANCiAgIyBBZGRpbmcgdGhlIHByb2JhYmlsaXR5IG9mIFR5cGUgMQ0KICBsYWJzKA0KICAgIHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBwLXZhbHVlcyB3aGVuIEhvIGlzIHRydWUgYW5kIHNpZ21hIGlzIGtub3duJywNCiAgICBzdWJ0aXRsZSA9IHBhc3RlKCdXaGVuIGFscGhhID0gNSUgdGhlIGNoYW5jZSBvZiBUeXBlIEkgZXJyb3IgaXMnLCANCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlczo6cGVyY2VudChwcm9iX3R5cGUxX2FscGhhXzUpKSwNCiAgICBjYXB0aW9uID0gcGFzdGUoJ1Jlc3VsdHMgZnJvbSBhIHNpbXVsYXRpb24gb2YnLCBzY2FsZXM6OmNvbW1hKG0pLCANCiAgICAgICAgICAgICAgICAgICAgJ3NpbXVsYXRpb25zIGVhY2ggd2l0aCBhIHNhbXBsZSBzaXplIG9mJywgc2FtcGxlX3NpemUpLA0KICAgIHggPSAnUC12YWx1ZScsDQogICAgeSA9ICdEZW5zaXR5Jw0KICApICsNCiAgdGhlbWVfYncoKSAgKw0KICBzY2FsZV9maWxsX2lkZW50aXR5KCkgKyANCiAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgIGV4cGFuZCA9IGMoMCwgMCwgMC4wNSwgMCkNCiAgKQ0KYGBgDQoNClRoZSBkaXN0cmlidXRpb24gYWJvdmUgYXNzdW1lcyB3ZSBrbm93IHdoYXQgJFxzaWdtYV4yJCBpcywgd2hpY2ggd2UgdXN1YWxseSBkb24ndC4gV2hhdCBoYXBwZW5zIGlmIHdlIHN3YXAgJFxzaWdtYV4yJCB3aXRoIHRoZSBNU0U/DQoNCg0KDQoNCiMjIyBUeXBlIEkgZXJyb3IgcmF0ZTogJFxzaWdtYV4yJCAqKnVua25vd24qKg0KDQpJbnN0ZWFkIG9mIHVzaW5nIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgJGJfMSQsIHdlJ2xsIGhhdmUgdG8gdXNlIHRoZSBzdGFuZGFyZCBlcnJvcjoNCg0KJCRTRShiXzEpID0gXHNxcnR7XGZyYWN7TVNFfXtTX3tYWH19fSQkDQoNCldlIGNhbiBjYWxjdWxhdGUgdGhlICRNU0UkIGZvciBlYWNoIHNhbXBsZSBieToNCg0KJCRNU0UgPSBcZnJhY3tTU0V9e24tMn0kJA0KDQpTbyBsZXQncyBmaW5kIHRoZSBTdGFuZGFyZCBlcnJvciwgdGVzdCBzdGF0LCBhbmQgcC12YWx1ZSB1c2luZyB0aGUgJE1TRSQ6DQoNCiQkeiA9IFxmcmFje2JfMSAtIFxiZXRhX3sxLDB9fXtcc3FydHtcZnJhY3tNU0V9e1Nfe1hYfX19fSQkDQoNCmBgYHtyIHBfdmFsX3NpbV9NU0V9DQojIEZpbmRpbmcgdGhlIHAtdmFsdWVzOg0Kc2ltX2RmIDwtIA0KICBzaW1fZGYgfD4NCiAgbXV0YXRlKA0KICAgIE1TRSA9IFNTRSAvIChzYW1wbGVfc2l6ZSAtIDIpLA0KICAgICMgVGVzdCBzdGF0aXN0aWMgdXNpbmcgbXNlDQogICAgdGVzdF9zdGF0X21zZSA9IChiMSAtIGJldGExKSAvIHNxcnQoTVNFL1NfWFgpLA0KICAgICMgTm93IHAtdmFsdWUgZm9yIEJldGExID1cPSA0MA0KICAgIHBfdmFsX21zZSA9IDIqcG5vcm0oYWJzKHRlc3Rfc3RhdF9tc2UpLCBsb3dlci50YWlsID0gRikNCiAgKQ0KDQpzaW1fZGYgfD4NCiAgZHBseXI6OnNlbGVjdChzYW1wbGUsIGIxLCBNU0UsIHRlc3Rfc3RhdF9tc2UsIHBfdmFsX21zZSkgfD4NCiAgdGliYmxlKCkNCmBgYA0KDQojIyMjIFBsb3Qgb2YgdGhlIHRlc3Qgc3RhdGlzdGljIHVzaW5nIE1TRSBpbnN0ZWFkIG9mICRcc2lnbWFeMiQNCg0KVGhlIGhpc3RvZ3JhbSBvZiB0aGUgdGVzdCBzdGF0aXN0aWMgaXMgc2hvd24gYmVsb3cuIERvZXMgaXQgbG9vayBsaWtlIHRoZSBTdGFuZGFyZCBOb3JtYWwgZGlzdHJpYnV0aW9uIGZpdCB0aGUgaGlzdG9ncmFtPw0KDQpgYGB7ciB0ZXN0X3N0YXRfaGlzdF9tc2Vfbm9ybWFsfQ0KZ2dfdGVzdF9zdGF0X21zZV9oaXN0IDwtIA0KICBnZ3Bsb3QoDQogICAgIyBUaGVyZSBhcmUgYSBmZXcgZXh0cmVtZSB2YWx1ZXMsIHNvIHdlJ2xsIG9ubHkgbG9vayBhdCAtNSA8IHogPCA1DQogICAgZGF0YSA9IHNpbV9kZiB8Pg0KICAgICAgZmlsdGVyKGJldHdlZW4odGVzdF9zdGF0X21zZSwgLTUsIDUpKSwNCiAgICBtYXBwaW5nID0gYWVzKA0KICAgICAgeCA9IHRlc3Rfc3RhdF9tc2UNCiAgICApDQogICkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oDQogICAgIyBOZWVkIHRvIHN3YXAgZnJvbSBjb3VudCB0byBkZW5zaXR5IG9uIHRoZSB5LWF4aXMgdG8gcGxhY2UgYSBub3JtYWwgY3VydmUNCiAgICBtYXBwaW5nID0gYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwNCiAgICBiaW5zID0gNDAsDQogICAgZmlsbCA9ICdzdGVlbGJsdWUnLA0KICAgIGNvbG9yID0gJ3doaXRlJw0KICApICsgDQogIHRoZW1lX2J3KCkgICsNCiAgbGFicygNCiAgICB0aXRsZSA9IHBhc3RlKCdIaXN0b2dyYW0gb2YnLCBzY2FsZXM6OmNvbW1hKG0pLCAndGVzdCBzdGF0aXN0aWNzIGZvciB0aGUgc2xvcGUnKSwNCiAgICBzdWJ0aXRsZSA9ICdDYWxjdWxhdGVkIHVzaW5nIHRoZSBNU0UnLA0KICAgIHggPSAnVGVzdCBzdGF0aXN0aWNzJw0KICApICsgDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBleHBhbmQgPSBjKDAsIDAsIDAuMDUsIDApDQogICkgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IC01OjUNCiAgKQ0KDQoNCmdnX3Rlc3Rfc3RhdF9tc2VfaGlzdCArIA0KICAjIEFkZGluZyB0aGUgTm9ybWFsIGN1cnZlOg0KICBzdGF0X2Z1bmN0aW9uKA0KICAgIGZ1biA9IGRub3JtLA0KICAgIGFyZ3MgPSBsaXN0KG1lYW4gPSAwLCBzZCA9IDEpLA0KICAgIGNvbG9yID0gJ3JlZCcsDQogICAgbGluZXdpZHRoID0gMSwNCiAgICBhbHBoYSA9IDAuNQ0KICApICsgDQogIGxhYnMoDQogICAgY2FwdGlvbiA9ICdTdGFuZGFyZCBOb3JtYWwgRGlzdHJpYnV0aW9uIE92ZXJsYXllZCBvbiB0aGUgSGlzdG9ncmFtJw0KICApDQpgYGANCg0KVGhlIE5vcm1hbCBjdXJ2ZSBsb29rcyBjbG9zZSwgYnV0IHRoZSBtaWRkbGUgYmFycyBhcmUgY29uc2lzdGVudGx5IGJlbG93IHRoZSBsaW5lIHdoaWxlIHRoZSB0YWlscyBhcmUgYWJvdmUgdGhlIGxpbmUuIFRoYXQgdHlwaWNhbGx5IGluZGljYXRlcyB0aGF0IGEgd2lkZXIgZGlzdHJpYnV0aW9uIGlzIG5lZWRlZCBpbnN0ZWFkIG9mIGEgTm9ybWFsIGRpc3RyaWJ1dGlvbi4NCg0KTGV0J3MgY2hlY2sgdGhlIHAtdmFsdWVzIGFzIHdlbGwhDQoNCiMjIyMgUGxvdCBvZiB0aGUgcC12YWx1ZXMgdXNpbmcgTVNFIGFuZCBOb3JtYWwgZGlzdHJpYnV0aW9uDQoNCkFnYWluLCBwbG90dGluZyB0aGVtIGFuZCBjYWxjdWxhdGUgdGhlIHByb2JhYmlsaXR5IG9mIHJlamVjdGluZyBhIHRydWUgJEhfMCQgYXNzdW1pbmcgdGhlIHRlc3Qgc3RhdGlzdGljIGZvbGxvd3MgYSBTdGFuZGFyZCBOb3JtYWw6DQoNCmBgYHtyIHBfdmFsX3Bsb3RfbXNlLCB3YXJuaW5nID0gRn0NCiMgQ2FsY3VsYXRpbmcgdGhlIHByb2JhYmlsaXR5IG9mIGEgdHlwZSAxIGVycm9yDQpwcm9iX3R5cGUxX2FscGhhXzVfbXNlIDwtIG1lYW4oc2ltX2RmJHBfdmFsX21zZSA8IDAuMDUpDQoNCiMgQ3JlYXRpbmcgdGhlIGdyYXBoDQpnZ3Bsb3QoDQogIGRhdGEgPSBzaW1fZGYsDQogIG1hcHBpbmcgPSBhZXMoDQogICAgeCA9IHBfdmFsX21zZSwNCiAgICBmaWxsID0gaWZfZWxzZShwX3ZhbF9tc2UgPCAwLjA1LCAndG9tYXRvJywgJ3N0ZWVsYmx1ZScpLA0KICAgIyBncm91cCA9IDENCiAgKQ0KKSArIA0KICBnZW9tX2hpc3RvZ3JhbSgNCiAgICAjIE5lZWQgdG8gc3dhcCBmcm9tIGNvdW50IHRvIGRlbnNpdHkgb24gdGhlIHktYXhpcyB0byBwbGFjZSBhIG5vcm1hbCBjdXJ2ZQ0KICAgIG1hcHBpbmcgPSBhZXMoeSA9IGFmdGVyX3N0YXQoY291bnQpIC8gKG0gKiBiaW53aWR0aCkpLA0KICAgIGJyZWFrcyA9IHNlcSgwLCAxLCBiaW53aWR0aCksDQogICAgY29sb3IgPSAnd2hpdGUnDQogICkgKyANCiAgIyBBZGRpbmcgdGhlIFVuaWZvcm0gJ2N1cnZlJzoNCiAgc3RhdF9mdW5jdGlvbigNCiAgICBmdW4gPSBkdW5pZiwNCiAgICBhcmdzID0gbGlzdChtaW4gPSAwLCBtYXggPSAxKSwNCiAgICBjb2xvciA9ICdyZWQnLA0KICAgIGxpbmV3aWR0aCA9IDEsDQogICAgYWxwaGEgPSAwLjUNCiAgKSArIA0KICAjIEFkZGluZyB0aGUgcHJvYmFiaWxpdHkgb2YgVHlwZSAxDQogIGxhYnMoDQogICAgdGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHAtdmFsdWVzIHdoZW4gSDAgaXMgdHJ1ZSwgdXNpbmcgYSBOb3JtYWwgd2l0aCBzaWdtYSB1bmtub3duJywNCiAgICBzdWJ0aXRsZSA9IHBhc3RlKCdhbHBoYSA9IDUlIGFuZCBUeXBlIEkgcHJvYmFiaWxpdHkgaXMnLCANCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlczo6cGVyY2VudChwcm9iX3R5cGUxX2FscGhhXzVfbXNlKSksDQogICAgY2FwdGlvbiA9IHBhc3RlKCdSZXN1bHRzIGZyb20gYSBzaW11bGF0aW9uIG9mJywgc2NhbGVzOjpjb21tYShtKSwgDQogICAgICAgICAgICAgICAgICAgICdzaW11bGF0aW9ucyBlYWNoIHdpdGggYSBzYW1wbGUgc2l6ZSBvZicsIHNhbXBsZV9zaXplKSwNCiAgICB4ID0gJ1AtdmFsdWUnLA0KICAgIHkgPSAnRGVuc2l0eScNCiAgKSArDQogIHRoZW1lX2J3KCkgICsNCiAgc2NhbGVfZmlsbF9pZGVudGl0eSgpICsgDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBleHBhbmQgPSBjKDAsIDAsIDAuMDUsIDApDQogICkNCmBgYA0KDQpPdXIgY2hhbmNlIG9mIGEgVHlwZSBJIGVycm9yIGlzIGFsbW9zdCB0d2ljZSB0aGUgc2lnbmlmaWNhbmNlIGxldmVsISBXaHk/DQoNCiMjIyBQLXZhbHVlIHVzaW5nIGEgdC1kaXN0cmlidXRpb24NCg0KTGlrZSB3aGF0IHlvdSBkaWQgd2FhYWF5IGJhY2sgaW4geW91ciBpbnRyb2R1Y3Rvcnkgc3RhdHMgY2xhc3MsIHdoZW4geW91IHJlcGxhY2UgJFxzaWdtYV4yJCB3aXRoIGl0cyBzYW1wbGUgc3RhdGlzdGljIGVxdWl2YWxlbnQsIHRoZSB0ZXN0IHN0YXRpc3RpYyBpcyBubyBsb25nZXIgTm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCiFbXShodHRwczovL2VuY3J5cHRlZC10Ym4wLmdzdGF0aWMuY29tL2ltYWdlcz9xPXRibjpBTmQ5R2NRM2Y5SWc3QjVuZGRQdHVwYTlDc1hCbjVrV3dsWDh4U2lEMnBPaDRNTC1GQmlKTGJLUzhiYU1sam8mcz0xMCl7d2lkdGg9IjUwJSIgaGVpZ2h0PSI1MCUifQ0KDQpJbnN0ZWFkLCB0aGUgdGVzdCBzdGF0IHdpbGwgZm9sbG93IGEgXCpcKnQtZGlzdHJpYnV0aW9uXCogd2l0aCBkZWdyZWVzIG9mIGZyZWVkb20gZXF1YWwgdG8gdGhlIGRlbm9taW5hdG9yIG9mIHRoZSBmb3JtdWxhIHRvIGNhbGN1bGF0ZSAkXGhhdHtcc2lnbWF9XjIkOg0KDQokJFxoYXR7XHNpZ21hfV4yID0gXHNxcnR7XGZyYWN7U1NFfXtuIC0gMn19JCQNCg0KU28gaWYgd2UgdXNlICRNU0UkIGluIHBsYWNlIG9mICRcc2lnbWFeMiQsIHRoZW4gdGhlIHRlc3Qgc3RhdGlzdGljIHdpbGwgZm9sbG93IGEgdC1kaXN0cmlidXRpb24gd2l0aCAkbiAtIDIkIGRlZ3JlZXMgb2YgZnJlZWRvbSENCg0KIyMjIyBIaXN0b2dyYW0gb2YgdGhlIHRlc3Qgc3RhdGlzdGljIHdpdGggYSB0LWRpc3RyaWJ1dGlvbg0KDQpgYGB7ciB0ZXN0X3N0YXRfdF9kaXN0fQ0KZ2dfdGVzdF9zdGF0X21zZV9oaXN0ICsgDQogICMgQWRkaW5nIHRoZSBOb3JtYWwgY3VydmU6DQogIHN0YXRfZnVuY3Rpb24oDQogICAgZnVuID0gZHQsDQogICAgYXJncyA9IGxpc3QoZGYgPSBzYW1wbGVfc2l6ZSAtIDIpLA0KICAgIGNvbG9yID0gJ3JlZCcsDQogICAgbGluZXdpZHRoID0gMSwNCiAgICBhbHBoYSA9IDAuNQ0KICApICsgDQogIGxhYnMoDQogICAgY2FwdGlvbiA9IHBhc3RlKCd0LWRpc3RyaWJ1dGlvbiB3aXRoJywgc2FtcGxlX3NpemUgLSAyLCANCiAgICAgICAgICAgICAgICAgICAgJ2RmIG92ZXJsYXllZCBvbiB0aGUgaGlzdG9ncmFtJykNCiAgKQ0KYGBgDQoNClRoZSB0LWRpc3RyaWJ1dGlvbiBmaXRzIGdyZWF0IQ0KDQojIyMjIEhpc3RvZ3JhbSBvZiBwLXZhbHVlcyB1c2luZyBNU0UgYW5kIHQtZGlzdHJpYnV0aW9uDQoNClRoZSBjb2RlIGNodW5rIGJlbG93IHdpbGwgY2FsY3VsYXRlIHRoZSBwLXZhbHVlIHVzaW5nIHRoZSB0LWRpc3RyaWJ1dGlvbiB3aXRoIGRmID0gODoNCg0KYGBge3IgcF92YWxfc2ltX3RkaXN0fQ0KIyBGaW5kaW5nIHRoZSBwLXZhbHVlczoNCnNpbV9kZiA8LSANCiAgc2ltX2RmIHw+DQogIG11dGF0ZSgNCiAgICAjIE5vdyBwLXZhbHVlIGZvciBCZXRhMSA9XD0gNDAgdXNpbmcgYSB0LWRpc3RyaWJ1dGlvbg0KICAgIHRfcF92YWwgPSAyKnB0KGFicyh0ZXN0X3N0YXRfbXNlKSwgZGYgPSBzYW1wbGVfc2l6ZSAtIDIsIGxvd2VyLnRhaWwgPSBGKQ0KICApDQoNCnNpbV9kZiB8Pg0KICBkcGx5cjo6c2VsZWN0KHNhbXBsZSwgYjEsIE1TRSwgdGVzdF9zdGF0X21zZSwgdF9wX3ZhbCkgfD4NCiAgdGliYmxlKCkNCmBgYA0KDQpBZ2FpbiwgcGxvdHRpbmcgdGhlIHAtdmFsdWVzIGNhbGN1bGF0ZWQgYWJvdmUgYW5kIGNhbGN1bGF0ZSB0aGUgcHJvYmFiaWxpdHkgb2YgcmVqZWN0aW5nIGEgdHJ1ZSAkSF8wJCBhc3N1bWluZyB0aGUgdGVzdCBzdGF0aXN0aWMgZm9sbG93cyBhIHQtZGlzdHJpYnV0aW9uOg0KDQpgYGB7ciBwX3ZhbF9wbG90X3RkaXN0LCB3YXJuaW5nID0gRn0NCiMgQ2FsY3VsYXRpbmcgdGhlIHByb2JhYmlsaXR5IG9mIGEgdHlwZSAxIGVycm9yDQpwcm9iX3R5cGUxX2FscGhhXzVfdCA8LSBtZWFuKHNpbV9kZiR0X3BfdmFsIDwgMC4wNSkNCg0KIyBHcmFwaA0KZ2dwbG90KA0KICBkYXRhID0gc2ltX2RmLA0KICBtYXBwaW5nID0gYWVzKA0KICAgIHggPSB0X3BfdmFsLA0KICAgIGZpbGwgPSBpZl9lbHNlKHRfcF92YWwgPCAwLjA1LCAndG9tYXRvJywgJ3N0ZWVsYmx1ZScpLA0KICAgIyBncm91cCA9IDENCiAgKQ0KKSArIA0KICBnZW9tX2hpc3RvZ3JhbSgNCiAgICAjIE5lZWQgdG8gc3dhcCBmcm9tIGNvdW50IHRvIGRlbnNpdHkgb24gdGhlIHktYXhpcyB0byBwbGFjZSBhIG5vcm1hbCBjdXJ2ZQ0KICAgIG1hcHBpbmcgPSBhZXMoeSA9IGFmdGVyX3N0YXQoY291bnQpIC8gKG0gKiBiaW53aWR0aCkpLA0KICAgIGJyZWFrcyA9IHNlcSgwLCAxLCBiaW53aWR0aCksDQogICAgY29sb3IgPSAnd2hpdGUnDQogICkgKyANCiAgIyBBZGRpbmcgdGhlIFVuaWZvcm0gJ2N1cnZlJzoNCiAgc3RhdF9mdW5jdGlvbigNCiAgICBmdW4gPSBkdW5pZiwNCiAgICBhcmdzID0gbGlzdChtaW4gPSAwLCBtYXggPSAxKSwNCiAgICBjb2xvciA9ICdyZWQnLA0KICAgIGxpbmV3aWR0aCA9IDEsDQogICAgYWxwaGEgPSAwLjUNCiAgKSArIA0KICAjIEFkZGluZyB0aGUgcHJvYmFiaWxpdHkgb2YgVHlwZSAxDQogIGxhYnMoDQogICAgdGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHAtdmFsdWVzIHdoZW4gSG8gaXMgdHJ1ZSwgdXNpbmcgTVNFLCBhbmQgdC1kaXN0cmlidXRpb24nLA0KICAgIHN1YnRpdGxlID0gcGFzdGUoJ2FscGhhID0gNSUgYW5kIFR5cGUgSSBwcm9iYWJpbGl0eSBpcycsIA0KICAgICAgICAgICAgICAgICAgICAgc2NhbGVzOjpwZXJjZW50KHByb2JfdHlwZTFfYWxwaGFfNV90KSksDQogICAgY2FwdGlvbiA9IHBhc3RlKCdSZXN1bHRzIGZyb20gYSBzaW11bGF0aW9uIG9mJywgc2NhbGVzOjpjb21tYShtKSwgDQogICAgICAgICAgICAgICAgICAgICdzaW11bGF0aW9ucyBlYWNoIHdpdGggYSBzYW1wbGUgc2l6ZSBvZicsIHNhbXBsZV9zaXplKSwNCiAgICB4ID0gJ1AtdmFsdWUnLA0KICAgIHkgPSAnRGVuc2l0eScNCiAgKSArDQogIHRoZW1lX2J3KCkgICsNCiAgc2NhbGVfZmlsbF9pZGVudGl0eSgpICsgDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBleHBhbmQgPSBjKDAsIDAsIDAuMDUsIDApDQogICkNCmBgYA0KDQpOb3cgaXQgbWF0Y2hlcyENCg==