Testing Overfitting/Underfitting
In Machine Learning and Statistics, overfitting occurs when a model
is too complex and learns noise, leading to poor performance on new
data, while underfitting happens when a model is too simple to capture
important patterns, resulting in high errors overall; both issues are
explained by the Bias–Variance Tradeoff and can cause unreliable
predictions in real-world applications.
The probability density function (PDF) of the Weibull distribution
is:
\[
f(t; \lambda, \beta) = \frac{\beta}{\lambda} \left( \frac{t}{\lambda}
\right)^{\beta-1} \exp\left[ -\left( \frac{t}{\lambda} \right)^\beta
\right], \quad t \ge 0
\] where \(\lambda > 0\) is
the scale parameter (characteristic life) and \(\beta > 0\) is the shape parameter.
When \(\beta = 1\), the Weibull PDF
simplifies to the exponential PDF:
\[
f(t; \lambda) = \frac{1}{\lambda} \exp\left( -\frac{t}{\lambda} \right)
\] with constant hazard rate \(h(t) =
1/\lambda\).
This assignment focuses on performing a
hypothesis test for the shape parameter (\(\beta\)) of the Weibull distribution within
a reliability mode
\[\begin{align}
H_0&: \beta = 1 \quad \text{(Exponential model, simpler)} \\
H_1&: \beta \neq 1 \quad \text{(Weibull model, more complex)}
\end{align}\]
Question: Reliability Application
A mid-sized manufacturing company producing industrial conveyor
systems began experiencing unexpected downtime in one of its
distribution facilities, prompting concern about the reliability of a
newly sourced batch of ball bearings used in the motor assemblies. These
bearings, supplied by a vendor adopting cost-saving production methods,
were installed across multiple units operating under continuous load
conditions. After several months, maintenance logs revealed a pattern of
increasing failures, with components lasting anywhere from a few dozen
to over 150 hours before breakdown. To investigate, the engineering team
collected time-to-failure data from 50 identical bearings and conducted
a Weibull analysis within the framework of Reliability Engineering. The
50 time-to-failure (survival time) are:
12.4, 18.7, 25.3, 30.1, 33.5, 35.2, 38.9, 40.3, 42.7, 45.1, 47.6, 49.8, 52.4, 55.0,
57.3, 60.2, 62.8, 65.1, 67.9, 70.5, 72.3, 75.6, 78.2, 80.9, 83.4, 85.7, 88.1, 90.6,
93.2, 95.8, 98.4, 101.0, 104.5, 107.3, 110.6, 113.2, 116.8, 120.1, 123.7, 127.4,
130.9, 134.5, 138.2, 142.0, 146.3, 150.7, 155.2, 160.8, 168.4, 175.9
This assignment focuses on hypothesis \(H_0: \beta = 1\) (exponential) against
\(H_1: \beta \neq 1\) (Weibull). This
framework detects overfitting (fitting a Weibull when exponential is
true) and underfitting (fitting exponential when Weibull with \(\beta \neq 1\) is true).
a). Find the MLE of the Weibull parameters \(\lambda\) (scale) and \(\beta\) (shape), denoted by \(\hat{\lambda}\) and \(\hat{\beta}\), respectively, using the
optim() procedure. [Hint: You should provide explicit
expressions for the log-likelihood and gradient functions of the Weibull
distribution parameters.]
Answer to Question 1 Part A
We are provided with the probability density function (PDF) of the
Weibull distribution:
\[
f(t; \lambda, \beta) = \frac{\beta}{\lambda} \left( \frac{t}{\lambda}
\right)^{\beta-1} \exp\left[ -\left( \frac{t}{\lambda} \right)^\beta
\right], \quad t \ge 0
\]
We can use this to find the likelihood function:
\[
L(\lambda, \beta)=\prod_{i=1}^nf(t_i ; \lambda, \beta)=\prod_{i=1}^n
\frac{\beta}{\lambda} \left( \frac{t_i}{\lambda} \right)^{\beta-1}
\exp\left[ -\left( \frac{t_i}{\lambda} \right)^\beta \right]
\]
Therefore the log-likelihood function is:
$$
\[\begin{aligned}
\ell(\lambda, \beta) &= \log(L(\lambda, \beta)) \\
&=
\sum_{i=1}^n\left[\log\beta-\log\lambda+(\beta-1)\log(t_i/\lambda)-(t_i/\lambda)^\beta\right]
\\
&= n\log\beta-n\log\lambda+(\beta-1)\sum_{i=1}^n\log
t_i-\sum_{i=1}^n(t_i/\lambda)^\beta
\end{aligned}\]
$$
Using the log-likelihood function we can take the partial derivatives
of \(\lambda\) and \(\beta\) to find the gradient functions:
$$ =-+_{i=1}n(t_i/)\
=-n+_{i=1}nt_i-{i=1}^nt_i-{i=1}n(t_i/)^(t_i/)
$$
We can then use our log-likelihood function and gradient functions to
find \(\hat{\lambda}\) and \(\hat{\beta}\):
bearings <- c(12.4, 18.7, 25.3, 30.1, 33.5, 35.2, 38.9, 40.3, 42.7, 45.1, 47.6, 49.8, 52.4, 55.0,
57.3, 60.2, 62.8, 65.1, 67.9, 70.5, 72.3, 75.6, 78.2, 80.9, 83.4, 85.7, 88.1, 90.6,
93.2, 95.8, 98.4, 101.0, 104.5, 107.3, 110.6, 113.2, 116.8, 120.1, 123.7, 127.4,
130.9, 134.5, 138.2, 142.0, 146.3, 150.7, 155.2, 160.8, 168.4, 175.9)
loglik_weibull <- function(par, x){ #Used to impute log-likelihood
lambda <- par[1]
beta <- par[2]
if (lambda <= 0 || beta <= 0) return (Inf)
n <- length(x)
ll <- n*log(beta)-n*beta*log(lambda)+(beta-1)*sum(log(x))-sum((x/lambda)^beta)
return(-ll)
}
grad_weibull <- function(par, x){ #Used to impute gradient functions
lambda <- par[1]
beta <- par[2]
if (lambda <= 0 || beta <= 0) return (c(Inf, Inf))
n <- length(x)
term <- (x/lambda)^beta
d_lambda <- -n*beta/lambda+(beta/lambda)*sum(term)
d_beta <- n/beta-n*log(lambda)+sum(log(x))-sum(term*log(x/lambda))
return(-c(d_lambda, d_beta))
}
result <- optim( #Used to compute MLEs
par=c(1,1),
fn=loglik_weibull,
gr=grad_weibull,
x=bearings,
method="L-BFGS-B",
lower=c(1e-6, 1e-6)
)
result
$par
[1] 99.020320 2.206001
$value
[1] 256.4198
$counts
function gradient
26 26
$convergence
[1] 0
$message
[1] "CONVERGENCE: REL_REDUCTION_OF_F <= FACTR*EPSMCH"
lambda_hat <- result$par[1] #Gets MLEs from optim function
beta_hat <- result$par[2]
lambda_hat
[1] 99.02032
[1] 2.206001
The MLE of the Weibull parameters are \(\hat{\lambda}=99.02032\) and \(\hat{\beta}=2.206001\).
b). Find the MLE of the exponential parameter \(\lambda\) (scale), denoted by \(\hat{\lambda}\), using any procedure.
[Hint: You should provide explicit expressions for the
log-likelihood and gradient functions of the exponential distribution
parameters.]
Answer to Question 1 Part B
We are provided with the probability density function (PDF) of the
Weibull distribution when \(\beta=1\):
\[
f(t; \lambda) = \frac{1}{\lambda} \exp\left( -\frac{t}{\lambda} \right)
\]
We can use this to find the likelihood function:
\[
L(\lambda)=\prod_{i=1}^nf(t;
\lambda)=\prod_{i=1}^n\frac{1}{\lambda}e^{-t_i/\lambda}
\]
Then we can find the log-likelihood function:
\[
\ell(\lambda)=\log
L(\lambda)=\sum_{i=1}^n\left[-\log\lambda-\frac{t_i}{\lambda}\right] =
-n\log\lambda-\frac{1}{\lambda}\sum_{i=1}^n t_i
\]
We can then find the gradient function and solve for \(\hat{\lambda}\):
$$
\[\begin{aligned}
&\frac{\partial\ell}{\partial\lambda}=-\frac{n}{\lambda}+\frac{1}{\lambda^2}\sum_{i=1}^n
t_i \\
&\Rightarrow -\frac{n}{\lambda}+\frac{1}{\lambda^2}\sum_{i=1}^n
t_i=0 \\
&\Rightarrow -n\lambda+\sum_{i=1}^n t_i =0 \\
&\Rightarrow \lambda=\frac{1}{n}\sum_{i=1}^n t_i
\end{aligned}\]
$$
Therefore,
\[
\hat{\lambda}=\frac{1}{n}\sum_{i=1}^n t_i
\]
We can use this to find \(\hat{\lambda}\):
lambda_hat2 = mean(bearings) #Gets lambda MLE
lambda_hat2
[1] 87.61
The MLE of the Weibull parameter when \(\beta=1\) is \(\hat{\lambda}=87.61\).
c). Perform the likelihood ratio \(\chi^2\) test on \(\beta = 1\). What is the p-value?
[Hint: Use the results in a) and b).]
Answer to Question 1 Part C
ll_weibull <- function(x, lambda, beta){ #Computes Weibull log-likelihood
n <- length(x)
n*log(beta)-n*beta*log(lambda)+(beta-1)*sum(log(x))-sum((x/lambda)^beta)
}
ll_exp <- function(x, lambda){ #Computes exponential log-likelihood
n <- length(x)
-n*log(lambda)-sum(x)/lambda
}
lambda_hat_weibull <- 99.020320 #Plugs in MLEs
beta_hat_weibull <- 2.206001
lambda_hat_exp <- 87.61
ll1 <- ll_weibull(bearings, lambda_hat_weibull, beta_hat_weibull) #Gets maximized log-likelihoods
ll0 <- ll_exp(bearings, lambda_hat_exp)
LR <- 2*(ll1 - ll0) #Computes likelihood ratio
LR
[1] 34.44995
p_value <- 1 - pchisq(LR, df=1) #Gets p-value
p_value
[1] 4.373531e-09
The p-value is 4.373531e-09.
d). Perform the Wald \(\chi^2\) on
the same hypothesis \(\beta = 1\). What
is the p-value? [Hint: You need to find the observed Fisher
information matrix (i.e., the negative Hessian matrix from
optim()) based on the Weibull distribution. The inverse of
the negative observed Hessian matrix is the
covariance matrix.]
Answer to Question 1 Part D
result2 <- optim( #Used to get hessian
par=c(1,1),
fn=loglik_weibull,
gr=grad_weibull,
x=bearings,
method="L-BFGS-B",
lower=c(1e-6, 1e-6),
hessian=TRUE
)
H <- result2$hessian
cov_mat <- solve(H) #Used to get covariance matrix
cov_mat
[,1] [,2]
[1,] 44.6100636 0.52102376
[2,] 0.5210238 0.06293246
var_beta <- cov_mat[2,2] #Gets variance of beta
se_beta <- sqrt(var_beta) #Gets standard deviation of beta
beta_hat <- result2$par[2] #Gets MLE of beta
W <- (beta_hat-1)^2 /var_beta #Gets Wald test statistic
W
[1] 23.11111
p_value <- 1-pchisq(W, df=1) #Gets p-value
p_value
[1] 1.529047e-06
The p-value is 1.529047e-06.
e). Write a summary of the above analyses to address the
following:
Whether the two tests generated the same results.
Which model is recommended for the data.
Draw the density curve based on the MLE(s) of the parameter(s)
and describe the distribution of the time-to-failure.
Answer to Question 1 Part E
Both tests indicated the \(\beta \ne
1\) (at the 0.05 significance level) given that \(\text{p-value}= 4.373531 \times 10^{-09} <
0.05\) and \(\text{p-value}= 1.529047
\times 10^{-06} < 0.05\). Therefore, the Weibull model would
be recommended for this data given that we have evidence that \(\beta \ne 1\).
x <- seq(min(bearings), max(bearings), length.out=300) #gets x values used later
weib_dens <- (beta_hat_weibull / lambda_hat_weibull) *
(x / lambda_hat_weibull)^(beta_hat_weibull - 1) *
exp(-(x / lambda_hat_weibull)^beta_hat_weibull) #Weibull pdf
exp_dens <- (1 / lambda_hat_exp) * exp(-x / lambda_hat_exp) #Exponential pdf
plot(x, weib_dens, type = "l", lwd = 2, col = "blue", xlab = "", ylab = "Density", main = "Weibull vs. Exponential Densities")
lines(x, exp_dens, lwd = 2, col = "red", lty = 2)
legend("topright",
legend = c("Weibull (MLE)", "Exponential (MLE)"),
col = c("blue", "red"),
lwd = 2,
lty = c(1, 2)) #Plots densities

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMTE6IERldGVjdGluZyBPdmVyZml0dGluZyBhbmQgT3ZlcmZpdHRpbmcgSXNzdWVzIg0KYXV0aG9yOiAiR3JhY2UgTGlwcGVydCAiDQpkYXRlOiAiIER1ZTogNC8xNC8yMDI2Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIGhpZ2hsaWdodDogbW9ub2Nocm9tZQ0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0NCiNUT0M6OmJlZm9yZSB7DQogIGNvbnRlbnQ6ICJUYWJsZSBvZiBDb250ZW50cyI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXNpemU6IDEuMmVtOw0KICBkaXNwbGF5OiBibG9jazsNCiAgY29sb3I6IG5hdnk7DQogIG1hcmdpbi1ib3R0b206IDEwcHg7DQp9DQoNCg0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLw0KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLw0KICBmb250LXNpemU6IDIycHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQoNCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMTVweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8NCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsNCiAgY29udGVudDogIi4iOw0KDQpib2R5IHtiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmZmZmOw0KICAgICAgY29sb3I6ICMwMDAwMDA7DQogICAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7DQogICAgICBmb250LXNpemU6IDFyZW07DQogICAgICBsaW5lLWhlaWdodDogMS42Ow0KICAgICAgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQp9DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KICBsaWJyYXJ5KGdncGxvdDIpDQp9DQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQogIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQogIGxpYnJhcnkocGxvdGx5KQ0KfQ0KDQppZiAoIXJlcXVpcmUoIlZHQU0iKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJWR0FNIikNCiAgbGlicmFyeShWR0FNKQ0KfQ0KIyMjIyBWR0FNDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KIA0KIFwNCiANCiMjICoqQXNzaWdubWVudCBPYmplY3RpdmVzKiogDQoNCjxwPg0KKiBFbmhhbmNlIHVuZGVyc3RhbmRpbmcgdGhlIHByb2NlZHVyZSBvZiBsaWtlbGlob29kLWJhc2VkIGNoaS1zcXVhcmUgaHlwb3RoZXNpcyB0ZXN0aW5nIC4NCg0KKiBJbXBsZW1lbnQgdGhlIHByb2NlZHVyZXMgZm9yIGRldGVjdGluZyBvdmVyZml0dGluZy91bmRlcmZpdHRpbmcgaXNzdWVzIGluIHByYWN0aWNhbCBhcHBsaWNhdGlvbnMuDQo8L3A+DQoNCg0KIyMgKipQb2xpY2llcyBvZiBVc2luZyBBSSBUb29scyoqDQoNCjxwPg0KKipQb2xpY3kgb24gQUkgVG9vbCBVc2UqKjogUGxlYXNlIGFkaGVyZSB0byB0aGUgQUkgdG9vbCBwb2xpY3kgc3BlY2lmaWVkIGluIHRoZSBjb3Vyc2Ugc3lsbGFidXMuIFRoZSBkaXJlY3QgY29weWluZyBvZiBBSS1nZW5lcmF0ZWQgY29udGVudCBpcyBzdHJpY3RseSBwcm9oaWJpdGVkLiBBbGwgc3VibWl0dGVkIHdvcmsgbXVzdCByZWZsZWN0IHlvdXIgb3duIHVuZGVyc3RhbmRpbmc7IHdoZXJlIGV4dGVybmFsIHRvb2xzIGFyZSBjb25zdWx0ZWQsIGNvbnRlbnQgbXVzdCBiZSB0aG9yb3VnaGx5IHJlcGhyYXNlZCBhbmQgc3ludGhlc2l6ZWQgaW4geW91ciBvd24gd29yZHMuDQo8L3A+DQoNCjxwPg0KKipDb2RlIEluY2x1c2lvbiBSZXF1aXJlbWVudCoqOiBBbnkgY29kZSBpbmNsdWRlZCBpbiB5b3VyIGVzc2F5IG11c3QgYmUgcHJvcGVybHkgY29tbWVudGVkIHRvIGV4cGxhaW4gdGhlIHB1cnBvc2UgYW5kL29yIGV4cGVjdGVkIG91dHB1dCBvZiBrZXkgY29kZSBsaW5lcy4gU3VibWl0dGluZyBBSS1nZW5lcmF0ZWQgY29kZSB3aXRob3V0IG1lYW5pbmdmdWwsIHN0dWRlbnQtYWRkZWQgY29tbWVudHMgd2lsbCBub3QgYmUgYWNjZXB0ZWQuDQo8L3A+DQoNCg0KIyMgVGVzdGluZyBPdmVyZml0dGluZy9VbmRlcmZpdHRpbmcNCg0KSW4gTWFjaGluZSBMZWFybmluZyBhbmQgU3RhdGlzdGljcywgb3ZlcmZpdHRpbmcgb2NjdXJzIHdoZW4gYSBtb2RlbCBpcyB0b28gY29tcGxleCBhbmQgbGVhcm5zIG5vaXNlLCBsZWFkaW5nIHRvIHBvb3IgcGVyZm9ybWFuY2Ugb24gbmV3IGRhdGEsIHdoaWxlIHVuZGVyZml0dGluZyBoYXBwZW5zIHdoZW4gYSBtb2RlbCBpcyB0b28gc2ltcGxlIHRvIGNhcHR1cmUgaW1wb3J0YW50IHBhdHRlcm5zLCByZXN1bHRpbmcgaW4gaGlnaCBlcnJvcnMgb3ZlcmFsbDsgYm90aCBpc3N1ZXMgYXJlIGV4cGxhaW5lZCBieSB0aGUgQmlhc+KAk1ZhcmlhbmNlIFRyYWRlb2ZmIGFuZCBjYW4gY2F1c2UgdW5yZWxpYWJsZSBwcmVkaWN0aW9ucyBpbiByZWFsLXdvcmxkIGFwcGxpY2F0aW9ucy4NCg0KDQpUaGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbiAoUERGKSBvZiB0aGUgV2VpYnVsbCBkaXN0cmlidXRpb24gaXM6DQoNCiQkDQpmKHQ7IFxsYW1iZGEsIFxiZXRhKSA9IFxmcmFje1xiZXRhfXtcbGFtYmRhfSBcbGVmdCggXGZyYWN7dH17XGxhbWJkYX0gXHJpZ2h0KV57XGJldGEtMX0gXGV4cFxsZWZ0WyAtXGxlZnQoIFxmcmFje3R9e1xsYW1iZGF9IFxyaWdodCleXGJldGEgXHJpZ2h0XSwgXHF1YWQgdCBcZ2UgMA0KJCQNCndoZXJlICRcbGFtYmRhID4gMCQgaXMgdGhlIHNjYWxlIHBhcmFtZXRlciAoY2hhcmFjdGVyaXN0aWMgbGlmZSkgYW5kICRcYmV0YSA+IDAkIGlzIHRoZSBzaGFwZSBwYXJhbWV0ZXIuDQoNCldoZW4gJFxiZXRhID0gMSQsIHRoZSBXZWlidWxsIFBERiBzaW1wbGlmaWVzIHRvIHRoZSBleHBvbmVudGlhbCBQREY6DQoNCiQkDQpmKHQ7IFxsYW1iZGEpID0gXGZyYWN7MX17XGxhbWJkYX0gXGV4cFxsZWZ0KCAtXGZyYWN7dH17XGxhbWJkYX0gXHJpZ2h0KQ0KJCQNCndpdGggY29uc3RhbnQgaGF6YXJkIHJhdGUgJGgodCkgPSAxL1xsYW1iZGEkLg0KDQoNCjxwPjxmb250IGNvbG9yID0gImRhcmtyZWQiPioqVGhpcyBhc3NpZ25tZW50IGZvY3VzZXMgb24gcGVyZm9ybWluZyBhIGh5cG90aGVzaXMgdGVzdCBmb3IgdGhlIHNoYXBlIHBhcmFtZXRlciAoJFxiZXRhJCkgb2YgdGhlIFdlaWJ1bGwgZGlzdHJpYnV0aW9uIHdpdGhpbiBhIHJlbGlhYmlsaXR5IG1vZGUqKjwvZm9udD48L3A+DQoNCg0KXGJlZ2lue2FsaWdufQ0KSF8wJjogXGJldGEgPSAxIFxxdWFkIFx0ZXh0eyhFeHBvbmVudGlhbCBtb2RlbCwgc2ltcGxlcil9IFxcDQpIXzEmOiBcYmV0YSBcbmVxIDEgXHF1YWQgXHRleHR7KFdlaWJ1bGwgbW9kZWwsIG1vcmUgY29tcGxleCl9DQpcZW5ke2FsaWdufQ0KDQoNClwNCg0KIyMgKipRdWVzdGlvbjogUmVsaWFiaWxpdHkgQXBwbGljYXRpb24qKg0KDQo8cD4NCkEgbWlkLXNpemVkIG1hbnVmYWN0dXJpbmcgY29tcGFueSBwcm9kdWNpbmcgaW5kdXN0cmlhbCBjb252ZXlvciBzeXN0ZW1zIGJlZ2FuIGV4cGVyaWVuY2luZyB1bmV4cGVjdGVkIGRvd250aW1lIGluIG9uZSBvZiBpdHMgZGlzdHJpYnV0aW9uIGZhY2lsaXRpZXMsIHByb21wdGluZyBjb25jZXJuIGFib3V0IHRoZSByZWxpYWJpbGl0eSBvZiBhIG5ld2x5IHNvdXJjZWQgYmF0Y2ggb2YgYmFsbCBiZWFyaW5ncyB1c2VkIGluIHRoZSBtb3RvciBhc3NlbWJsaWVzLiBUaGVzZSBiZWFyaW5ncywgc3VwcGxpZWQgYnkgYSB2ZW5kb3IgYWRvcHRpbmcgY29zdC1zYXZpbmcgcHJvZHVjdGlvbiBtZXRob2RzLCB3ZXJlIGluc3RhbGxlZCBhY3Jvc3MgbXVsdGlwbGUgdW5pdHMgb3BlcmF0aW5nIHVuZGVyIGNvbnRpbnVvdXMgbG9hZCBjb25kaXRpb25zLiBBZnRlciBzZXZlcmFsIG1vbnRocywgbWFpbnRlbmFuY2UgbG9ncyByZXZlYWxlZCBhIHBhdHRlcm4gb2YgaW5jcmVhc2luZyBmYWlsdXJlcywgd2l0aCBjb21wb25lbnRzIGxhc3RpbmcgYW55d2hlcmUgZnJvbSBhIGZldyBkb3plbiB0byBvdmVyIDE1MCBob3VycyBiZWZvcmUgYnJlYWtkb3duLiBUbyBpbnZlc3RpZ2F0ZSwgdGhlIGVuZ2luZWVyaW5nIHRlYW0gY29sbGVjdGVkIHRpbWUtdG8tZmFpbHVyZSBkYXRhIGZyb20gNTAgaWRlbnRpY2FsIGJlYXJpbmdzIGFuZCBjb25kdWN0ZWQgYSBXZWlidWxsIGFuYWx5c2lzIHdpdGhpbiB0aGUgZnJhbWV3b3JrIG9mIFJlbGlhYmlsaXR5IEVuZ2luZWVyaW5nLiBUaGUgNTAgdGltZS10by1mYWlsdXJlIChzdXJ2aXZhbCB0aW1lKSBhcmU6DQoNCmBgYA0KMTIuNCwgMTguNywgMjUuMywgMzAuMSwgMzMuNSwgMzUuMiwgMzguOSwgNDAuMywgNDIuNywgNDUuMSwgNDcuNiwgNDkuOCwgNTIuNCwgNTUuMCwgDQo1Ny4zLCA2MC4yLCA2Mi44LCA2NS4xLCA2Ny45LCA3MC41LCA3Mi4zLCA3NS42LCA3OC4yLCA4MC45LCA4My40LCA4NS43LCA4OC4xLCA5MC42LCANCjkzLjIsIDk1LjgsIDk4LjQsIDEwMS4wLCAxMDQuNSwgMTA3LjMsIDExMC42LCAxMTMuMiwgMTE2LjgsIDEyMC4xLCAxMjMuNywgMTI3LjQsDQoxMzAuOSwgMTM0LjUsIDEzOC4yLCAxNDIuMCwgMTQ2LjMsIDE1MC43LCAxNTUuMiwgMTYwLjgsIDE2OC40LCAxNzUuOQ0KYGBgDQo8L3A+DQoNClRoaXMgYXNzaWdubWVudCBmb2N1c2VzIG9uIGh5cG90aGVzaXMgJEhfMDogXGJldGEgPSAxJCAoZXhwb25lbnRpYWwpIGFnYWluc3QgJEhfMTogXGJldGEgXG5lcSAxJCAoV2VpYnVsbCkuIFRoaXMgZnJhbWV3b3JrIGRldGVjdHMgb3ZlcmZpdHRpbmcgKGZpdHRpbmcgYSBXZWlidWxsIHdoZW4gZXhwb25lbnRpYWwgaXMgdHJ1ZSkgYW5kIHVuZGVyZml0dGluZyAoZml0dGluZyBleHBvbmVudGlhbCB3aGVuIFdlaWJ1bGwgd2l0aCAkXGJldGEgXG5lcSAxJCBpcyB0cnVlKS4gDQoNCg0KPHA+DQphKS4gRmluZCB0aGUgTUxFIG9mIHRoZSBXZWlidWxsIHBhcmFtZXRlcnMgJFxsYW1iZGEkIChzY2FsZSkgYW5kICRcYmV0YSQgKHNoYXBlKSwgZGVub3RlZCBieSAkXGhhdHtcbGFtYmRhfSQgYW5kICRcaGF0e1xiZXRhfSQsIHJlc3BlY3RpdmVseSwgdXNpbmcgdGhlIGBvcHRpbSgpYCBwcm9jZWR1cmUuIFsqSGludDogWW91IHNob3VsZCBwcm92aWRlIGV4cGxpY2l0IGV4cHJlc3Npb25zIGZvciB0aGUgbG9nLWxpa2VsaWhvb2QgYW5kIGdyYWRpZW50IGZ1bmN0aW9ucyBvZiB0aGUgV2VpYnVsbCBkaXN0cmlidXRpb24gcGFyYW1ldGVycy4qXQ0KDQojIEFuc3dlciB0byBRdWVzdGlvbiAxIFBhcnQgQQ0KDQpXZSBhcmUgcHJvdmlkZWQgd2l0aCB0aGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbiAoUERGKSBvZiB0aGUgV2VpYnVsbCBkaXN0cmlidXRpb246DQoNCiQkDQpmKHQ7IFxsYW1iZGEsIFxiZXRhKSA9IFxmcmFje1xiZXRhfXtcbGFtYmRhfSBcbGVmdCggXGZyYWN7dH17XGxhbWJkYX0gXHJpZ2h0KV57XGJldGEtMX0gXGV4cFxsZWZ0WyAtXGxlZnQoIFxmcmFje3R9e1xsYW1iZGF9IFxyaWdodCleXGJldGEgXHJpZ2h0XSwgXHF1YWQgdCBcZ2UgMA0KJCQNCg0KV2UgY2FuIHVzZSB0aGlzIHRvIGZpbmQgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb246DQoNCiQkDQpMKFxsYW1iZGEsIFxiZXRhKT1ccHJvZF97aT0xfV5uZih0X2kgOyBcbGFtYmRhLCBcYmV0YSk9XHByb2Rfe2k9MX1ebiBcZnJhY3tcYmV0YX17XGxhbWJkYX0gXGxlZnQoIFxmcmFje3RfaX17XGxhbWJkYX0gXHJpZ2h0KV57XGJldGEtMX0gXGV4cFxsZWZ0WyAtXGxlZnQoIFxmcmFje3RfaX17XGxhbWJkYX0gXHJpZ2h0KV5cYmV0YSBccmlnaHRdDQokJA0KDQpUaGVyZWZvcmUgdGhlIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uIGlzOg0KDQokJA0KXGJlZ2lue2FsaWduZWR9DQoNClxlbGwoXGxhbWJkYSwgXGJldGEpICY9IFxsb2coTChcbGFtYmRhLCBcYmV0YSkpIFxcDQomPSBcc3VtX3tpPTF9Xm5cbGVmdFtcbG9nXGJldGEtXGxvZ1xsYW1iZGErKFxiZXRhLTEpXGxvZyh0X2kvXGxhbWJkYSktKHRfaS9cbGFtYmRhKV5cYmV0YVxyaWdodF0gXFwNCiY9IG5cbG9nXGJldGEtblxsb2dcbGFtYmRhKyhcYmV0YS0xKVxzdW1fe2k9MX1eblxsb2cgdF9pLVxzdW1fe2k9MX1ebih0X2kvXGxhbWJkYSleXGJldGENCg0KXGVuZHthbGlnbmVkfQ0KJCQNCg0KVXNpbmcgdGhlIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uIHdlIGNhbiB0YWtlIHRoZSBwYXJ0aWFsIGRlcml2YXRpdmVzIG9mICRcbGFtYmRhJCBhbmQgJFxiZXRhJCB0byBmaW5kIHRoZSBncmFkaWVudCBmdW5jdGlvbnM6DQoNCiQkDQpcZnJhY3tccGFydGlhbFxlbGx9e1xwYXJ0aWFsXGxhbWJkYX09LVxmcmFje25cYmV0YX17XGxhbWJkYX0rXGZyYWN7XGJldGF9e1xsYW1iZGF9XHN1bV97aT0xfV5uKHRfaS9cbGFtYmRhKV5cYmV0YSBcXA0KDQpcZnJhY3tccGFydGlhbFxlbGx9e1xwYXJ0aWFsXGJldGF9PVxmcmFje259e1xiZXRhfS1uXGxvZ1xsYW1iZGErXHN1bV97aT0xfV5uXGxvZyB0X2ktXHN1bV97aT0xfV5uXGxvZyB0X2ktXHN1bV97aT0xfV5uKHRfaS9cbGFtYmRhKV5cYmV0YVxsb2codF9pL1xsYW1iZGEpDQokJA0KDQpXZSBjYW4gdGhlbiB1c2Ugb3VyIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uIGFuZCBncmFkaWVudCBmdW5jdGlvbnMgdG8gZmluZCAkXGhhdHtcbGFtYmRhfSQgYW5kICRcaGF0e1xiZXRhfSQ6DQoNCmBgYHtyfQ0KYmVhcmluZ3MgPC0gYygxMi40LCAxOC43LCAyNS4zLCAzMC4xLCAzMy41LCAzNS4yLCAzOC45LCA0MC4zLCA0Mi43LCA0NS4xLCA0Ny42LCA0OS44LCA1Mi40LCA1NS4wLCANCjU3LjMsIDYwLjIsIDYyLjgsIDY1LjEsIDY3LjksIDcwLjUsIDcyLjMsIDc1LjYsIDc4LjIsIDgwLjksIDgzLjQsIDg1LjcsIDg4LjEsIDkwLjYsIA0KOTMuMiwgOTUuOCwgOTguNCwgMTAxLjAsIDEwNC41LCAxMDcuMywgMTEwLjYsIDExMy4yLCAxMTYuOCwgMTIwLjEsIDEyMy43LCAxMjcuNCwNCjEzMC45LCAxMzQuNSwgMTM4LjIsIDE0Mi4wLCAxNDYuMywgMTUwLjcsIDE1NS4yLCAxNjAuOCwgMTY4LjQsIDE3NS45KQ0KDQpsb2dsaWtfd2VpYnVsbCA8LSBmdW5jdGlvbihwYXIsIHgpeyAjVXNlZCB0byBpbXB1dGUgbG9nLWxpa2VsaWhvb2QNCiAgbGFtYmRhIDwtIHBhclsxXQ0KICBiZXRhIDwtIHBhclsyXQ0KICBpZiAobGFtYmRhIDw9IDAgfHwgYmV0YSA8PSAwKSByZXR1cm4gKEluZikNCiAgbiA8LSBsZW5ndGgoeCkNCiAgbGwgPC0gbipsb2coYmV0YSktbipiZXRhKmxvZyhsYW1iZGEpKyhiZXRhLTEpKnN1bShsb2coeCkpLXN1bSgoeC9sYW1iZGEpXmJldGEpDQogIA0KICByZXR1cm4oLWxsKQ0KfQ0KDQpncmFkX3dlaWJ1bGwgPC0gZnVuY3Rpb24ocGFyLCB4KXsgI1VzZWQgdG8gaW1wdXRlIGdyYWRpZW50IGZ1bmN0aW9ucw0KICBsYW1iZGEgPC0gcGFyWzFdDQogIGJldGEgPC0gcGFyWzJdDQogIGlmIChsYW1iZGEgPD0gMCB8fCBiZXRhIDw9IDApIHJldHVybiAoYyhJbmYsIEluZikpDQogIG4gPC0gbGVuZ3RoKHgpDQogIHRlcm0gPC0gKHgvbGFtYmRhKV5iZXRhDQogIGRfbGFtYmRhIDwtIC1uKmJldGEvbGFtYmRhKyhiZXRhL2xhbWJkYSkqc3VtKHRlcm0pDQogIGRfYmV0YSA8LSBuL2JldGEtbipsb2cobGFtYmRhKStzdW0obG9nKHgpKS1zdW0odGVybSpsb2coeC9sYW1iZGEpKQ0KICANCiAgcmV0dXJuKC1jKGRfbGFtYmRhLCBkX2JldGEpKQ0KfQ0KDQpyZXN1bHQgPC0gb3B0aW0oICNVc2VkIHRvIGNvbXB1dGUgTUxFcw0KICBwYXI9YygxLDEpLA0KICBmbj1sb2dsaWtfd2VpYnVsbCwNCiAgZ3I9Z3JhZF93ZWlidWxsLA0KICB4PWJlYXJpbmdzLA0KICBtZXRob2Q9IkwtQkZHUy1CIiwNCiAgbG93ZXI9YygxZS02LCAxZS02KQ0KKQ0KcmVzdWx0DQoNCmxhbWJkYV9oYXQgPC0gcmVzdWx0JHBhclsxXSAjR2V0cyBNTEVzIGZyb20gb3B0aW0gZnVuY3Rpb24NCmJldGFfaGF0IDwtIHJlc3VsdCRwYXJbMl0NCg0KbGFtYmRhX2hhdA0KYmV0YV9oYXQNCmBgYA0KDQpUaGUgTUxFIG9mIHRoZSBXZWlidWxsIHBhcmFtZXRlcnMgYXJlICRcaGF0e1xsYW1iZGF9PTk5LjAyMDMyJCBhbmQgJFxoYXR7XGJldGF9PTIuMjA2MDAxJC4NCg0KYikuIEZpbmQgdGhlIE1MRSBvZiB0aGUgZXhwb25lbnRpYWwgcGFyYW1ldGVyICRcbGFtYmRhJCAoc2NhbGUpLCBkZW5vdGVkIGJ5ICRcaGF0e1xsYW1iZGF9JCwgdXNpbmcgYW55IHByb2NlZHVyZS4gWypIaW50OiBZb3Ugc2hvdWxkIHByb3ZpZGUgZXhwbGljaXQgZXhwcmVzc2lvbnMgZm9yIHRoZSBsb2ctbGlrZWxpaG9vZCBhbmQgZ3JhZGllbnQgZnVuY3Rpb25zIG9mIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24gcGFyYW1ldGVycy4qXQ0KDQojIEFuc3dlciB0byBRdWVzdGlvbiAxIFBhcnQgQg0KDQpXZSBhcmUgcHJvdmlkZWQgd2l0aCB0aGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbiAoUERGKSBvZiB0aGUgV2VpYnVsbCBkaXN0cmlidXRpb24gd2hlbiAkXGJldGE9MSQ6DQoNCiQkDQpmKHQ7IFxsYW1iZGEpID0gXGZyYWN7MX17XGxhbWJkYX0gXGV4cFxsZWZ0KCAtXGZyYWN7dH17XGxhbWJkYX0gXHJpZ2h0KQ0KJCQNCg0KV2UgY2FuIHVzZSB0aGlzIHRvIGZpbmQgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb246DQoNCiQkDQpMKFxsYW1iZGEpPVxwcm9kX3tpPTF9Xm5mKHQ7IFxsYW1iZGEpPVxwcm9kX3tpPTF9Xm5cZnJhY3sxfXtcbGFtYmRhfWVeey10X2kvXGxhbWJkYX0NCiQkDQoNClRoZW4gd2UgY2FuIGZpbmQgdGhlIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uOg0KDQokJA0KXGVsbChcbGFtYmRhKT1cbG9nIEwoXGxhbWJkYSk9XHN1bV97aT0xfV5uXGxlZnRbLVxsb2dcbGFtYmRhLVxmcmFje3RfaX17XGxhbWJkYX1ccmlnaHRdID0gLW5cbG9nXGxhbWJkYS1cZnJhY3sxfXtcbGFtYmRhfVxzdW1fe2k9MX1ebiB0X2kNCiQkDQoNCldlIGNhbiB0aGVuIGZpbmQgdGhlIGdyYWRpZW50IGZ1bmN0aW9uIGFuZCBzb2x2ZSBmb3IgJFxoYXR7XGxhbWJkYX0kOg0KDQokJA0KXGJlZ2lue2FsaWduZWR9DQomXGZyYWN7XHBhcnRpYWxcZWxsfXtccGFydGlhbFxsYW1iZGF9PS1cZnJhY3tufXtcbGFtYmRhfStcZnJhY3sxfXtcbGFtYmRhXjJ9XHN1bV97aT0xfV5uIHRfaSBcXA0KDQomXFJpZ2h0YXJyb3cgLVxmcmFje259e1xsYW1iZGF9K1xmcmFjezF9e1xsYW1iZGFeMn1cc3VtX3tpPTF9Xm4gdF9pPTAgXFwNCg0KJlxSaWdodGFycm93IC1uXGxhbWJkYStcc3VtX3tpPTF9Xm4gdF9pID0wIFxcDQoNCiZcUmlnaHRhcnJvdyBcbGFtYmRhPVxmcmFjezF9e259XHN1bV97aT0xfV5uIHRfaQ0KDQpcZW5ke2FsaWduZWR9DQokJA0KDQpUaGVyZWZvcmUsDQoNCiQkDQpcaGF0e1xsYW1iZGF9PVxmcmFjezF9e259XHN1bV97aT0xfV5uIHRfaQ0KJCQNCg0KV2UgY2FuIHVzZSB0aGlzIHRvIGZpbmQgJFxoYXR7XGxhbWJkYX0kOg0KDQpgYGB7cn0NCg0KbGFtYmRhX2hhdDIgPSBtZWFuKGJlYXJpbmdzKSAjR2V0cyBsYW1iZGEgTUxFDQoNCmxhbWJkYV9oYXQyDQoNCmBgYA0KDQpUaGUgTUxFIG9mIHRoZSBXZWlidWxsIHBhcmFtZXRlciB3aGVuICRcYmV0YT0xJCBpcyAkXGhhdHtcbGFtYmRhfT04Ny42MSQuDQoNCmMpLiBQZXJmb3JtIHRoZSBsaWtlbGlob29kIHJhdGlvICRcY2hpXjIkIHRlc3Qgb24gJFxiZXRhID0gMSQuIFdoYXQgaXMgdGhlIHAtdmFsdWU/IFsqSGludDogVXNlIHRoZSByZXN1bHRzIGluIGEpIGFuZCBiKSouXQ0KDQojIEFuc3dlciB0byBRdWVzdGlvbiAxIFBhcnQgQw0KDQpgYGB7cn0NCmxsX3dlaWJ1bGwgPC0gZnVuY3Rpb24oeCwgbGFtYmRhLCBiZXRhKXsgI0NvbXB1dGVzIFdlaWJ1bGwgbG9nLWxpa2VsaWhvb2QNCiAgbiA8LSBsZW5ndGgoeCkNCiAgbipsb2coYmV0YSktbipiZXRhKmxvZyhsYW1iZGEpKyhiZXRhLTEpKnN1bShsb2coeCkpLXN1bSgoeC9sYW1iZGEpXmJldGEpDQp9DQoNCmxsX2V4cCA8LSBmdW5jdGlvbih4LCBsYW1iZGEpeyAjQ29tcHV0ZXMgZXhwb25lbnRpYWwgbG9nLWxpa2VsaWhvb2QNCiAgbiA8LSBsZW5ndGgoeCkNCiAgLW4qbG9nKGxhbWJkYSktc3VtKHgpL2xhbWJkYQ0KfQ0KDQpsYW1iZGFfaGF0X3dlaWJ1bGwgPC0gOTkuMDIwMzIwICNQbHVncyBpbiBNTEVzDQpiZXRhX2hhdF93ZWlidWxsIDwtIDIuMjA2MDAxDQpsYW1iZGFfaGF0X2V4cCA8LSA4Ny42MQ0KDQpsbDEgPC0gbGxfd2VpYnVsbChiZWFyaW5ncywgbGFtYmRhX2hhdF93ZWlidWxsLCBiZXRhX2hhdF93ZWlidWxsKSAjR2V0cyBtYXhpbWl6ZWQgbG9nLWxpa2VsaWhvb2RzDQpsbDAgPC0gbGxfZXhwKGJlYXJpbmdzLCBsYW1iZGFfaGF0X2V4cCkNCg0KTFIgPC0gMioobGwxIC0gbGwwKSAjQ29tcHV0ZXMgbGlrZWxpaG9vZCByYXRpbw0KTFINCg0KcF92YWx1ZSA8LSAxIC0gcGNoaXNxKExSLCBkZj0xKSAjR2V0cyBwLXZhbHVlDQpwX3ZhbHVlDQpgYGANCg0KVGhlIHAtdmFsdWUgaXMgNC4zNzM1MzFlLTA5Lg0KDQpkKS4gUGVyZm9ybSB0aGUgV2FsZCAkXGNoaV4yJCBvbiB0aGUgc2FtZSBoeXBvdGhlc2lzICRcYmV0YSA9IDEkLiBXaGF0IGlzIHRoZSBwLXZhbHVlPyBbKkhpbnQ6IFlvdSBuZWVkIHRvIGZpbmQgdGhlIG9ic2VydmVkIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXggKGkuZS4sIHRoZSBuZWdhdGl2ZSBIZXNzaWFuIG1hdHJpeCBmcm9tIGBvcHRpbSgpYCkgYmFzZWQgb24gdGhlIFdlaWJ1bGwgZGlzdHJpYnV0aW9uLiBUaGUgaW52ZXJzZSBvZiB0aGUgPGZvbnQgY29sb3IgPSAiYmx1ZSI+bmVnYXRpdmU8L2ZvbnQ+IG9ic2VydmVkIEhlc3NpYW4gbWF0cml4IGlzIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCouXSANCg0KIyBBbnN3ZXIgdG8gUXVlc3Rpb24gMSBQYXJ0IEQNCg0KYGBge3J9DQpyZXN1bHQyIDwtIG9wdGltKCAjVXNlZCB0byBnZXQgaGVzc2lhbg0KICBwYXI9YygxLDEpLA0KICBmbj1sb2dsaWtfd2VpYnVsbCwNCiAgZ3I9Z3JhZF93ZWlidWxsLA0KICB4PWJlYXJpbmdzLA0KICBtZXRob2Q9IkwtQkZHUy1CIiwNCiAgbG93ZXI9YygxZS02LCAxZS02KSwNCiAgaGVzc2lhbj1UUlVFDQopDQpIIDwtIHJlc3VsdDIkaGVzc2lhbg0KY292X21hdCA8LSBzb2x2ZShIKSAjVXNlZCB0byBnZXQgY292YXJpYW5jZSBtYXRyaXgNCmNvdl9tYXQNCg0KdmFyX2JldGEgPC0gY292X21hdFsyLDJdICNHZXRzIHZhcmlhbmNlIG9mIGJldGENCnNlX2JldGEgPC0gc3FydCh2YXJfYmV0YSkgI0dldHMgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGJldGENCg0KYmV0YV9oYXQgPC0gcmVzdWx0MiRwYXJbMl0gI0dldHMgTUxFIG9mIGJldGENClcgPC0gKGJldGFfaGF0LTEpXjIgL3Zhcl9iZXRhICNHZXRzIFdhbGQgdGVzdCBzdGF0aXN0aWMNClcNCg0KcF92YWx1ZSA8LSAxLXBjaGlzcShXLCBkZj0xKSAjR2V0cyBwLXZhbHVlDQpwX3ZhbHVlDQpgYGANCg0KVGhlIHAtdmFsdWUgaXMgMS41MjkwNDdlLTA2Lg0KDQplKS4gV3JpdGUgYSBzdW1tYXJ5IG9mIHRoZSBhYm92ZSBhbmFseXNlcyB0byBhZGRyZXNzIHRoZSBmb2xsb3dpbmc6DQoNCiogV2hldGhlciB0aGUgdHdvIHRlc3RzIGdlbmVyYXRlZCB0aGUgc2FtZSByZXN1bHRzLg0KDQoqIFdoaWNoIG1vZGVsIGlzIHJlY29tbWVuZGVkIGZvciB0aGUgZGF0YS4NCg0KKiBEcmF3IHRoZSBkZW5zaXR5IGN1cnZlIGJhc2VkIG9uIHRoZSBNTEUocykgb2YgdGhlIHBhcmFtZXRlcihzKSBhbmQgZGVzY3JpYmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdGltZS10by1mYWlsdXJlLg0KDQojIEFuc3dlciB0byBRdWVzdGlvbiAxIFBhcnQgRQ0KDQpCb3RoIHRlc3RzIGluZGljYXRlZCB0aGUgJFxiZXRhIFxuZSAxJCAoYXQgdGhlIDAuMDUgc2lnbmlmaWNhbmNlIGxldmVsKSBnaXZlbiB0aGF0ICRcdGV4dHtwLXZhbHVlfT0gNC4zNzM1MzEgXHRpbWVzIDEwXnstMDl9IDwgMC4wNSQgYW5kICRcdGV4dHtwLXZhbHVlfT0gMS41MjkwNDcgXHRpbWVzIDEwXnstMDZ9IDwgMC4wNSQuICBUaGVyZWZvcmUsIHRoZSBXZWlidWxsIG1vZGVsIHdvdWxkIGJlIHJlY29tbWVuZGVkIGZvciB0aGlzIGRhdGEgZ2l2ZW4gdGhhdCB3ZSBoYXZlIGV2aWRlbmNlIHRoYXQgJFxiZXRhIFxuZSAxJC4NCg0KYGBge3J9DQp4IDwtIHNlcShtaW4oYmVhcmluZ3MpLCBtYXgoYmVhcmluZ3MpLCBsZW5ndGgub3V0PTMwMCkgI2dldHMgeCB2YWx1ZXMgdXNlZCBsYXRlcg0Kd2VpYl9kZW5zIDwtIChiZXRhX2hhdF93ZWlidWxsIC8gbGFtYmRhX2hhdF93ZWlidWxsKSAqIA0KICAoeCAvIGxhbWJkYV9oYXRfd2VpYnVsbCleKGJldGFfaGF0X3dlaWJ1bGwgLSAxKSAqDQogIGV4cCgtKHggLyBsYW1iZGFfaGF0X3dlaWJ1bGwpXmJldGFfaGF0X3dlaWJ1bGwpICNXZWlidWxsIHBkZg0KZXhwX2RlbnMgPC0gKDEgLyBsYW1iZGFfaGF0X2V4cCkgKiBleHAoLXggLyBsYW1iZGFfaGF0X2V4cCkgI0V4cG9uZW50aWFsIHBkZg0KDQpwbG90KHgsIHdlaWJfZGVucywgdHlwZSA9ICJsIiwgbHdkID0gMiwgY29sID0gImJsdWUiLCB4bGFiID0gIiIsIHlsYWIgPSAiRGVuc2l0eSIsIG1haW4gPSAiV2VpYnVsbCB2cy4gRXhwb25lbnRpYWwgRGVuc2l0aWVzIikNCmxpbmVzKHgsIGV4cF9kZW5zLCBsd2QgPSAyLCBjb2wgPSAicmVkIiwgbHR5ID0gMikNCmxlZ2VuZCgidG9wcmlnaHQiLA0KICAgICAgIGxlZ2VuZCA9IGMoIldlaWJ1bGwgKE1MRSkiLCAiRXhwb25lbnRpYWwgKE1MRSkiKSwNCiAgICAgICBjb2wgPSBjKCJibHVlIiwgInJlZCIpLA0KICAgICAgIGx3ZCA9IDIsDQogICAgICAgbHR5ID0gYygxLCAyKSkgI1Bsb3RzIGRlbnNpdGllcw0KYGBgDQoNCg0KDQoNCg0KDQo=