Introduction
This module focuses on the three most commonly used statistical tests
in subsequent courses: the Wald, Score, and Likelihood Ratio tests.
These three methods form the cornerstone of inference in parametric
models, providing powerful and versatile approaches for testing
hypotheses, constructing confidence intervals, and assessing model
fit.
While rooted in the elegant framework of maximum likelihood
estimation, each test offers a distinct geometric or algebraic
perspective on the evidence against a null hypothesis. Understanding
their theoretical foundations, comparative strengths, and intrinsic
relationships is essential for mastering advanced statistical
methodology and applying it correctly to complex data.
In this module, we will state formulation, assumptions, steps to
perform these tests and explained by numerical examples with manual
solution and verification using R.
Review of Likelihood
Formulation and Estimation
In maximum likelihood estimation, we fit models by finding parameters
that make the observed data most probable. This process naturally leads
to three related methods for testing hypotheses such as the likelihood
ratio, Wald, and score tests. Each test uses a different feature of the
likelihood function, but all are rooted in the same principles of
likelihood and asymptotic theory. This section reviews basics of maximum
likelihood estimation and their asymptotic normality.
Likelihood Function
Let \(X_1, X_2, \dots, X_n\) be
independent and identically distributed (i.i.d) random variables with
probability density (or mass) function \(f(x_i; \boldsymbol{\theta})\), where \(\boldsymbol{\theta} = (\theta_1, \dots,
\theta_p)^T\) is a \(p\)-dimensional parameter vector. The
likelihood function is:
\[
L(\boldsymbol{\theta}) = \prod_{i=1}^n f(x_i; \boldsymbol{\theta})
\]
The log-likelihood function is:
\[
\ell(\boldsymbol{\theta}) = \log L(\boldsymbol{\theta}) = \sum_{i=1}^n
\log f(x_i; \boldsymbol{\theta})
\]
Maximum Likelihood Estimation
The maximum likelihood estimator (MLE) \(\hat{\boldsymbol{\theta}}\) satisfies:
\[
\hat{\boldsymbol{\theta}} = \arg\max_{\boldsymbol{\theta}}
\ell(\boldsymbol{\theta})
\]
Under regularity conditions, \(\hat{\boldsymbol{\theta}}\) is obtained by
solving the score equations:
\[
U(\boldsymbol{\theta}) = \frac{\partial
\ell(\boldsymbol{\theta})}{\partial \boldsymbol{\theta}} =
\boldsymbol{0}
\]
Fisher Information Matrix
The Fisher information matrix of \(\theta\) based on an entire sample with
size \(n\) is given by:
\[
I_n(\boldsymbol{\theta}) = E\left[-\frac{\partial^2
\ell(\boldsymbol{\theta})}{\partial \boldsymbol{\theta} \partial
\boldsymbol{\theta}^T}\right]
\]
The above (theoretical) Fisher information matrix requires integral
that integrates variables out from the expression. In practice, we use
the following observed information matrix:
\[
J_n(\boldsymbol{\theta}) = -\frac{\partial^2
\ell(\boldsymbol{\theta})}{\partial \boldsymbol{\theta} \partial
\boldsymbol{\theta}^T}
\]
Some software programs return Hessian matrix \(H_n( \boldsymbol{\theta}) = -J_n(
\boldsymbol{\theta})\), that is
\[
H_n(\boldsymbol{\theta}) = \frac{\partial^2
\ell(\boldsymbol{\theta})}{\partial \boldsymbol{\theta} \partial
\boldsymbol{\theta}^T}
\]
Note that, in some textbooks, research articles and web postings, the
Fisher Information Matrix based on single data point is
denoted by \(I_0(\boldsymbol{\theta})\),
\[
I_n(\boldsymbol{\theta}) = n\times I_1(\boldsymbol{\theta})
\]
Under some regularity conditions and the null hypothesis \(H_0: \boldsymbol{\theta} =
\boldsymbol{\theta}_0\), we have the following
\[
\sqrt{n}(\hat{\boldsymbol{\theta}} - \boldsymbol{\theta}_0)
\xrightarrow{d} N(\boldsymbol{0}, I_1^{-1}(\boldsymbol{\theta}_0)).
\]
The relationship between Fisher Information Matrix
of \(\boldsymbol{\theta}\) and the
variance of the MLE \(\hat{\boldsymbol{\theta}}\) is
\[
\text{var}(\hat{\boldsymbol{\theta}}) \approx
I_n^{-1}(\boldsymbol{\theta}) = [n\times I_1(\boldsymbol{\theta})]^{-1}
= \frac{I_1^{-1}(\boldsymbol{\theta})}{n}
\] Therefore, we can rewrite the above asymptotic distribution of
\(\boldsymbol{\theta}\) as
\[
\hat{\boldsymbol{\theta}}\to N\left( \boldsymbol{\theta},
\frac{I_1^{-1}(\boldsymbol{\theta})}{n} \right) \quad \text{or
equivalently} \quad \hat{\boldsymbol{\theta}}\to N\left(
\boldsymbol{\theta}, I_n^{-1}(\boldsymbol{\theta}) \right)
\]
The diagonal elements in the covariance \(I_n^{-1}(\boldsymbol{\theta})\) represent
the variance of the corresponding parameters in \(\hat{\boldsymbol{\theta}} = (\hat{\theta}_1,
\hat{\theta}_2, \cdots, \hat{\theta_k})\). For example. $(_1) = $
the first element in the main diagonal of the inverse of the fisher
information matrix based on the entire sample.
For example, let \(\boldsymbol{\theta}
=(\theta_1, \theta_2)\), the corresponding MLE is \(\hat{\boldsymbol{\theta}} =(\hat{\theta_1},
\hat{\theta_2)}\). Let the observed Fisher information
matrix be
\[
J_n(\boldsymbol{\theta}) = -\frac{\partial^2
\ell(\boldsymbol{\theta})}{\partial \boldsymbol{\theta} \partial
\boldsymbol{\theta}^T}=-\begin{pmatrix}
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial^2 \theta_1} &
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial \theta_1\partial
\theta_2} \\
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial \theta_2\partial
\theta_1} & \frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial^2
\theta_2}
\end{pmatrix}
\]
The estimated Fisher information matrix is given by
\[
\widehat{J_n(\boldsymbol{\theta})} = -\begin{pmatrix}
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial^2 \theta_1} &
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial \theta_1\partial
\theta_2} \\
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial \theta_2\partial
\theta_1} & \frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial^2
\theta_2}
\end{pmatrix}\Bigg|_{\boldsymbol{\theta} = \hat{\boldsymbol{\theta}}}.
\]
Note that R function optim() returns Hessian matrix
\(\widehat{H_n(\boldsymbol{\theta})}=-
\widehat{J_n(\boldsymbol{\theta})}\).
Let the inverse of \(widehat{J_n(\boldsymbol{\theta})}\) be of
the following form
\[
\left[\widehat{J_n(\boldsymbol{\theta})}\right]^{-1} =
-\left[\begin{pmatrix}
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial^2 \theta_1} &
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial \theta_1\partial
\theta_2} \\
\frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial \theta_2\partial
\theta_1} & \frac{\partial^2 \ell(\boldsymbol{\theta})}{\partial^2
\theta_2}
\end{pmatrix}\Bigg|_{\boldsymbol{\theta} =
\hat{\boldsymbol{\theta}}}\right]^{-1}
=\begin{pmatrix}
a & c \\
c & d
\end{pmatrix}.
\]
Then we have
\[
\widehat{\text{var}(\hat{\boldsymbol{\theta})}} \approx \begin{pmatrix}
a & c \\
c & d
\end{pmatrix}.
\]
That is,
\[
\text{var}(\hat{\theta}_1) \approx a, \quad \text{var}(\hat{\theta}_2)
\approx d, \quad \text{and} \quad \text{cov}(\hat{\theta}_1,
\hat{\theta}_2) \approx c.
\]
The above asymptotic normality is the foundation of the Wald and
Score tests.
The Three Asymptotic
\(\chi^2\) Tests
At the foundation of parametric hypothesis testing lies a trio of
asymptotically equivalent methods: the likelihood ratio, Wald, and score
tests. All three derive from maximum likelihood theory and converge to
the same chi-squared distribution under the null hypothesis, yet they
approach the problem of testing from meaningfully different angles.
The likelihood ratio test directly compares the
goodness-of-fit between the unrestricted model and the model constrained
by the null hypothesis. The Wald test evaluates the
distance between the estimated parameter vector and its hypothesized
value, standardized by the estimated curvature of the likelihood. The
score test, alternatively, examines whether the slope
of the log-likelihood at the null parameter value is sufficiently close
to zero—an indication that the null point is a plausible maximum.
Despite their asymptotic equivalence, these tests differ in
computation, finite-sample performance, and invariance properties,
leading to practical trade-offs in applied work. The following
sub-sections develop their formulations, contrasts their theoretical and
practical attributes, and provide guidance for choosing among them in
statistical modeling.
Wald Test
Formulation Tests the distance between the
unconstrained MLE and the hypothesized
value. It measures geometric displacement from
\(H_0\) in parameter space. To make it
simple, let’s \(\boldsymbol{\theta} =
(\theta_1, \theta_2)\) be the vector of the parameters of a
distribution. Consider hypothesis
\[
H_0: \boldsymbol{\theta} = \boldsymbol{\theta}_0, \quad \text{i.e.}\quad
\begin{pmatrix}
\theta_1 \\
\theta_2
\end{pmatrix}
=
\begin{pmatrix}
\theta_{10} \\
\theta_{20}
\end{pmatrix}.
\]
The difference between the hypothesized value and
the unrestricted MLE is given by
\[
D = \hat{\boldsymbol{\theta}} - \boldsymbol{\theta}_0 = \begin{pmatrix}
\hat{\theta}_1 -\theta_{10} \\
\hat{\theta}_2 -\theta_{20}
\end{pmatrix}
\]
Test Statistic
With the above notations, the Wald test statistic is given by
\[
W = \hat{D}^{T} \, \left[
\widehat{\text{var}(\hat{\boldsymbol{\theta}})}\right]^{-1} \,
\hat{D} = \hat{D}^{T} \,\text{I}_n(\hat{\boldsymbol{\theta}}) \,
\hat{D}
\]
More explicitly, we have
\[
W =
\begin{pmatrix}
\hat{\theta}_1 - \theta_{10} & \hat{\theta}_2 - \theta_{20}
\end{pmatrix}
\begin{pmatrix}
\text{var}(\hat{\theta}_1) & \text{cov}(\hat{\theta}_1,
\hat{\theta}_2) \\
\text{cov}(\hat{\theta}_1, \hat{\theta}_2) &
\text{var}(\hat{\theta}_2)
\end{pmatrix}^{-1}
\begin{pmatrix}
\hat{\theta}_1 - \theta_{10} \\
\hat{\theta}_2 - \theta_{20}
\end{pmatrix}.
\]
For testing single parameter case \(H_0:
\boldsymbol{\theta}_1 = \boldsymbol{\theta}_{10}\)
\[
W = (\hat{\theta} -
\theta_0)[\text{var}(\hat{\theta}_1)]^{-1}(\hat{\theta} - \theta_0) =
\frac{(\hat{\theta} - \theta_0)^2}{\text{var}(\hat{\theta}_1)}
\]
Asymptotic Distribution: \(W \xrightarrow{d} \chi^2_q\) under \(H_0\), where \(q\) is the number of parameters specified
under the null hypothesis.
In the two-parameter and one-parameter cases described above, the
degrees of freedom of the \(\chi^2\)
test are \(q = 2\) and \(q=1\), respectively.
Assumptions: Wald test requires only the
unconstrained MLE (as well as Information matrix to derive the
covariance matrix of the MLE) and is sensitive to parameterization.
Score Test (Rao’s
Score Test)
Rao’s score is also known as the Lagrange multiplier
test.
Formulation: Tests whether the score at the null
hypothesis is significantly different from zero. It measures local
gradient at \(H_0\) in likelihood
space.
Test Statistic:
\[
S = U(\tilde{\boldsymbol{\theta}})^T
I_n^{-1}(\tilde{\boldsymbol{\theta}}) U(\tilde{\boldsymbol{\theta}})
\] where \(\tilde{\boldsymbol{\theta}}\) is the MLE
under \(H_0\) (constrained MLE).
Asymptotic Distribution: \(S \xrightarrow{d} \chi^2_q\) under \(H_0\).
Assumptions: Requires only the constrained MLE.
Invariant to reparameterization.
Likelihood Ratio
Test
Formulation: Compares the maximized log-likelihood
under \(H_0\) and \(H_1\). It measures information loss when
imposing \(H_0\).
Test Statistic:
\[
\Lambda = -2[\ell(\tilde{\boldsymbol{\theta}}) -
\ell(\hat{\boldsymbol{\theta}})] = 2[\ell(\hat{\boldsymbol{\theta}}) -
\ell(\tilde{\boldsymbol{\theta}})]
\]
Asymptotic Distribution: \(\Lambda \xrightarrow{d} \chi^2_q\) under
\(H_0\).
Assumptions: Requires both constrained and
unconstrained MLEs. Invariant to reparameterization.
Practical Examples:
Single Parameter
To concretely demonstrate the similarities and differences among the
three likelihood-based tests, we now turn to practical implementation in
R. While these tests often yield similar conclusions with large samples,
their distinctions become particularly instructive when examining simple
yet fundamental distributions.
Through hands-on examples using Poisson and normal distributions, we
will systematically apply the Likelihood Ratio, Wald, and Score tests to
identical hypotheses. This comparative approach will illuminate how each
test statistic is calculated, showcase scenarios where their results
diverge meaningfully, and provide reusable code templates that reveal
the computational machinery underlying common statistical
procedures.
Unlike t-tests and z-tests which have
closed-form formulas, likelihood-based chi-squared tests require
explicit derivation of the likelihood function, parameter estimation
under null/alternative, and careful construction of the test statistics.
This is why they’re more flexible but require more
preparation. The key preparation steps required
- Derive log-likelihood function \(\ell(\theta; x)\)
- Derive score function \(U(\theta) =
\partial \ell/\partial \theta\)
- Derive Fisher Information \(I_n(\theta) =
-E[\partial^2 \ell/\partial \theta^2]\)
- Find MLEs under both \(H_0\) and
\(H_1\)
- Compute standard errors from inverse Fisher Information
- Construct test statistics using appropriate formulas
Note that likelihood-based inferences
rely on large-sample asymptotic theory. For the purpose of clearly
illustrating the procedure, the examples in the following subsections
will use small toy datasets.
Example 1: Poisson
Distribution
Problem: Test \(H_0:
\lambda = 2\) vs \(H_1: \lambda \neq
2\) for \(X_1, \dots, X_n \sim
\text{Poisson}(\lambda)\).
Observed data: 3, 1, 4, 2, 3.
Manual Solution:
Likelihood: \(L(\lambda) = \prod_{i=1}^n \frac{e^{-\lambda}
\lambda^{x_i}}{x_i!}\)
Log-likelihood: \(\ell(\lambda) = -n\lambda + (\sum x_i)\log\lambda
- \sum \log(x_i!)\)
MLE: \(\hat{\lambda} =
\bar{x} = \frac{3+1+4+2+3}{5} = 2.6\)
Score function: \(U(\lambda) = \frac{d\ell}{d\lambda} = -n +
\frac{\sum x_i}{\lambda}\)
Information: \(I_n(\lambda) = \frac{n}{\lambda}\)
(expected), \(J_n(\lambda) = \frac{\sum
x_i}{\lambda^2}\) (observed)
Wald Test
\[
W = (\hat{\lambda} - \lambda_0)^2 \hat{I}_n(\hat{\lambda}) = (2.6 - 2)^2
\times \frac{5}{2.6} = 0.36 \times 1.923 = 0.692
\] Using observed information: \(W =
(0.6)^2 \times \frac{13}{2.6^2} = 0.36 \times 1.923 = 0.692\)
Score Test
Score at \(\lambda_0=2\): \(U(2) = -5 + \frac{13}{2} = 1.5\)
\[
I(2) = \frac{5}{2} = 2.5
\]
\[
S = U(2)^2 I_n^{-1}(2) = (1.5)^2 \times \frac{1}{2.5} = 2.25 \times 0.4
= 0.9
\]
Likelihood Ratio Test
\[
\ell(\hat{\lambda}) = -5(2.6) + 13\log(2.6) - \sum \log(x_i!) = -13 +
13(0.9555) - \log(1728) \approx -8.0335
\]
\[
\ell(\lambda_0) = -5(2) + 13\log(2) - \sum \log(x_i!) = -10 + 13(0.6931)
- 7.455 \approx -8.4447
\]
\[
\Lambda = 2[-8.0335 - (-8.4447)] = 2(0.4112) = 0.8224
\]
Conclusion All test statistics are approximately
between 0.7 and 0.9. Since all three test statistics are less than the
critical value \(\chi^2_{1,0.05} =
3.841\), we fail to reject \(H_0\).
R Verification
# Poisson example
x <- c(3, 1, 4, 2, 3)
n <- length(x)
# MLE
lambda_mle <- mean(x)
# Wald test
se_wald <- sqrt(lambda_mle/n)
W <- ((lambda_mle - 2)/se_wald)^2
# Score test
U <- -n + sum(x)/2
I <- n/2
S <- U^2/I
# Likelihood ratio test
ll_mle <- sum(dpois(x, lambda_mle, log = TRUE))
ll_null <- sum(dpois(x, 2, log = TRUE))
LR <- 2*(ll_mle - ll_null)
cat(" Wald:", W, "p-value:", 1-pchisq(W, 1), "\n",
"Score:", S, "p-value:", 1-pchisq(S, 1), "\n",
" LR:", LR, "p-value:", 1-pchisq(LR, 1), "\n")
Wald: 0.6923077 p-value: 0.4053806
Score: 0.9 p-value: 0.3427817
LR: 0.8214709 p-value: 0.3647505
Example 2: Normal
Distribution Mean Test
Problem Test \(H_0: \mu =
10\) vs \(H_1: \mu \neq 10\) for
\(X_i \sim N(\mu, \sigma^2)\), where
\(\sigma^2 = 0.1\).
Data: 10.2, 9.8, 10.0, 10.2, 9.9.
Manual Solution
Likelihood: \(L(\mu) =
(2\pi\sigma^2)^{-n/2} \exp\left\{-\frac{1}{2\sigma^2} \sum_{i=1}^n (x_i
- \mu)^2\right\}\).
Log-likelihood: \(\ell(\mu) = \log L(\mu) =
-\frac{n}{2}\log(2\pi\sigma^2) - \frac{1}{2\sigma^2} \sum_{i=1}^n (x_i -
\mu)^2\)
Score Equation: \(S(\mu) = \frac{\partial \ell(\mu)}{\partial \mu} =
\frac{1}{\sigma^2} \sum_{i=1}^n (x_i - \mu)\)
MLE \(\hat{\mu} =
\bar{x} = \frac{1}{n} \sum_{i=1}^n x_i =
\frac{10.2+9.8+10.0+10.2+9.9}{5} = 10.02\)
Information \(I(\mu) =
-\frac{\partial^2 \ell(\mu)}{\partial \mu^2} = \frac{n}{\sigma^2} =
\frac{5}{0.1} = 50\)
With the above manual work, we next define the three test
statistic:
Wald Test
\[
W = (\hat{\mu} - \mu_0)^2 I(\hat{\mu}) = (0.02)^2 \times 50 = 0.0004
\times 50 = 0.02
\]
Score Test
\[
U(\mu) = \frac{n}{\sigma^2}(\bar{x} - \mu)
\]
At \(\mu_0=10\): \(U(10) = 50 \times (10.02 - 10) = 1\)
\[
S = U(10)^2 I^{-1}(10) = 1^2 \times \frac{1}{50} = 0.02
\]
Likelihood Ratio Test
\[
\ell(\mu) = -\frac{n}{2}\log(2\pi\sigma^2) - \frac{1}{2\sigma^2}\sum(x_i
- \mu)^2
\]
\[
\ell(\mu_0) = -\frac{n}{2}\log(2\pi\sigma^2) -
\frac{1}{2\sigma^2}\sum(x_i - \mu_0)^2
\]
\[
\ell(\hat{\mu}) - \ell(\mu_0) = -\frac{1}{2\sigma^2}[\sum(x_i -
\hat{\mu})^2 - \sum(x_i - \mu_0)^2]
\]
\[
= -\frac{1}{0.2}[0.13 - 0.128] = -5 \times 0.002 = -0.01
\]
\[
\Lambda = 2 \times 0.01 = 0.02.
\]
R Verification
# Normal example
x <- c(10.2, 9.8, 10.0, 10.2, 9.9)
n <- length(x)
sigma2 <- 0.1
mu0 <- 10
mu_mle <- mean(x)
# Wald test
W <- (mu_mle - mu0)^2 * (n/sigma2) # Wald test statistic
# Score test
U <- (n/sigma2) * (mu_mle - mu0)
I <- n/sigma2
S <- U^2/I # Rao test statistic
# Likelihood ratio test
ll_mle <- sum(dnorm(x, mu_mle, sqrt(sigma2), log = TRUE)) # log = TRUE yields log-likelihood
ll_null <- sum(dnorm(x, mu0, sqrt(sigma2), log = TRUE))
LR <- 2*(ll_mle - ll_null) # log-likelihood ratio test statistic
cat(" Wald:", W, "p-value:", 1-pchisq(W, 1), "\n",
"Score:", S, "p-value:", 1-pchisq(S, 1), "\n",
" LR:", LR, "p-value:", 1-pchisq(LR, 1), "\n")
Wald: 0.02 p-value: 0.8875371
Score: 0.02 p-value: 0.8875371
LR: 0.02 p-value: 0.8875371
Practical Example:
Multiple Parameters
In the single-parameter case, the Fisher information number is
relatively straightforward to derive. For multi-parameter cases,
however, we need to obtain the Fisher information matrix in order to
conduct both the Wald and score tests. This section uses the Weibull
distribution as an example to illustrate the procedure for the three
chi-square tests.
Components for the
Three \(\chi^2\) Tests
In this subsection, we use the gamma distribution as an example to
illustrate how to test the significance of parameters. Since the gamma
distribution is commonly expressed in two distinct formulations, we
adopt the following parameterization.
The gamma distribution with shape parameter \(\alpha > 0\) and rate parameter \(\beta > 0\) has probability density
function:
\[
f(x; \alpha, \beta) = \frac{\beta^{\alpha}}{\Gamma(\alpha)} x^{\alpha-1}
e^{-\beta x}, \quad x > 0
\]
The case where the shape parameter \(\alpha
= 1\) reduces the gamma to an exponential distribution. Thus,
testing this null hypothesis indicates whether the gamma distribution
provides a significantly better fit or leads to overfitting for the
given data.
Assume \(\{x_1, x_2, \cdots, x_n\}
\xrightarrow{i.i.d} \text{gamma}(\alpha, \beta)\). \(\psi(\alpha)\) denotes the digamma
function
\[
\psi(z) = \frac{d}{dz} \ln \Gamma(z) = \frac{\Gamma'(z)}{\Gamma(z)}.
\]
R functions digamma(z),
trigamma(z), tetragamma(z) evaluate \(\psi(x), \psi^\prime (z)\) and \(\psi^{\prime\prime}(z)\), respectively.
The objective is to test \(H_0: \alpha =
1\). The major components required for testing the hypothesis are
given below.
Log-likelihood
\[
\ell(\alpha, \beta) = n\alpha\log\beta - n\log\Gamma(\alpha) +
(\alpha-1)\sum_{i=1}^n \log x_i - \beta\sum_{i=1}^n x_i
\]
Score Equations
\[
\frac{\partial\ell}{\partial\alpha} = n\log\beta - n\psi(\alpha) +
\sum_{i=1}^n \log x_i = 0
\]
\[
\frac{\partial\ell}{\partial\beta} = \frac{n\alpha}{\beta} -
\sum_{i=1}^n x_i = 0
\]
Maximum Likelihood Estimation
The maximum likelihood estimates of \(\alpha\) and \(\beta\), denoted by \(\hat{\alpha}\) and \(\hat{\beta}\), are the solutions to the
above system of score equations.
Information Matrix
\(\mathcal{I}_n(2,2)\) is the (2,2)
element of the Fisher information matrix of \(\alpha\) and \(\beta\) based on entire sample with size
\(n\):
\[
\mathcal{I}_n(\alpha, \beta) = - E\begin{pmatrix}
\frac{\partial^2\ell}{\partial \alpha^2} &
\frac{\partial^2\ell}{\partial\alpha\partial\beta} \\
\frac{\partial^2\ell}{\partial\beta\partial\alpha}&
\frac{\partial^2\ell}{\partial\beta^2} \end{pmatrix} = -\begin{pmatrix}
n\psi'(\alpha) & \frac{n}{\beta} \\ \frac{n}{\beta} &
\frac{n\alpha}{\beta^2} \end{pmatrix}
\]
Remark: For the likelihood ratio test, we must
obtain both the restricted and unrestricted maximum likelihood estimates
(MLEs). The restricted MLE is derived under the null hypothesis \(H_0: \alpha = 1\) (i.e., \(\alpha\) fixed to a constant), while the
unrestricted MLE treats both \(\alpha\)
and \(\beta\) as unknown parameters. In
general, these MLEs must be obtained using numerical approximation
methods.
Numerical
Implementation
The dataset used in this example contains measurements of microtubule
catastrophe times (the time until a microtubule stops growing). In their
Cell paper (2011), Gardner, Zanic, and colleagues (Gardner, Zanic, et
al. (2011). Cell, 147(5), 1092-1103.) explicitly modeled these
catastrophe times using a gamma distribution. For
illustrative purpose, we only use complete times in this example.
We first load the data into R and then follow the steps above to
perform the three likelihood-based \(\chi^2\) tests.
time2event <- read.table("https://pengdsci.github.io/STA506/w11/Time2Catastrophe.txt")
colnames(time2event) <- "time"
x <- time2event$time
Loglikelihood function
The following R function evaluate the loglikelihood function and will
be used to find the unrestricted MLE of \(\alpha\) and \(\beta\).
# loglikelihood function
log_likelihood <- function(param) {
alpha <- param[1]
beta <- param[2]
n <- length(x)
sum_x <- sum(x)
sum_logx <- sum(log(x))
##
ll <- n * alpha * log(beta) - n * log(gamma(alpha)) +
(alpha - 1) * sum_logx - beta * sum(x)
ll
}
Score Equations: The following R function returns a
vector score functions, computed from the data values and parameter
estimates.
# Score equations (should be zero at solution)
score_equ <-function(par){
alpha <- par[1]
beta <- par[2]
##
n <- length(x)
sum_x <- sum(x)
sum_logx <- sum(log(x))
##
score_alpha <- n * log(beta) - n * digamma(alpha) + sum_logx
score_beta <- n * alpha / beta - sum_x
c(score_alpha, score_beta)
}
Fisher Information Matrix is coded in the
following
FisherInfo <- function(par){
# Fisher information matrix (negative expected Hessian)
# Used for Newton-Raphson update
# It contains only parameters
alpha <- par[1]
beta <- par[2]
# Fisher Info cell
I_11 <- n * trigamma(alpha)
I_12 <- -n / beta
I_22 <- n * alpha / beta^2
# Information matrix
Fisher <- matrix(c(I_11, I_12, I_12, I_22), nrow = 2, byrow = TRUE)
Fisher
}
Maximum Likelihood
Estimation
Instead of relying on special built-in R functions that compute
maximum likelihood estimates (MLEs) for specific distribution families,
we introduce a general purpose optimization function
optim() for obtaining MLEs for arbitrary distributions.
Specifically, we will derive the MLEs of the parameters \(\alpha\) and \(\beta\), along with the corresponding
Fisher information matrix, which will be used in the Score and Wald
tests.
optim() is a wrapper function that provides access to
several optimization algorithms. The specific numerical method invoked
internally depends on the information supplied to the function. In
practice, a popular variant of the Newton–Raphson algorithm known as the
Broyden–Fletcher–Goldfarb–Shanno (BFGS) algorithm is frequently
employed. BFGS requires the gradient (score vector) to efficiently guide
the search toward the optimal solution. The following R code illustrates
how to use the BFGS method via optim().
x <- time2event$time
n = length(x)
# initial values
###
result <- optim(
par = c(100,0.1),
#need to provide initial values to start the iteration.
# Choosing appropriate initial values is critical.
fn = log_likelihood, # Caution: need negative log-likelihood
gr = score_equ, # also nee negative score
method = "BFGS", # calling BFGS algorithm
hessian = TRUE, # return Hessian matrix
control = list( # some controls in numerical iteration
fnscale = -1, # turn the minimization to maximization problem
maxit = 1000, # stopping rule 1: cap number of iterations
reltol = 1e-8, # stopping rule: precision control
REPORT = 10 # The algorithm will print progress updates
# every 10 iterations
)
)
result
$par
[1] 2.407544212 0.005462866
$value
[1] -1458.997
$counts
function gradient
91 20
$convergence
[1] 0
$message
NULL
$hessian
[,1] [,2]
[1,] -108.2844 38844.57
[2,] 38844.5676 -17612367.12
Double check with the hessian matrix using the derived formula
Fisher <- FisherInfo(result$par)
Fisher
[,1] [,2]
[1,] 108.2844 -38624.41
[2,] -38624.4144 17022197.79
Which is consistent with the hessian matrix in the
output of optim().
The variance and covariance matrix can be approximated by inverting
the Fisher Information Matrix or the inverse of the
negative Hessian matrix returned from optim().
varcov <- solve(-result$hessian) # solve() is a matrix inversion function
varcov
[,1] [,2]
[1,] 4.422498e-02 9.753942e-05
[2,] 9.753942e-05 2.719042e-07
That is, \(\text{var}(\alpha) = 4.42\times
10^{-2}\) and \(\text{var}(\beta) =
2.72\times 10^{-7}\).
Two \(\chi^2\) Tests
The three \(\chi^2\) tests are given
respectively in the following.
Likelihood Ratio
Test
We have found the un-restrictive MLEs of \(\alpha\) and \(\beta\):
MLE <- result$par
MLE
[1] 2.407544212 0.005462866
We now find restrictive MLE of \(\beta\) under \(H_0: \alpha = 1\). The optimization
problems becomes single parameter problem.
##
loglik <- function(beta) n*log(beta)-n -beta*sum(x)
##
score <- function(beta) n/beta - sum(x)
##
x <- time2event$time
n = length(x)
result0 <- optim(
par = 0.05, # need to provide initial values to start the iteration.
# Choosing appropriate initial values is critical.
fn = loglik, # Caution: need negative log-likelihood
gr = score, # also nee negative score
method = "BFGS", # calling BFGS algorithm
hessian = TRUE, # return Hessian matrix
control = list( # some controls in numerical iteration
fnscale = -1, # turn the minimization to maximization problem
maxit = 1000, # stopping rule 1: cap number of iterations
reltol = 1e-8, # stopping rule: precision control
REPORT = 10 # The algorithm will print progress updates
# every 10 iterations
)
)
result0
$par
[1] 0.002269067
$value
[1] -1706.65
$counts
function gradient
42 7
$convergence
[1] 0
$message
NULL
$hessian
[,1]
[1,] -50859711
That is the restrictive MLE of \(\beta\), denoted by \(\hat{\beta}=0.002269067\).
The likelihood ratio test statistic is
\[
LR = −2[\ell(\hat{\alpha}, \hat{\beta})−\ell(1,\hat{\beta})] \to
\chi^2_1.
\]
The R code that evaluates the above test statistic is given by
x <- time2event$time
n = length(x)
##
LR = -2*(loglik(result0$par) - log_likelihood(result$par))
LR
[1] 495.3061
Since the chi-square test is always right-tailed, the p-value based
on the test statistic above is given by \(p =
P(\chi^2_1 > LR)\). The p-value can be obtained using the
following R code.
pval <- 1 - pchisq(LR, df = 1)
pval
[1] 0
The p-value is nearly zero, leading to the rejection of the null
hypothesis \(H_0: \alpha = 1\).
Wald \(\chi^2\) Test
The Wald \(\chi^2\) test statistics
for the null hypothesis \(H_0: \alpha =
1\) is given by
\[
W_{\text{Wald}} = [\frac{\hat{\alpha} - 1}{\text{se}(\hat{\alpha})}]^2 =
\frac{(\hat{\alpha}-1)^2}{\text{var}(\hat{\alpha})} \to \chi^2_1
\]
where \(\text{Var}(\hat{\alpha})\)
is the diagonal element of the inverse of the observed Fisher
information matrix (i.e., the variance–covariance matrix). This means
that the Fisher information matrix is required for the Wald test.
Next, we define the test statistic and calculate the p-value using
the following R code
alpha.hat <- result$par[1] # based on the unrestricted likelihood estimation
se.alpha <- sqrt(varcov[1, 1]) # the square root of the top-left diagonal value
W <- (alpha.hat - 1)^2/(se.alpha)^2 # Wald test statistic
##
pval.W <- 1 - pchisq(W, df = 1)
c(W = W, pval.W = pval.W)
W pval.W
4.479778e+01 2.184708e-11
The p-value is also near 0 implying the rejection of the null
hypothesis.
LS0tDQp0aXRsZTogIldhbGQsIFNjb3JlIGFuZCBMaWtlbGlob29kIFJhdGlvIFRlc3RzIg0KYXV0aG9yOiAiQ2hlbmcgUGVuZyINCmRhdGU6ICJXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgdGhlbWU6IGx1bWVuDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge2NzcywgZWNobyA9IEZBTFNFfQ0KI1RPQzo6YmVmb3JlIHsNCiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMS4yZW07DQogIGRpc3BsYXk6IGJsb2NrOw0KICBjb2xvcjogbmF2eTsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KDQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQp9DQoNCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovDQogIGZvbnQtc2l6ZTogMjJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCg0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxNXB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLw0KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgew0KICBjb250ZW50OiAiLiI7DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCn0NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwc3ljaCIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInBzeWNoIikNCiAgbGlicmFyeShwc3ljaCkNCn0NCmlmICghcmVxdWlyZSgiUkNvbG9yQnJld2VyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiUkNvbG9yQnJld2VyIikNCiAgbGlicmFyeShSQ29sb3JCcmV3ZXIpDQp9DQoNCmlmICghcmVxdWlyZSgiYm9vdCIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImJvb3QiKQ0KICBsaWJyYXJ5KGJvb3QpDQp9DQppZiAoIXJlcXVpcmUoImVmZnNpemUiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJlZmZzaXplIikNCiAgbGlicmFyeShlZmZzaXplKQ0KfQ0KIyMgbGlicmFyeShlZmZzaXplKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BDQogICAgICAgICAgICAgICAgICAgICAgKSAgDQpgYGANCg0KXA0KDQojIEludHJvZHVjdGlvbg0KDQoNClRoaXMgbW9kdWxlIGZvY3VzZXMgb24gdGhlIHRocmVlIG1vc3QgY29tbW9ubHkgdXNlZCBzdGF0aXN0aWNhbCB0ZXN0cyBpbiBzdWJzZXF1ZW50IGNvdXJzZXM6IHRoZSBXYWxkLCBTY29yZSwgYW5kIExpa2VsaWhvb2QgUmF0aW8gdGVzdHMuIFRoZXNlIHRocmVlIG1ldGhvZHMgZm9ybSB0aGUgY29ybmVyc3RvbmUgb2YgaW5mZXJlbmNlIGluIHBhcmFtZXRyaWMgbW9kZWxzLCBwcm92aWRpbmcgcG93ZXJmdWwgYW5kIHZlcnNhdGlsZSBhcHByb2FjaGVzIGZvciB0ZXN0aW5nIGh5cG90aGVzZXMsIGNvbnN0cnVjdGluZyBjb25maWRlbmNlIGludGVydmFscywgYW5kIGFzc2Vzc2luZyBtb2RlbCBmaXQuIA0KDQpXaGlsZSByb290ZWQgaW4gdGhlIGVsZWdhbnQgZnJhbWV3b3JrIG9mIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0aW9uLCBlYWNoIHRlc3Qgb2ZmZXJzIGEgZGlzdGluY3QgZ2VvbWV0cmljIG9yIGFsZ2VicmFpYyBwZXJzcGVjdGl2ZSBvbiB0aGUgZXZpZGVuY2UgYWdhaW5zdCBhIG51bGwgaHlwb3RoZXNpcy4gVW5kZXJzdGFuZGluZyB0aGVpciB0aGVvcmV0aWNhbCBmb3VuZGF0aW9ucywgY29tcGFyYXRpdmUgc3RyZW5ndGhzLCBhbmQgaW50cmluc2ljIHJlbGF0aW9uc2hpcHMgaXMgZXNzZW50aWFsIGZvciBtYXN0ZXJpbmcgYWR2YW5jZWQgc3RhdGlzdGljYWwgbWV0aG9kb2xvZ3kgYW5kIGFwcGx5aW5nIGl0IGNvcnJlY3RseSB0byBjb21wbGV4IGRhdGEuDQoNCkluIHRoaXMgbW9kdWxlLCB3ZSB3aWxsIHN0YXRlIGZvcm11bGF0aW9uLCBhc3N1bXB0aW9ucywgc3RlcHMgdG8gcGVyZm9ybSB0aGVzZSB0ZXN0cyBhbmQgZXhwbGFpbmVkIGJ5IG51bWVyaWNhbCBleGFtcGxlcyB3aXRoIG1hbnVhbCBzb2x1dGlvbiBhbmQgdmVyaWZpY2F0aW9uIHVzaW5nIFIuDQoNCg0KIyBSZXZpZXcgb2YgTGlrZWxpaG9vZCBGb3JtdWxhdGlvbiBhbmQgRXN0aW1hdGlvbg0KDQpJbiBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbiwgd2UgZml0IG1vZGVscyBieSBmaW5kaW5nIHBhcmFtZXRlcnMgdGhhdCBtYWtlIHRoZSBvYnNlcnZlZCBkYXRhIG1vc3QgcHJvYmFibGUuIFRoaXMgcHJvY2VzcyBuYXR1cmFsbHkgbGVhZHMgdG8gdGhyZWUgcmVsYXRlZCBtZXRob2RzIGZvciB0ZXN0aW5nIGh5cG90aGVzZXMgc3VjaCBhcyB0aGUgbGlrZWxpaG9vZCByYXRpbywgV2FsZCwgYW5kIHNjb3JlIHRlc3RzLiBFYWNoIHRlc3QgdXNlcyBhIGRpZmZlcmVudCBmZWF0dXJlIG9mIHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uLCBidXQgYWxsIGFyZSByb290ZWQgaW4gdGhlIHNhbWUgcHJpbmNpcGxlcyBvZiBsaWtlbGlob29kIGFuZCBhc3ltcHRvdGljIHRoZW9yeS4gVGhpcyBzZWN0aW9uIHJldmlld3MgYmFzaWNzIG9mIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0aW9uIGFuZCB0aGVpciBhc3ltcHRvdGljIG5vcm1hbGl0eS4NCg0KDQoqKkxpa2VsaWhvb2QgRnVuY3Rpb24qKg0KDQpMZXQgJFhfMSwgWF8yLCBcZG90cywgWF9uJCBiZSBpbmRlcGVuZGVudCBhbmQgaWRlbnRpY2FsbHkgZGlzdHJpYnV0ZWQgKGkuaS5kKSByYW5kb20gdmFyaWFibGVzIHdpdGggcHJvYmFiaWxpdHkgZGVuc2l0eSAob3IgbWFzcykgZnVuY3Rpb24gJGYoeF9pOyBcYm9sZHN5bWJvbHtcdGhldGF9KSQsIHdoZXJlICRcYm9sZHN5bWJvbHtcdGhldGF9ID0gKFx0aGV0YV8xLCBcZG90cywgXHRoZXRhX3ApXlQkIGlzIGEgJHAkLWRpbWVuc2lvbmFsIHBhcmFtZXRlciB2ZWN0b3IuIFRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIGlzOg0KDQokJA0KTChcYm9sZHN5bWJvbHtcdGhldGF9KSA9IFxwcm9kX3tpPTF9Xm4gZih4X2k7IFxib2xkc3ltYm9se1x0aGV0YX0pDQokJA0KDQpUaGUgbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24gaXM6DQoNCiQkDQpcZWxsKFxib2xkc3ltYm9se1x0aGV0YX0pID0gXGxvZyBMKFxib2xkc3ltYm9se1x0aGV0YX0pID0gXHN1bV97aT0xfV5uIFxsb2cgZih4X2k7IFxib2xkc3ltYm9se1x0aGV0YX0pDQokJA0KDQoqKk1heGltdW0gTGlrZWxpaG9vZCBFc3RpbWF0aW9uKioNCg0KVGhlIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0b3IgKE1MRSkgJFxoYXR7XGJvbGRzeW1ib2x7XHRoZXRhfX0kIHNhdGlzZmllczoNCg0KJCQNClxoYXR7XGJvbGRzeW1ib2x7XHRoZXRhfX0gPSBcYXJnXG1heF97XGJvbGRzeW1ib2x7XHRoZXRhfX0gXGVsbChcYm9sZHN5bWJvbHtcdGhldGF9KQ0KJCQNCg0KVW5kZXIgcmVndWxhcml0eSBjb25kaXRpb25zLCAkXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fSQgaXMgb2J0YWluZWQgYnkgc29sdmluZyB0aGUgc2NvcmUgZXF1YXRpb25zOg0KDQokJA0KVShcYm9sZHN5bWJvbHtcdGhldGF9KSA9IFxmcmFje1xwYXJ0aWFsIFxlbGwoXGJvbGRzeW1ib2x7XHRoZXRhfSl9e1xwYXJ0aWFsIFxib2xkc3ltYm9se1x0aGV0YX19ID0gXGJvbGRzeW1ib2x7MH0NCiQkDQoNCg0KKipGaXNoZXIgSW5mb3JtYXRpb24gTWF0cml4KioNCg0KVGhlIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXggb2YgJFx0aGV0YSQgYmFzZWQgb24gYW4gZW50aXJlIHNhbXBsZSB3aXRoIHNpemUgJG4kIGlzIGdpdmVuIGJ5Og0KDQokJA0KSV9uKFxib2xkc3ltYm9se1x0aGV0YX0pID0gRVxsZWZ0Wy1cZnJhY3tccGFydGlhbF4yIFxlbGwoXGJvbGRzeW1ib2x7XHRoZXRhfSl9e1xwYXJ0aWFsIFxib2xkc3ltYm9se1x0aGV0YX0gXHBhcnRpYWwgXGJvbGRzeW1ib2x7XHRoZXRhfV5UfVxyaWdodF0NCiQkDQoNClRoZSBhYm92ZSAodGhlb3JldGljYWwpIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXggcmVxdWlyZXMgaW50ZWdyYWwgdGhhdCBpbnRlZ3JhdGVzIHZhcmlhYmxlcyBvdXQgZnJvbSB0aGUgZXhwcmVzc2lvbi4gSW4gcHJhY3RpY2UsIHdlIHVzZSB0aGUgZm9sbG93aW5nIG9ic2VydmVkIGluZm9ybWF0aW9uIG1hdHJpeDoNCg0KJCQNCkpfbihcYm9sZHN5bWJvbHtcdGhldGF9KSA9IC1cZnJhY3tccGFydGlhbF4yIFxlbGwoXGJvbGRzeW1ib2x7XHRoZXRhfSl9e1xwYXJ0aWFsIFxib2xkc3ltYm9se1x0aGV0YX0gXHBhcnRpYWwgXGJvbGRzeW1ib2x7XHRoZXRhfV5UfQ0KJCQNCg0KU29tZSBzb2Z0d2FyZSBwcm9ncmFtcyByZXR1cm4gSGVzc2lhbiBtYXRyaXggJEhfbiggXGJvbGRzeW1ib2x7XHRoZXRhfSkgPSAtSl9uKCBcYm9sZHN5bWJvbHtcdGhldGF9KSQsIHRoYXQgaXMNCg0KJCQNCkhfbihcYm9sZHN5bWJvbHtcdGhldGF9KSA9IFxmcmFje1xwYXJ0aWFsXjIgXGVsbChcYm9sZHN5bWJvbHtcdGhldGF9KX17XHBhcnRpYWwgXGJvbGRzeW1ib2x7XHRoZXRhfSBccGFydGlhbCBcYm9sZHN5bWJvbHtcdGhldGF9XlR9DQokJA0KDQpOb3RlIHRoYXQsIGluIHNvbWUgdGV4dGJvb2tzLCByZXNlYXJjaCBhcnRpY2xlcyBhbmQgd2ViIHBvc3RpbmdzLCB0aGUgKipGaXNoZXIgSW5mb3JtYXRpb24gTWF0cml4KiogYmFzZWQgb24gc2luZ2xlIGRhdGEgcG9pbnQgaXMgZGVub3RlZCBieSAkSV8wKFxib2xkc3ltYm9se1x0aGV0YX0pJCwNCg0KJCQNCklfbihcYm9sZHN5bWJvbHtcdGhldGF9KSA9IG5cdGltZXMgSV8xKFxib2xkc3ltYm9se1x0aGV0YX0pDQokJA0KDQpVbmRlciBzb21lIHJlZ3VsYXJpdHkgY29uZGl0aW9ucyBhbmQgdGhlIG51bGwgaHlwb3RoZXNpcyAkSF8wOiBcYm9sZHN5bWJvbHtcdGhldGF9ID0gXGJvbGRzeW1ib2x7XHRoZXRhfV8wJCwgd2UgaGF2ZSB0aGUgZm9sbG93aW5nIA0KDQokJA0KXHNxcnR7bn0oXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fSAtIFxib2xkc3ltYm9se1x0aGV0YX1fMCkgXHhyaWdodGFycm93e2R9IE4oXGJvbGRzeW1ib2x7MH0sIElfMV57LTF9KFxib2xkc3ltYm9se1x0aGV0YX1fMCkpLg0KJCQNCg0KDQpUaGUgcmVsYXRpb25zaGlwIGJldHdlZW4gKipGaXNoZXIgSW5mb3JtYXRpb24gTWF0cml4Kiogb2YgJFxib2xkc3ltYm9se1x0aGV0YX0kIGFuZCB0aGUgdmFyaWFuY2Ugb2YgdGhlIE1MRSAkXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fSQgaXMNCg0KJCQNClx0ZXh0e3Zhcn0oXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fSkgXGFwcHJveCBJX25eey0xfShcYm9sZHN5bWJvbHtcdGhldGF9KSA9IFtuXHRpbWVzIElfMShcYm9sZHN5bWJvbHtcdGhldGF9KV1eey0xfSA9IFxmcmFje0lfMV57LTF9KFxib2xkc3ltYm9se1x0aGV0YX0pfXtufQ0KJCQNClRoZXJlZm9yZSwgd2UgY2FuIHJld3JpdGUgdGhlIGFib3ZlIGFzeW1wdG90aWMgZGlzdHJpYnV0aW9uIG9mICRcYm9sZHN5bWJvbHtcdGhldGF9JCBhcw0KDQokJA0KXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fVx0byBOXGxlZnQoIFxib2xkc3ltYm9se1x0aGV0YX0sIFxmcmFje0lfMV57LTF9KFxib2xkc3ltYm9se1x0aGV0YX0pfXtufSBccmlnaHQpIFxxdWFkIFx0ZXh0e29yIGVxdWl2YWxlbnRseX0gXHF1YWQgXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fVx0byBOXGxlZnQoIFxib2xkc3ltYm9se1x0aGV0YX0sIElfbl57LTF9KFxib2xkc3ltYm9se1x0aGV0YX0pIFxyaWdodCkNCiQkDQoNClRoZSBkaWFnb25hbCBlbGVtZW50cyBpbiB0aGUgY292YXJpYW5jZSAkSV9uXnstMX0oXGJvbGRzeW1ib2x7XHRoZXRhfSkkIHJlcHJlc2VudCB0aGUgdmFyaWFuY2Ugb2YgdGhlIGNvcnJlc3BvbmRpbmcgcGFyYW1ldGVycyBpbiAkXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fSA9IChcaGF0e1x0aGV0YX1fMSwgXGhhdHtcdGhldGF9XzIsIFxjZG90cywgXGhhdHtcdGhldGFfa30pJC4gRm9yIGV4YW1wbGUuICRcdGV4dHt2YXJ9KFxoYXR7XHRoZXRhfV8xKSA9ICQgdGhlIGZpcnN0IGVsZW1lbnQgaW4gdGhlIG1haW4gZGlhZ29uYWwgb2YgdGhlIGludmVyc2Ugb2YgdGhlIGZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXggYmFzZWQgb24gdGhlIGVudGlyZSBzYW1wbGUuICANCg0KRm9yIGV4YW1wbGUsIGxldCAkXGJvbGRzeW1ib2x7XHRoZXRhfSA9KFx0aGV0YV8xLCBcdGhldGFfMikkLCB0aGUgY29ycmVzcG9uZGluZyBNTEUgaXMgJFxoYXR7XGJvbGRzeW1ib2x7XHRoZXRhfX0gPShcaGF0e1x0aGV0YV8xfSwgXGhhdHtcdGhldGFfMil9JC4gTGV0IHRoZSAqKm9ic2VydmVkIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXgqKiBiZQ0KDQokJA0KSl9uKFxib2xkc3ltYm9se1x0aGV0YX0pID0gLVxmcmFje1xwYXJ0aWFsXjIgXGVsbChcYm9sZHN5bWJvbHtcdGhldGF9KX17XHBhcnRpYWwgXGJvbGRzeW1ib2x7XHRoZXRhfSBccGFydGlhbCBcYm9sZHN5bWJvbHtcdGhldGF9XlR9PS1cYmVnaW57cG1hdHJpeH0NClxmcmFje1xwYXJ0aWFsXjIgXGVsbChcYm9sZHN5bWJvbHtcdGhldGF9KX17XHBhcnRpYWxeMiBcdGhldGFfMX0gJiBcZnJhY3tccGFydGlhbF4yIFxlbGwoXGJvbGRzeW1ib2x7XHRoZXRhfSl9e1xwYXJ0aWFsIFx0aGV0YV8xXHBhcnRpYWwgXHRoZXRhXzJ9IFxcDQpcZnJhY3tccGFydGlhbF4yIFxlbGwoXGJvbGRzeW1ib2x7XHRoZXRhfSl9e1xwYXJ0aWFsIFx0aGV0YV8yXHBhcnRpYWwgXHRoZXRhXzF9ICYgXGZyYWN7XHBhcnRpYWxeMiBcZWxsKFxib2xkc3ltYm9se1x0aGV0YX0pfXtccGFydGlhbF4yIFx0aGV0YV8yfQ0KXGVuZHtwbWF0cml4fQ0KJCQNCg0KVGhlIGVzdGltYXRlZCBGaXNoZXIgaW5mb3JtYXRpb24gbWF0cml4IGlzIGdpdmVuIGJ5DQoNCiQkDQpcd2lkZWhhdHtKX24oXGJvbGRzeW1ib2x7XHRoZXRhfSl9ID0gLVxiZWdpbntwbWF0cml4fQ0KXGZyYWN7XHBhcnRpYWxeMiBcZWxsKFxib2xkc3ltYm9se1x0aGV0YX0pfXtccGFydGlhbF4yIFx0aGV0YV8xfSAmIFxmcmFje1xwYXJ0aWFsXjIgXGVsbChcYm9sZHN5bWJvbHtcdGhldGF9KX17XHBhcnRpYWwgXHRoZXRhXzFccGFydGlhbCBcdGhldGFfMn0gXFwNClxmcmFje1xwYXJ0aWFsXjIgXGVsbChcYm9sZHN5bWJvbHtcdGhldGF9KX17XHBhcnRpYWwgXHRoZXRhXzJccGFydGlhbCBcdGhldGFfMX0gJiBcZnJhY3tccGFydGlhbF4yIFxlbGwoXGJvbGRzeW1ib2x7XHRoZXRhfSl9e1xwYXJ0aWFsXjIgXHRoZXRhXzJ9DQpcZW5ke3BtYXRyaXh9XEJpZ2d8X3tcYm9sZHN5bWJvbHtcdGhldGF9ID0gXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fX0uDQokJA0KDQpOb3RlIHRoYXQgUiBmdW5jdGlvbiBgb3B0aW0oKWAgcmV0dXJucyBIZXNzaWFuIG1hdHJpeCAkXHdpZGVoYXR7SF9uKFxib2xkc3ltYm9se1x0aGV0YX0pfT0tIFx3aWRlaGF0e0pfbihcYm9sZHN5bWJvbHtcdGhldGF9KX0kLg0KDQpMZXQgdGhlIGludmVyc2Ugb2YgJHdpZGVoYXR7Sl9uKFxib2xkc3ltYm9se1x0aGV0YX0pfSQgYmUgb2YgdGhlIGZvbGxvd2luZyBmb3JtDQoNCiQkDQpcbGVmdFtcd2lkZWhhdHtKX24oXGJvbGRzeW1ib2x7XHRoZXRhfSl9XHJpZ2h0XV57LTF9ID0gLVxsZWZ0W1xiZWdpbntwbWF0cml4fQ0KXGZyYWN7XHBhcnRpYWxeMiBcZWxsKFxib2xkc3ltYm9se1x0aGV0YX0pfXtccGFydGlhbF4yIFx0aGV0YV8xfSAmIFxmcmFje1xwYXJ0aWFsXjIgXGVsbChcYm9sZHN5bWJvbHtcdGhldGF9KX17XHBhcnRpYWwgXHRoZXRhXzFccGFydGlhbCBcdGhldGFfMn0gXFwNClxmcmFje1xwYXJ0aWFsXjIgXGVsbChcYm9sZHN5bWJvbHtcdGhldGF9KX17XHBhcnRpYWwgXHRoZXRhXzJccGFydGlhbCBcdGhldGFfMX0gJiBcZnJhY3tccGFydGlhbF4yIFxlbGwoXGJvbGRzeW1ib2x7XHRoZXRhfSl9e1xwYXJ0aWFsXjIgXHRoZXRhXzJ9DQpcZW5ke3BtYXRyaXh9XEJpZ2d8X3tcYm9sZHN5bWJvbHtcdGhldGF9ID0gXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fX1ccmlnaHRdXnstMX0NCj1cYmVnaW57cG1hdHJpeH0NCmEgJiBjIFxcDQpjICYgZA0KXGVuZHtwbWF0cml4fS4NCiQkDQoNClRoZW4gd2UgaGF2ZQ0KDQokJA0KXHdpZGVoYXR7XHRleHR7dmFyfShcaGF0e1xib2xkc3ltYm9se1x0aGV0YX0pfX0gXGFwcHJveCBcYmVnaW57cG1hdHJpeH0NCmEgJiBjIFxcDQpjICYgZA0KXGVuZHtwbWF0cml4fS4NCiQkDQoNClRoYXQgaXMsDQoNCiQkDQpcdGV4dHt2YXJ9KFxoYXR7XHRoZXRhfV8xKSBcYXBwcm94IGEsIFxxdWFkICBcdGV4dHt2YXJ9KFxoYXR7XHRoZXRhfV8yKSBcYXBwcm94IGQsIFxxdWFkIFx0ZXh0e2FuZH0gXHF1YWQgIFx0ZXh0e2Nvdn0oXGhhdHtcdGhldGF9XzEsIFxoYXR7XHRoZXRhfV8yKSBcYXBwcm94IGMuDQokJA0KDQpUaGUgYWJvdmUgYXN5bXB0b3RpYyBub3JtYWxpdHkgaXMgdGhlIGZvdW5kYXRpb24gb2YgdGhlIFdhbGQgYW5kIFNjb3JlIHRlc3RzLg0KDQoNClwNCg0KIyBUaGUgVGhyZWUgQXN5bXB0b3RpYyAkXGNoaV4yJCBUZXN0cw0KDQpBdCB0aGUgZm91bmRhdGlvbiBvZiBwYXJhbWV0cmljIGh5cG90aGVzaXMgdGVzdGluZyBsaWVzIGEgdHJpbyBvZiBhc3ltcHRvdGljYWxseSBlcXVpdmFsZW50IG1ldGhvZHM6IHRoZSBsaWtlbGlob29kIHJhdGlvLCBXYWxkLCBhbmQgc2NvcmUgdGVzdHMuIEFsbCB0aHJlZSBkZXJpdmUgZnJvbSBtYXhpbXVtIGxpa2VsaWhvb2QgdGhlb3J5IGFuZCBjb252ZXJnZSB0byB0aGUgc2FtZSBjaGktc3F1YXJlZCBkaXN0cmlidXRpb24gdW5kZXIgdGhlIG51bGwgaHlwb3RoZXNpcywgeWV0IHRoZXkgYXBwcm9hY2ggdGhlIHByb2JsZW0gb2YgdGVzdGluZyBmcm9tIG1lYW5pbmdmdWxseSBkaWZmZXJlbnQgYW5nbGVzLg0KDQpUaGUgKipsaWtlbGlob29kIHJhdGlvIHRlc3QqKiBkaXJlY3RseSBjb21wYXJlcyB0aGUgZ29vZG5lc3Mtb2YtZml0IGJldHdlZW4gdGhlIHVucmVzdHJpY3RlZCBtb2RlbCBhbmQgdGhlIG1vZGVsIGNvbnN0cmFpbmVkIGJ5IHRoZSBudWxsIGh5cG90aGVzaXMuIFRoZSAqKldhbGQgdGVzdCoqIGV2YWx1YXRlcyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGUgZXN0aW1hdGVkIHBhcmFtZXRlciB2ZWN0b3IgYW5kIGl0cyBoeXBvdGhlc2l6ZWQgdmFsdWUsIHN0YW5kYXJkaXplZCBieSB0aGUgZXN0aW1hdGVkIGN1cnZhdHVyZSBvZiB0aGUgbGlrZWxpaG9vZC4gVGhlICoqc2NvcmUgdGVzdCoqLCBhbHRlcm5hdGl2ZWx5LCBleGFtaW5lcyB3aGV0aGVyIHRoZSBzbG9wZSBvZiB0aGUgbG9nLWxpa2VsaWhvb2QgYXQgdGhlIG51bGwgcGFyYW1ldGVyIHZhbHVlIGlzIHN1ZmZpY2llbnRseSBjbG9zZSB0byB6ZXJv4oCUYW4gaW5kaWNhdGlvbiB0aGF0IHRoZSBudWxsIHBvaW50IGlzIGEgcGxhdXNpYmxlIG1heGltdW0uDQoNCkRlc3BpdGUgdGhlaXIgYXN5bXB0b3RpYyBlcXVpdmFsZW5jZSwgdGhlc2UgdGVzdHMgZGlmZmVyIGluIGNvbXB1dGF0aW9uLCBmaW5pdGUtc2FtcGxlIHBlcmZvcm1hbmNlLCBhbmQgaW52YXJpYW5jZSBwcm9wZXJ0aWVzLCBsZWFkaW5nIHRvIHByYWN0aWNhbCB0cmFkZS1vZmZzIGluIGFwcGxpZWQgd29yay4gVGhlIGZvbGxvd2luZyBzdWItc2VjdGlvbnMgZGV2ZWxvcCB0aGVpciBmb3JtdWxhdGlvbnMsIGNvbnRyYXN0cyB0aGVpciB0aGVvcmV0aWNhbCBhbmQgcHJhY3RpY2FsIGF0dHJpYnV0ZXMsIGFuZCBwcm92aWRlIGd1aWRhbmNlIGZvciBjaG9vc2luZyBhbW9uZyB0aGVtIGluIHN0YXRpc3RpY2FsIG1vZGVsaW5nLg0KDQoNCg0KIyMgV2FsZCBUZXN0DQoNCioqRm9ybXVsYXRpb24qKiBUZXN0cyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGUgKip1bmNvbnN0cmFpbmVkIE1MRSoqIGFuZCB0aGUgKipoeXBvdGhlc2l6ZWQgdmFsdWUqKi4gSXQgbWVhc3VyZXMgKipnZW9tZXRyaWMgZGlzcGxhY2VtZW50KiogZnJvbSAkSF8wJCBpbiBwYXJhbWV0ZXIgc3BhY2UuIFRvIG1ha2UgaXQgc2ltcGxlLCBsZXQncyAkXGJvbGRzeW1ib2x7XHRoZXRhfSA9IChcdGhldGFfMSwgXHRoZXRhXzIpJCBiZSB0aGUgdmVjdG9yIG9mIHRoZSBwYXJhbWV0ZXJzIG9mIGEgZGlzdHJpYnV0aW9uLiBDb25zaWRlciBoeXBvdGhlc2lzIA0KDQokJA0KSF8wOiBcYm9sZHN5bWJvbHtcdGhldGF9ID0gXGJvbGRzeW1ib2x7XHRoZXRhfV8wLCBccXVhZCBcdGV4dHtpLmUufVxxdWFkIFxiZWdpbntwbWF0cml4fQ0KXHRoZXRhXzEgIFxcDQpcdGhldGFfMiANClxlbmR7cG1hdHJpeH0NCj0NClxiZWdpbntwbWF0cml4fQ0KXHRoZXRhX3sxMH0gIFxcDQpcdGhldGFfezIwfSANClxlbmR7cG1hdHJpeH0uDQokJA0KDQpUaGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSAqKmh5cG90aGVzaXplZCB2YWx1ZSoqIGFuZCB0aGUgKip1bnJlc3RyaWN0ZWQgTUxFKiogaXMgZ2l2ZW4gYnkNCg0KJCQNCkQgPSBcaGF0e1xib2xkc3ltYm9se1x0aGV0YX19IC0gXGJvbGRzeW1ib2x7XHRoZXRhfV8wID0gXGJlZ2lue3BtYXRyaXh9DQpcaGF0e1x0aGV0YX1fMSAtXHRoZXRhX3sxMH0gIFxcDQpcaGF0e1x0aGV0YX1fMiAtXHRoZXRhX3syMH0NClxlbmR7cG1hdHJpeH0NCiQkDQoNCg0KKipUZXN0IFN0YXRpc3RpYyoqDQoNCldpdGggdGhlIGFib3ZlIG5vdGF0aW9ucywgdGhlIFdhbGQgdGVzdCBzdGF0aXN0aWMgaXMgZ2l2ZW4gYnkNCg0KJCQNClcgPSBcaGF0e0R9XntUfSBcLCBcbGVmdFsgXHdpZGVoYXR7XHRleHR7dmFyfShcaGF0e1xib2xkc3ltYm9se1x0aGV0YX19KX1ccmlnaHRdXnstMX0gXCwgXGhhdHtEfSAgPSBcaGF0e0R9XntUfSBcLFx0ZXh0e0l9X24oXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fSkgXCwgXGhhdHtEfSANCiQkDQoNCk1vcmUgZXhwbGljaXRseSwgd2UgaGF2ZQ0KDQokJA0KVyA9IA0KXGJlZ2lue3BtYXRyaXh9IA0KXGhhdHtcdGhldGF9XzEgLSBcdGhldGFfezEwfSAmIFxoYXR7XHRoZXRhfV8yIC0gXHRoZXRhX3syMH0NClxlbmR7cG1hdHJpeH0NClxiZWdpbntwbWF0cml4fQ0KXHRleHR7dmFyfShcaGF0e1x0aGV0YX1fMSkgJiBcdGV4dHtjb3Z9KFxoYXR7XHRoZXRhfV8xLCBcaGF0e1x0aGV0YX1fMikgXFwNClx0ZXh0e2Nvdn0oXGhhdHtcdGhldGF9XzEsIFxoYXR7XHRoZXRhfV8yKSAmIFx0ZXh0e3Zhcn0oXGhhdHtcdGhldGF9XzIpDQpcZW5ke3BtYXRyaXh9XnstMX0NClxiZWdpbntwbWF0cml4fQ0KXGhhdHtcdGhldGF9XzEgLSBcdGhldGFfezEwfSBcXA0KXGhhdHtcdGhldGF9XzIgLSBcdGhldGFfezIwfQ0KXGVuZHtwbWF0cml4fS4NCiQkDQoNCg0KDQpGb3IgdGVzdGluZyBzaW5nbGUgcGFyYW1ldGVyIGNhc2UgJEhfMDogXGJvbGRzeW1ib2x7XHRoZXRhfV8xID0gXGJvbGRzeW1ib2x7XHRoZXRhfV97MTB9JA0KDQoNCiQkDQpXID0gKFxoYXR7XHRoZXRhfSAtIFx0aGV0YV8wKVtcdGV4dHt2YXJ9KFxoYXR7XHRoZXRhfV8xKV1eey0xfShcaGF0e1x0aGV0YX0gLSBcdGhldGFfMCkgPSBcZnJhY3soXGhhdHtcdGhldGF9IC0gXHRoZXRhXzApXjJ9e1x0ZXh0e3Zhcn0oXGhhdHtcdGhldGF9XzEpfQ0KJCQNCg0KDQoNCioqQXN5bXB0b3RpYyBEaXN0cmlidXRpb24qKjogJFcgXHhyaWdodGFycm93e2R9IFxjaGleMl9xJCB1bmRlciAkSF8wJCwgIHdoZXJlICRxJCBpcyB0aGUgbnVtYmVyIG9mIHBhcmFtZXRlcnMgc3BlY2lmaWVkIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMuDQoNCkluIHRoZSB0d28tcGFyYW1ldGVyIGFuZCBvbmUtcGFyYW1ldGVyIGNhc2VzIGRlc2NyaWJlZCBhYm92ZSwgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSBvZiB0aGUgJFxjaGleMiQgdGVzdCBhcmUgJHEgPSAyJCBhbmQgJHE9MSQsIHJlc3BlY3RpdmVseS4NCg0KDQoNCioqQXNzdW1wdGlvbnMqKjogV2FsZCB0ZXN0IHJlcXVpcmVzIG9ubHkgdGhlIHVuY29uc3RyYWluZWQgTUxFIChhcyB3ZWxsIGFzIEluZm9ybWF0aW9uIG1hdHJpeCB0byBkZXJpdmUgdGhlIGNvdmFyaWFuY2UgbWF0cml4IG9mIHRoZSBNTEUpIGFuZCBpcyBzZW5zaXRpdmUgdG8gcGFyYW1ldGVyaXphdGlvbi4NCg0KDQoNCiMjIFNjb3JlIFRlc3QgKFJhbydzIFNjb3JlIFRlc3QpDQoNClJhbydzIHNjb3JlIGlzIGFsc28ga25vd24gYXMgdGhlICoqTGFncmFuZ2UgbXVsdGlwbGllciB0ZXN0KiouDQoNCioqRm9ybXVsYXRpb24qKjogVGVzdHMgd2hldGhlciB0aGUgc2NvcmUgYXQgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHplcm8uIEl0IG1lYXN1cmVzIGxvY2FsIGdyYWRpZW50IGF0ICRIXzAkIGluIGxpa2VsaWhvb2Qgc3BhY2UuDQoNCioqVGVzdCBTdGF0aXN0aWMqKjoNCg0KJCQNClMgPSBVKFx0aWxkZXtcYm9sZHN5bWJvbHtcdGhldGF9fSleVCBJX25eey0xfShcdGlsZGV7XGJvbGRzeW1ib2x7XHRoZXRhfX0pIFUoXHRpbGRle1xib2xkc3ltYm9se1x0aGV0YX19KQ0KJCQNCndoZXJlICRcdGlsZGV7XGJvbGRzeW1ib2x7XHRoZXRhfX0kIGlzIHRoZSBNTEUgdW5kZXIgJEhfMCQgKGNvbnN0cmFpbmVkIE1MRSkuDQoNCioqQXN5bXB0b3RpYyBEaXN0cmlidXRpb24qKjogJFMgXHhyaWdodGFycm93e2R9IFxjaGleMl9xJCB1bmRlciAkSF8wJC4NCg0KKipBc3N1bXB0aW9ucyoqOiBSZXF1aXJlcyBvbmx5IHRoZSBjb25zdHJhaW5lZCBNTEUuIEludmFyaWFudCB0byByZXBhcmFtZXRlcml6YXRpb24uDQoNCg0KIyMgTGlrZWxpaG9vZCBSYXRpbyBUZXN0DQoNCioqRm9ybXVsYXRpb24qKjogQ29tcGFyZXMgdGhlIG1heGltaXplZCBsb2ctbGlrZWxpaG9vZCB1bmRlciAkSF8wJCBhbmQgJEhfMSQuIEl0IG1lYXN1cmVzIGluZm9ybWF0aW9uIGxvc3Mgd2hlbiBpbXBvc2luZyAkSF8wJC4NCg0KKipUZXN0IFN0YXRpc3RpYyoqOg0KDQokJA0KXExhbWJkYSA9IC0yW1xlbGwoXHRpbGRle1xib2xkc3ltYm9se1x0aGV0YX19KSAtIFxlbGwoXGhhdHtcYm9sZHN5bWJvbHtcdGhldGF9fSldID0gMltcZWxsKFxoYXR7XGJvbGRzeW1ib2x7XHRoZXRhfX0pIC0gXGVsbChcdGlsZGV7XGJvbGRzeW1ib2x7XHRoZXRhfX0pXQ0KJCQNCg0KKipBc3ltcHRvdGljIERpc3RyaWJ1dGlvbioqOiAkXExhbWJkYSBceHJpZ2h0YXJyb3d7ZH0gXGNoaV4yX3EkIHVuZGVyICRIXzAkLg0KDQoqKkFzc3VtcHRpb25zKio6IFJlcXVpcmVzIGJvdGggY29uc3RyYWluZWQgYW5kIHVuY29uc3RyYWluZWQgTUxFcy4gSW52YXJpYW50IHRvIHJlcGFyYW1ldGVyaXphdGlvbi4NCg0KXA0KDQoNCg0KIyBQcmFjdGljYWwgRXhhbXBsZXM6IFNpbmdsZSBQYXJhbWV0ZXINCg0KVG8gY29uY3JldGVseSBkZW1vbnN0cmF0ZSB0aGUgc2ltaWxhcml0aWVzIGFuZCBkaWZmZXJlbmNlcyBhbW9uZyB0aGUgdGhyZWUgbGlrZWxpaG9vZC1iYXNlZCB0ZXN0cywgd2Ugbm93IHR1cm4gdG8gcHJhY3RpY2FsIGltcGxlbWVudGF0aW9uIGluIFIuIFdoaWxlIHRoZXNlIHRlc3RzIG9mdGVuIHlpZWxkIHNpbWlsYXIgY29uY2x1c2lvbnMgd2l0aCBsYXJnZSBzYW1wbGVzLCB0aGVpciBkaXN0aW5jdGlvbnMgYmVjb21lIHBhcnRpY3VsYXJseSBpbnN0cnVjdGl2ZSB3aGVuIGV4YW1pbmluZyBzaW1wbGUgeWV0IGZ1bmRhbWVudGFsIGRpc3RyaWJ1dGlvbnMuIA0KDQpUaHJvdWdoIGhhbmRzLW9uIGV4YW1wbGVzIHVzaW5nIFBvaXNzb24gYW5kIG5vcm1hbCBkaXN0cmlidXRpb25zLCB3ZSB3aWxsIHN5c3RlbWF0aWNhbGx5IGFwcGx5IHRoZSBMaWtlbGlob29kIFJhdGlvLCBXYWxkLCBhbmQgU2NvcmUgdGVzdHMgdG8gaWRlbnRpY2FsIGh5cG90aGVzZXMuIFRoaXMgY29tcGFyYXRpdmUgYXBwcm9hY2ggd2lsbCBpbGx1bWluYXRlIGhvdyBlYWNoIHRlc3Qgc3RhdGlzdGljIGlzIGNhbGN1bGF0ZWQsIHNob3djYXNlIHNjZW5hcmlvcyB3aGVyZSB0aGVpciByZXN1bHRzIGRpdmVyZ2UgbWVhbmluZ2Z1bGx5LCBhbmQgcHJvdmlkZSByZXVzYWJsZSBjb2RlIHRlbXBsYXRlcyB0aGF0IHJldmVhbCB0aGUgY29tcHV0YXRpb25hbCBtYWNoaW5lcnkgdW5kZXJseWluZyBjb21tb24gc3RhdGlzdGljYWwgcHJvY2VkdXJlcy4gDQoNCjxmb250IGNvbG9yID0gImJsdWUiPioqVW5saWtlIHQtdGVzdHMgYW5kIHotdGVzdHMgd2hpY2ggaGF2ZSBjbG9zZWQtZm9ybSBmb3JtdWxhcywgbGlrZWxpaG9vZC1iYXNlZCBjaGktc3F1YXJlZCB0ZXN0cyByZXF1aXJlIGV4cGxpY2l0IGRlcml2YXRpb24gb2YgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24sIHBhcmFtZXRlciBlc3RpbWF0aW9uIHVuZGVyIG51bGwvYWx0ZXJuYXRpdmUsIGFuZCBjYXJlZnVsIGNvbnN0cnVjdGlvbiBvZiB0aGUgdGVzdCBzdGF0aXN0aWNzLiBUaGlzIGlzIHdoeSB0aGV5J3JlIG1vcmUgZmxleGlibGUgYnV0IHJlcXVpcmUgbW9yZSBwcmVwYXJhdGlvbi4qKjwvZm9udD4gVGhlIGtleSBwcmVwYXJhdGlvbiBzdGVwcyByZXF1aXJlZA0KDQoqIERlcml2ZSBsb2ctbGlrZWxpaG9vZCBmdW5jdGlvbiAkXGVsbChcdGhldGE7IHgpJA0KKiBEZXJpdmUgc2NvcmUgZnVuY3Rpb24gJFUoXHRoZXRhKSA9IFxwYXJ0aWFsIFxlbGwvXHBhcnRpYWwgXHRoZXRhJA0KKiBEZXJpdmUgRmlzaGVyIEluZm9ybWF0aW9uICRJX24oXHRoZXRhKSA9IC1FW1xwYXJ0aWFsXjIgXGVsbC9ccGFydGlhbCBcdGhldGFeMl0kDQoqIEZpbmQgTUxFcyB1bmRlciBib3RoICRIXzAkIGFuZCAkSF8xJA0KKiBDb21wdXRlIHN0YW5kYXJkIGVycm9ycyBmcm9tIGludmVyc2UgRmlzaGVyIEluZm9ybWF0aW9uDQoqIENvbnN0cnVjdCB0ZXN0IHN0YXRpc3RpY3MgdXNpbmcgYXBwcm9wcmlhdGUgZm9ybXVsYXMNCg0KPGZvbnQgY29sb3IgPSAicmVkIj4qKk5vdGUgdGhhdCBsaWtlbGlob29kLWJhc2VkIGluZmVyZW5jZXMgcmVseSBvbiBsYXJnZS1zYW1wbGUgYXN5bXB0b3RpYyB0aGVvcnkuIEZvciB0aGUgcHVycG9zZSBvZiBjbGVhcmx5IGlsbHVzdHJhdGluZyB0aGUgcHJvY2VkdXJlLCB0aGUgZXhhbXBsZXMgaW4gdGhlIGZvbGxvd2luZyBzdWJzZWN0aW9ucyB3aWxsIHVzZSBzbWFsbCB0b3kgZGF0YXNldHMuKio8L2ZvbnQ+DQoNCg0KIyMgRXhhbXBsZSAxOiBQb2lzc29uIERpc3RyaWJ1dGlvbg0KDQoqKlByb2JsZW0qKjogVGVzdCAkSF8wOiBcbGFtYmRhID0gMiQgdnMgJEhfMTogXGxhbWJkYSBcbmVxIDIkIGZvciAkWF8xLCBcZG90cywgWF9uIFxzaW0gXHRleHR7UG9pc3Nvbn0oXGxhbWJkYSkkLiANCg0KKipPYnNlcnZlZCBkYXRhKio6IDMsIDEsIDQsIDIsIDMuDQoNCioqTWFudWFsIFNvbHV0aW9uKio6DQoNCiogKipMaWtlbGlob29kKio6ICRMKFxsYW1iZGEpID0gXHByb2Rfe2k9MX1ebiBcZnJhY3tlXnstXGxhbWJkYX0gXGxhbWJkYV57eF9pfX17eF9pIX0kDQogICAgDQoqICoqTG9nLWxpa2VsaWhvb2QqKjogJFxlbGwoXGxhbWJkYSkgPSAtblxsYW1iZGEgKyAoXHN1bSB4X2kpXGxvZ1xsYW1iZGEgLSBcc3VtIFxsb2coeF9pISkkDQogICAgDQoqICoqTUxFKio6ICRcaGF0e1xsYW1iZGF9ID0gXGJhcnt4fSA9IFxmcmFjezMrMSs0KzIrM317NX0gPSAyLjYkDQogICAgDQoqICoqU2NvcmUgZnVuY3Rpb24qKjogJFUoXGxhbWJkYSkgPSBcZnJhY3tkXGVsbH17ZFxsYW1iZGF9ID0gLW4gKyBcZnJhY3tcc3VtIHhfaX17XGxhbWJkYX0kDQogICAgDQoqICoqSW5mb3JtYXRpb24qKjogJElfbihcbGFtYmRhKSA9IFxmcmFje259e1xsYW1iZGF9JCAoZXhwZWN0ZWQpLCAkSl9uKFxsYW1iZGEpID0gXGZyYWN7XHN1bSB4X2l9e1xsYW1iZGFeMn0kIChvYnNlcnZlZCkNCg0KDQoqKldhbGQgVGVzdCoqDQoNCiQkDQpXID0gKFxoYXR7XGxhbWJkYX0gLSBcbGFtYmRhXzApXjIgXGhhdHtJfV9uKFxoYXR7XGxhbWJkYX0pID0gKDIuNiAtIDIpXjIgXHRpbWVzIFxmcmFjezV9ezIuNn0gPSAwLjM2IFx0aW1lcyAxLjkyMyA9IDAuNjkyDQokJA0KVXNpbmcgb2JzZXJ2ZWQgaW5mb3JtYXRpb246ICRXID0gKDAuNileMiBcdGltZXMgXGZyYWN7MTN9ezIuNl4yfSA9IDAuMzYgXHRpbWVzIDEuOTIzID0gMC42OTIkDQoNCioqU2NvcmUgVGVzdCoqDQoNClNjb3JlIGF0ICRcbGFtYmRhXzA9MiQ6ICRVKDIpID0gLTUgKyBcZnJhY3sxM317Mn0gPSAxLjUkDQoNCiQkDQpJKDIpID0gXGZyYWN7NX17Mn0gPSAyLjUNCiQkDQoNCiQkDQpTID0gVSgyKV4yIElfbl57LTF9KDIpID0gKDEuNSleMiBcdGltZXMgXGZyYWN7MX17Mi41fSA9IDIuMjUgXHRpbWVzIDAuNCA9IDAuOQ0KJCQNCg0KKipMaWtlbGlob29kIFJhdGlvIFRlc3QqKg0KDQokJA0KXGVsbChcaGF0e1xsYW1iZGF9KSA9IC01KDIuNikgKyAxM1xsb2coMi42KSAtIFxzdW0gXGxvZyh4X2khKSA9IC0xMyArIDEzKDAuOTU1NSkgLSBcbG9nKDE3MjgpIFxhcHByb3ggLTguMDMzNQ0KJCQNCg0KJCQNClxlbGwoXGxhbWJkYV8wKSA9IC01KDIpICsgMTNcbG9nKDIpIC0gXHN1bSBcbG9nKHhfaSEpID0gLTEwICsgMTMoMC42OTMxKSAtIDcuNDU1IFxhcHByb3ggLTguNDQ0Nw0KJCQNCg0KJCQNClxMYW1iZGEgPSAyWy04LjAzMzUgLSAoLTguNDQ0NyldID0gMigwLjQxMTIpID0gMC44MjI0DQokJA0KDQoqKkNvbmNsdXNpb24qKiBBbGwgdGVzdCBzdGF0aXN0aWNzIGFyZSBhcHByb3hpbWF0ZWx5IGJldHdlZW4gMC43IGFuZCAwLjkuICBTaW5jZSBhbGwgdGhyZWUgdGVzdCBzdGF0aXN0aWNzIGFyZSBsZXNzIHRoYW4gdGhlIGNyaXRpY2FsIHZhbHVlICRcY2hpXjJfezEsMC4wNX0gPSAzLjg0MSQsIHdlIGZhaWwgdG8gcmVqZWN0ICRIXzAkLg0KDQoNCioqUiBWZXJpZmljYXRpb24qKg0KDQpgYGB7cn0NCiMgUG9pc3NvbiBleGFtcGxlDQp4IDwtIGMoMywgMSwgNCwgMiwgMykNCm4gPC0gbGVuZ3RoKHgpDQoNCiMgTUxFDQpsYW1iZGFfbWxlIDwtIG1lYW4oeCkNCg0KIyBXYWxkIHRlc3QNCnNlX3dhbGQgPC0gc3FydChsYW1iZGFfbWxlL24pDQpXIDwtICgobGFtYmRhX21sZSAtIDIpL3NlX3dhbGQpXjINCg0KIyBTY29yZSB0ZXN0DQpVIDwtIC1uICsgc3VtKHgpLzINCkkgPC0gbi8yDQpTIDwtIFVeMi9JDQoNCiMgTGlrZWxpaG9vZCByYXRpbyB0ZXN0DQpsbF9tbGUgPC0gc3VtKGRwb2lzKHgsIGxhbWJkYV9tbGUsIGxvZyA9IFRSVUUpKQ0KbGxfbnVsbCA8LSBzdW0oZHBvaXMoeCwgMiwgbG9nID0gVFJVRSkpDQpMUiA8LSAyKihsbF9tbGUgLSBsbF9udWxsKQ0KDQpjYXQoIiAgV2FsZDoiLCBXLCAicC12YWx1ZToiLCAxLXBjaGlzcShXLCAxKSwgIlxuIiwNCiAgICAiU2NvcmU6IiwgUywgInAtdmFsdWU6IiwgMS1wY2hpc3EoUywgMSksICJcbiIsDQogICAgIiAgIExSOiIsIExSLCAicC12YWx1ZToiLCAxLXBjaGlzcShMUiwgMSksICJcbiIpDQpgYGANCg0KDQojIyBFeGFtcGxlIDI6IE5vcm1hbCBEaXN0cmlidXRpb24gTWVhbiBUZXN0DQoNCioqUHJvYmxlbSoqIFRlc3QgJEhfMDogXG11ID0gMTAkIHZzICRIXzE6IFxtdSBcbmVxIDEwJCBmb3IgJFhfaSBcc2ltIE4oXG11LCBcc2lnbWFeMikkLCB3aGVyZSAkXHNpZ21hXjIgPSAwLjEkLiANCg0KKipEYXRhKio6IDEwLjIsIDkuOCwgMTAuMCwgMTAuMiwgOS45Lg0KDQoqKk1hbnVhbCBTb2x1dGlvbioqDQoNCiogKipMaWtlbGlob29kKio6ICRMKFxtdSkgPSAoMlxwaVxzaWdtYV4yKV57LW4vMn0gXGV4cFxsZWZ0XHstXGZyYWN7MX17MlxzaWdtYV4yfSBcc3VtX3tpPTF9Xm4gKHhfaSAtIFxtdSleMlxyaWdodFx9JC4NCg0KKiAqKkxvZy1saWtlbGlob29kKio6ICRcZWxsKFxtdSkgPSBcbG9nIEwoXG11KSA9IC1cZnJhY3tufXsyfVxsb2coMlxwaVxzaWdtYV4yKSAtIFxmcmFjezF9ezJcc2lnbWFeMn0gXHN1bV97aT0xfV5uICh4X2kgLSBcbXUpXjIkDQoNCiogKipTY29yZSBFcXVhdGlvbioqOiAkUyhcbXUpID0gXGZyYWN7XHBhcnRpYWwgXGVsbChcbXUpfXtccGFydGlhbCBcbXV9ID0gXGZyYWN7MX17XHNpZ21hXjJ9IFxzdW1fe2k9MX1ebiAoeF9pIC0gXG11KSQNCg0KKiAqKk1MRSoqICRcaGF0e1xtdX0gPSBcYmFye3h9ID0gXGZyYWN7MX17bn0gXHN1bV97aT0xfV5uIHhfaSA9IFxmcmFjezEwLjIrOS44KzEwLjArMTAuMis5Ljl9ezV9ID0gMTAuMDIkDQogICAgDQoqICoqSW5mb3JtYXRpb24qKiAkSShcbXUpID0gLVxmcmFje1xwYXJ0aWFsXjIgXGVsbChcbXUpfXtccGFydGlhbCBcbXVeMn0gID0gXGZyYWN7bn17XHNpZ21hXjJ9ID0gXGZyYWN7NX17MC4xfSA9IDUwJA0KDQoNCldpdGggdGhlIGFib3ZlIG1hbnVhbCB3b3JrLCB3ZSBuZXh0IGRlZmluZSB0aGUgdGhyZWUgdGVzdCBzdGF0aXN0aWM6DQoNCg0KKipXYWxkIFRlc3QqKg0KDQokJA0KVyA9IChcaGF0e1xtdX0gLSBcbXVfMCleMiBJKFxoYXR7XG11fSkgPSAoMC4wMileMiBcdGltZXMgNTAgPSAwLjAwMDQgXHRpbWVzIDUwID0gMC4wMg0KJCQNCg0KKipTY29yZSBUZXN0KioNCg0KJCQNClUoXG11KSA9IFxmcmFje259e1xzaWdtYV4yfShcYmFye3h9IC0gXG11KQ0KJCQNCg0KQXQgJFxtdV8wPTEwJDogJFUoMTApID0gNTAgXHRpbWVzICgxMC4wMiAtIDEwKSA9IDEkDQoNCiQkDQpTID0gVSgxMCleMiBJXnstMX0oMTApID0gMV4yIFx0aW1lcyBcZnJhY3sxfXs1MH0gPSAwLjAyDQokJA0KDQoqKkxpa2VsaWhvb2QgUmF0aW8gVGVzdCoqDQoNCiQkDQpcZWxsKFxtdSkgPSAtXGZyYWN7bn17Mn1cbG9nKDJccGlcc2lnbWFeMikgLSBcZnJhY3sxfXsyXHNpZ21hXjJ9XHN1bSh4X2kgLSBcbXUpXjINCiQkDQoNCiQkDQpcZWxsKFxtdV8wKSA9IC1cZnJhY3tufXsyfVxsb2coMlxwaVxzaWdtYV4yKSAtIFxmcmFjezF9ezJcc2lnbWFeMn1cc3VtKHhfaSAtIFxtdV8wKV4yDQokJA0KDQoNCiQkDQpcZWxsKFxoYXR7XG11fSkgLSBcZWxsKFxtdV8wKSA9IC1cZnJhY3sxfXsyXHNpZ21hXjJ9W1xzdW0oeF9pIC0gXGhhdHtcbXV9KV4yIC0gXHN1bSh4X2kgLSBcbXVfMCleMl0NCiQkDQoNCiQkDQo9IC1cZnJhY3sxfXswLjJ9WzAuMTMgLSAwLjEyOF0gPSAtNSBcdGltZXMgMC4wMDIgPSAtMC4wMQ0KJCQNCg0KJCQNClxMYW1iZGEgPSAyIFx0aW1lcyAwLjAxID0gMC4wMi4NCiQkDQoNClwNCg0KKipSIFZlcmlmaWNhdGlvbioqDQoNCmBgYHtyfQ0KIyBOb3JtYWwgZXhhbXBsZQ0KeCA8LSBjKDEwLjIsIDkuOCwgMTAuMCwgMTAuMiwgOS45KQ0KbiA8LSBsZW5ndGgoeCkNCnNpZ21hMiA8LSAwLjENCm11MCA8LSAxMA0KDQptdV9tbGUgPC0gbWVhbih4KQ0KDQojIFdhbGQgdGVzdA0KVyA8LSAobXVfbWxlIC0gbXUwKV4yICogKG4vc2lnbWEyKSAgICMgV2FsZCB0ZXN0IHN0YXRpc3RpYw0KDQojIFNjb3JlIHRlc3QNClUgPC0gKG4vc2lnbWEyKSAqIChtdV9tbGUgLSBtdTApDQpJIDwtIG4vc2lnbWEyDQpTIDwtIFVeMi9JICAgICMgUmFvIHRlc3Qgc3RhdGlzdGljDQoNCiMgTGlrZWxpaG9vZCByYXRpbyB0ZXN0DQpsbF9tbGUgPC0gc3VtKGRub3JtKHgsIG11X21sZSwgc3FydChzaWdtYTIpLCBsb2cgPSBUUlVFKSkgICMgbG9nID0gVFJVRSB5aWVsZHMgbG9nLWxpa2VsaWhvb2QNCmxsX251bGwgPC0gc3VtKGRub3JtKHgsIG11MCwgc3FydChzaWdtYTIpLCBsb2cgPSBUUlVFKSkNCkxSIDwtIDIqKGxsX21sZSAtIGxsX251bGwpICAgICMgbG9nLWxpa2VsaWhvb2QgcmF0aW8gdGVzdCBzdGF0aXN0aWMNCg0KY2F0KCIgIFdhbGQ6IiwgVywgInAtdmFsdWU6IiwgMS1wY2hpc3EoVywgMSksICJcbiIsDQogICAgIlNjb3JlOiIsIFMsICJwLXZhbHVlOiIsIDEtcGNoaXNxKFMsIDEpLCAiXG4iLA0KICAgICIgICBMUjoiLCBMUiwgInAtdmFsdWU6IiwgMS1wY2hpc3EoTFIsIDEpLCAiXG4iKQ0KYGBgDQoNClwNCg0KIyBQcmFjdGljYWwgRXhhbXBsZTogTXVsdGlwbGUgUGFyYW1ldGVycw0KDQpJbiB0aGUgc2luZ2xlLXBhcmFtZXRlciBjYXNlLCB0aGUgRmlzaGVyIGluZm9ybWF0aW9uIG51bWJlciBpcyByZWxhdGl2ZWx5IHN0cmFpZ2h0Zm9yd2FyZCB0byBkZXJpdmUuIEZvciBtdWx0aS1wYXJhbWV0ZXIgY2FzZXMsIGhvd2V2ZXIsIHdlIG5lZWQgdG8gb2J0YWluIHRoZSBGaXNoZXIgaW5mb3JtYXRpb24gbWF0cml4IGluIG9yZGVyIHRvIGNvbmR1Y3QgYm90aCB0aGUgV2FsZCBhbmQgc2NvcmUgdGVzdHMuIFRoaXMgc2VjdGlvbiB1c2VzIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiBhcyBhbiBleGFtcGxlIHRvIGlsbHVzdHJhdGUgdGhlIHByb2NlZHVyZSBmb3IgdGhlIHRocmVlIGNoaS1zcXVhcmUgdGVzdHMuDQoNCiMjIENvbXBvbmVudHMgZm9yIHRoZSBUaHJlZSAkXGNoaV4yJCBUZXN0cw0KDQpJbiB0aGlzIHN1YnNlY3Rpb24sIHdlIHVzZSB0aGUgZ2FtbWEgZGlzdHJpYnV0aW9uIGFzIGFuIGV4YW1wbGUgdG8gaWxsdXN0cmF0ZSBob3cgdG8gdGVzdCB0aGUgc2lnbmlmaWNhbmNlIG9mIHBhcmFtZXRlcnMuIFNpbmNlIHRoZSBnYW1tYSBkaXN0cmlidXRpb24gaXMgY29tbW9ubHkgZXhwcmVzc2VkIGluIHR3byBkaXN0aW5jdCBmb3JtdWxhdGlvbnMsIHdlIGFkb3B0IHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyaXphdGlvbi4NCg0KVGhlIGdhbW1hIGRpc3RyaWJ1dGlvbiB3aXRoIHNoYXBlIHBhcmFtZXRlciAkXGFscGhhID4gMCQgYW5kIHJhdGUgcGFyYW1ldGVyICRcYmV0YSA+IDAkIGhhcyBwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9uOg0KDQokJA0KZih4OyBcYWxwaGEsIFxiZXRhKSA9IFxmcmFje1xiZXRhXntcYWxwaGF9fXtcR2FtbWEoXGFscGhhKX0geF57XGFscGhhLTF9IGVeey1cYmV0YSB4fSwgXHF1YWQgeCA+IDANCiQkDQoNClRoZSBjYXNlIHdoZXJlIHRoZSBzaGFwZSBwYXJhbWV0ZXIgJFxhbHBoYSA9IDEkIHJlZHVjZXMgdGhlIGdhbW1hIHRvIGFuIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbi4gVGh1cywgdGVzdGluZyB0aGlzIG51bGwgaHlwb3RoZXNpcyBpbmRpY2F0ZXMgd2hldGhlciB0aGUgZ2FtbWEgZGlzdHJpYnV0aW9uIHByb3ZpZGVzIGEgc2lnbmlmaWNhbnRseSBiZXR0ZXIgZml0IG9yIGxlYWRzIHRvIG92ZXJmaXR0aW5nIGZvciB0aGUgZ2l2ZW4gZGF0YS4NCg0KQXNzdW1lICRce3hfMSwgeF8yLCBcY2RvdHMsIHhfblx9IFx4cmlnaHRhcnJvd3tpLmkuZH0gXHRleHR7Z2FtbWF9KFxhbHBoYSwgXGJldGEpJC4gJFxwc2koXGFscGhhKSQgZGVub3RlcyB0aGUgKipkaWdhbW1hIGZ1bmN0aW9uKioNCg0KJCQNClxwc2koeikgPSBcZnJhY3tkfXtken0gXGxuIFxHYW1tYSh6KSA9IFxmcmFje1xHYW1tYScoeil9e1xHYW1tYSh6KX0uDQokJA0KDQoqKlIgZnVuY3Rpb25zKiogYGRpZ2FtbWEoeilgLCBgdHJpZ2FtbWEoeilgLCBgdGV0cmFnYW1tYSh6KWAgZXZhbHVhdGUgJFxwc2koeCksIFxwc2leXHByaW1lICh6KSQgYW5kICRccHNpXntccHJpbWVccHJpbWV9KHopJCwgcmVzcGVjdGl2ZWx5Lg0KDQoNClRoZSBvYmplY3RpdmUgaXMgdG8gdGVzdCAkSF8wOiBcYWxwaGEgPSAxJC4gVGhlIG1ham9yIGNvbXBvbmVudHMgcmVxdWlyZWQgZm9yIHRlc3RpbmcgdGhlIGh5cG90aGVzaXMgYXJlIGdpdmVuIGJlbG93LiAgDQoNCioqTG9nLWxpa2VsaWhvb2QqKg0KDQokJA0KXGVsbChcYWxwaGEsIFxiZXRhKSA9IG5cYWxwaGFcbG9nXGJldGEgLSBuXGxvZ1xHYW1tYShcYWxwaGEpICsgKFxhbHBoYS0xKVxzdW1fe2k9MX1ebiBcbG9nIHhfaSAtIFxiZXRhXHN1bV97aT0xfV5uIHhfaQ0KJCQNCg0KKipTY29yZSBFcXVhdGlvbnMqKg0KDQokJA0KXGZyYWN7XHBhcnRpYWxcZWxsfXtccGFydGlhbFxhbHBoYX0gPSBuXGxvZ1xiZXRhIC0gblxwc2koXGFscGhhKSArIFxzdW1fe2k9MX1ebiBcbG9nIHhfaSA9IDANCiQkDQoNCiQkDQpcZnJhY3tccGFydGlhbFxlbGx9e1xwYXJ0aWFsXGJldGF9ID0gXGZyYWN7blxhbHBoYX17XGJldGF9IC0gXHN1bV97aT0xfV5uIHhfaSA9IDANCiQkDQoNCioqTWF4aW11bSBMaWtlbGlob29kIEVzdGltYXRpb24qKg0KDQpUaGUgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRlcyBvZiAkXGFscGhhJCBhbmQgJFxiZXRhJCwgZGVub3RlZCBieSAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JCwgYXJlIHRoZSBzb2x1dGlvbnMgdG8gdGhlIGFib3ZlICoqc3lzdGVtKiogb2Ygc2NvcmUgZXF1YXRpb25zLg0KDQpcDQoNCioqSW5mb3JtYXRpb24gTWF0cml4KioNCg0KJFxtYXRoY2Fse0l9X24oMiwyKSQgaXMgdGhlICgyLDIpIGVsZW1lbnQgb2YgdGhlICoqRmlzaGVyIGluZm9ybWF0aW9uIG1hdHJpeCoqIG9mICRcYWxwaGEkIGFuZCAkXGJldGEkIGJhc2VkIG9uIGVudGlyZSBzYW1wbGUgd2l0aCBzaXplICRuJDoNCg0KJCQNClxtYXRoY2Fse0l9X24oXGFscGhhLCBcYmV0YSkgPSAtIEVcYmVnaW57cG1hdHJpeH0gXGZyYWN7XHBhcnRpYWxeMlxlbGx9e1xwYXJ0aWFsIFxhbHBoYV4yfSAmIFxmcmFje1xwYXJ0aWFsXjJcZWxsfXtccGFydGlhbFxhbHBoYVxwYXJ0aWFsXGJldGF9IFxcIFxmcmFje1xwYXJ0aWFsXjJcZWxsfXtccGFydGlhbFxiZXRhXHBhcnRpYWxcYWxwaGF9JiBcZnJhY3tccGFydGlhbF4yXGVsbH17XHBhcnRpYWxcYmV0YV4yfSBcZW5ke3BtYXRyaXh9ID0gLVxiZWdpbntwbWF0cml4fSBuXHBzaScoXGFscGhhKSAmIFxmcmFje259e1xiZXRhfSBcXCBcZnJhY3tufXtcYmV0YX0gJiBcZnJhY3tuXGFscGhhfXtcYmV0YV4yfSBcZW5ke3BtYXRyaXh9DQokJA0KDQoNCioqUmVtYXJrKio6IEZvciB0aGUgbGlrZWxpaG9vZCByYXRpbyB0ZXN0LCB3ZSBtdXN0IG9idGFpbiBib3RoIHRoZSByZXN0cmljdGVkIGFuZCB1bnJlc3RyaWN0ZWQgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRlcyAoTUxFcykuIFRoZSByZXN0cmljdGVkIE1MRSBpcyBkZXJpdmVkIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMgJEhfMDogXGFscGhhID0gMSQgKGkuZS4sICRcYWxwaGEkIGZpeGVkIHRvIGEgY29uc3RhbnQpLCB3aGlsZSB0aGUgdW5yZXN0cmljdGVkIE1MRSB0cmVhdHMgYm90aCAkXGFscGhhJCBhbmQgJFxiZXRhJCBhcyB1bmtub3duIHBhcmFtZXRlcnMuIEluIGdlbmVyYWwsIHRoZXNlIE1MRXMgbXVzdCBiZSBvYnRhaW5lZCB1c2luZyBudW1lcmljYWwgYXBwcm94aW1hdGlvbiBtZXRob2RzLg0KDQoNCg0KIyMgTnVtZXJpY2FsIEltcGxlbWVudGF0aW9uDQoNClRoZSBkYXRhc2V0IHVzZWQgaW4gdGhpcyBleGFtcGxlIGNvbnRhaW5zIG1lYXN1cmVtZW50cyBvZiBtaWNyb3R1YnVsZSBjYXRhc3Ryb3BoZSB0aW1lcyAodGhlIHRpbWUgdW50aWwgYSBtaWNyb3R1YnVsZSBzdG9wcyBncm93aW5nKS4gSW4gdGhlaXIgQ2VsbCBwYXBlciAoMjAxMSksIEdhcmRuZXIsIFphbmljLCBhbmQgY29sbGVhZ3VlcyAoR2FyZG5lciwgWmFuaWMsIGV0IGFsLiAoMjAxMSkuIENlbGwsIDE0Nyg1KSwgMTA5Mi0xMTAzLikgZXhwbGljaXRseSBtb2RlbGVkIHRoZXNlIGNhdGFzdHJvcGhlIHRpbWVzIHVzaW5nIGEgKipnYW1tYSBkaXN0cmlidXRpb24qKi4gRm9yIGlsbHVzdHJhdGl2ZSBwdXJwb3NlLCB3ZSBvbmx5IHVzZSBjb21wbGV0ZSB0aW1lcyBpbiB0aGlzIGV4YW1wbGUuDQoNCldlIGZpcnN0IGxvYWQgdGhlIGRhdGEgaW50byBSIGFuZCB0aGVuIGZvbGxvdyB0aGUgc3RlcHMgYWJvdmUgdG8gcGVyZm9ybSB0aGUgdGhyZWUgbGlrZWxpaG9vZC1iYXNlZCAkXGNoaV4yJCB0ZXN0cy4NCg0KYGBge3J9DQp0aW1lMmV2ZW50IDwtIHJlYWQudGFibGUoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL1NUQTUwNi93MTEvVGltZTJDYXRhc3Ryb3BoZS50eHQiKQ0KY29sbmFtZXModGltZTJldmVudCkgPC0gInRpbWUiDQp4IDwtIHRpbWUyZXZlbnQkdGltZQ0KYGBgDQoNCioqTG9nbGlrZWxpaG9vZCBmdW5jdGlvbioqIA0KDQpUaGUgZm9sbG93aW5nIFIgZnVuY3Rpb24gZXZhbHVhdGUgdGhlIGxvZ2xpa2VsaWhvb2QgZnVuY3Rpb24gYW5kIHdpbGwgYmUgdXNlZCB0byBmaW5kIHRoZSB1bnJlc3RyaWN0ZWQgTUxFIG9mICRcYWxwaGEkIGFuZCAkXGJldGEkLiANCg0KYGBge3J9DQojIGxvZ2xpa2VsaWhvb2QgZnVuY3Rpb24NCmxvZ19saWtlbGlob29kIDwtIGZ1bmN0aW9uKHBhcmFtKSB7DQogIGFscGhhIDwtIHBhcmFtWzFdIA0KICBiZXRhIDwtIHBhcmFtWzJdDQogIG4gPC0gbGVuZ3RoKHgpDQogIHN1bV94IDwtIHN1bSh4KQ0KICBzdW1fbG9neCA8LSBzdW0obG9nKHgpKQ0KICAjIw0KICBsbCA8LSBuICogYWxwaGEgKiBsb2coYmV0YSkgLSBuICogbG9nKGdhbW1hKGFscGhhKSkgKyANCiAgICAgICAgIChhbHBoYSAtIDEpICogc3VtX2xvZ3ggLSBiZXRhICogc3VtKHgpDQogIGxsDQp9DQpgYGANCg0KKipTY29yZSBFcXVhdGlvbnMqKjogVGhlIGZvbGxvd2luZyBSIGZ1bmN0aW9uIHJldHVybnMgYSB2ZWN0b3Igc2NvcmUgZnVuY3Rpb25zLCBjb21wdXRlZCBmcm9tIHRoZSBkYXRhIHZhbHVlcyBhbmQgcGFyYW1ldGVyIGVzdGltYXRlcy4NCg0KYGBge3J9DQojIFNjb3JlIGVxdWF0aW9ucyAoc2hvdWxkIGJlIHplcm8gYXQgc29sdXRpb24pDQpzY29yZV9lcXUgPC1mdW5jdGlvbihwYXIpew0KICAgIGFscGhhIDwtIHBhclsxXQ0KICAgIGJldGEgPC0gcGFyWzJdDQogICAgIyMNCiAgICBuIDwtIGxlbmd0aCh4KQ0KICAgIHN1bV94IDwtIHN1bSh4KQ0KICAgIHN1bV9sb2d4IDwtIHN1bShsb2coeCkpDQogICAgIyMNCiAgICBzY29yZV9hbHBoYSA8LSBuICogbG9nKGJldGEpIC0gbiAqIGRpZ2FtbWEoYWxwaGEpICsgc3VtX2xvZ3gNCiAgICBzY29yZV9iZXRhIDwtIG4gKiBhbHBoYSAvIGJldGEgLSBzdW1feA0KICAgIGMoc2NvcmVfYWxwaGEsIHNjb3JlX2JldGEpDQogIH0NCmBgYA0KDQoqKkZpc2hlciBJbmZvcm1hdGlvbiBNYXRyaXgqKiBpcyBjb2RlZCBpbiB0aGUgZm9sbG93aW5nDQoNCmBgYHtyfQ0KRmlzaGVySW5mbyA8LSBmdW5jdGlvbihwYXIpew0KICAgICMgRmlzaGVyIGluZm9ybWF0aW9uIG1hdHJpeCAobmVnYXRpdmUgZXhwZWN0ZWQgSGVzc2lhbikNCiAgICAjIFVzZWQgZm9yIE5ld3Rvbi1SYXBoc29uIHVwZGF0ZQ0KICAgICMgSXQgY29udGFpbnMgb25seSBwYXJhbWV0ZXJzDQogICAgYWxwaGEgPC0gcGFyWzFdDQogICAgYmV0YSA8LSBwYXJbMl0NCiAgICANCiAgICAjIEZpc2hlciBJbmZvIGNlbGwNCiAgICBJXzExIDwtIG4gKiB0cmlnYW1tYShhbHBoYSkNCiAgICBJXzEyIDwtIC1uIC8gYmV0YQ0KICAgIElfMjIgPC0gbiAqIGFscGhhIC8gYmV0YV4yDQogICAgDQogICAgIyBJbmZvcm1hdGlvbiBtYXRyaXgNCiAgICBGaXNoZXIgPC0gbWF0cml4KGMoSV8xMSwgSV8xMiwgSV8xMiwgSV8yMiksIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpDQogICAgRmlzaGVyICAgDQp9DQpgYGANCg0KDQojIyBNYXhpbXVtIExpa2VsaWhvb2QgRXN0aW1hdGlvbg0KDQpJbnN0ZWFkIG9mIHJlbHlpbmcgb24gc3BlY2lhbCBidWlsdC1pbiBSIGZ1bmN0aW9ucyB0aGF0IGNvbXB1dGUgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRlcyAoTUxFcykgZm9yIHNwZWNpZmljIGRpc3RyaWJ1dGlvbiBmYW1pbGllcywgd2UgaW50cm9kdWNlIGEgZ2VuZXJhbCBwdXJwb3NlIG9wdGltaXphdGlvbiBmdW5jdGlvbiBgb3B0aW0oKWAgZm9yIG9idGFpbmluZyBNTEVzIGZvciBhcmJpdHJhcnkgZGlzdHJpYnV0aW9ucy4gU3BlY2lmaWNhbGx5LCB3ZSB3aWxsIGRlcml2ZSB0aGUgTUxFcyBvZiB0aGUgcGFyYW1ldGVycyAkXGFscGhhJA0KIGFuZCAkXGJldGEkLCBhbG9uZyB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXgsIHdoaWNoIHdpbGwgYmUgdXNlZCBpbiB0aGUgU2NvcmUgYW5kIFdhbGQgdGVzdHMuDQoNCmBvcHRpbSgpYCBpcyBhIHdyYXBwZXIgZnVuY3Rpb24gdGhhdCBwcm92aWRlcyBhY2Nlc3MgdG8gc2V2ZXJhbCBvcHRpbWl6YXRpb24gYWxnb3JpdGhtcy4gVGhlIHNwZWNpZmljIG51bWVyaWNhbCBtZXRob2QgaW52b2tlZCBpbnRlcm5hbGx5IGRlcGVuZHMgb24gdGhlIGluZm9ybWF0aW9uIHN1cHBsaWVkIHRvIHRoZSBmdW5jdGlvbi4gSW4gcHJhY3RpY2UsIGEgcG9wdWxhciB2YXJpYW50IG9mIHRoZSBOZXd0b27igJNSYXBoc29uIGFsZ29yaXRobSBrbm93biBhcyB0aGUgQnJveWRlbuKAk0ZsZXRjaGVy4oCTR29sZGZhcmLigJNTaGFubm8gKEJGR1MpIGFsZ29yaXRobSBpcyBmcmVxdWVudGx5IGVtcGxveWVkLiBCRkdTIHJlcXVpcmVzIHRoZSBncmFkaWVudCAoc2NvcmUgdmVjdG9yKSB0byBlZmZpY2llbnRseSBndWlkZSB0aGUgc2VhcmNoIHRvd2FyZCB0aGUgb3B0aW1hbCBzb2x1dGlvbi4gVGhlIGZvbGxvd2luZyBSIGNvZGUgaWxsdXN0cmF0ZXMgaG93IHRvIHVzZSB0aGUgQkZHUyBtZXRob2QgdmlhIGBvcHRpbSgpYC4NCg0KDQpgYGB7cn0NCiB4IDwtIHRpbWUyZXZlbnQkdGltZQ0KIG4gPSBsZW5ndGgoeCkNCiAjIGluaXRpYWwgdmFsdWVzDQojIyMNCiByZXN1bHQgPC0gb3B0aW0oDQogICAgICAgICAgcGFyID0gYygxMDAsMC4xKSwgDQogICAgICAgICAgI25lZWQgdG8gcHJvdmlkZSBpbml0aWFsIHZhbHVlcyB0byBzdGFydCB0aGUgaXRlcmF0aW9uLg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBDaG9vc2luZyBhcHByb3ByaWF0ZSBpbml0aWFsIHZhbHVlcyBpcyBjcml0aWNhbC4NCiAgICAgICAgICBmbiA9IGxvZ19saWtlbGlob29kLCAgICAgICMgQ2F1dGlvbjogbmVlZCBuZWdhdGl2ZSBsb2ctbGlrZWxpaG9vZA0KICAgICAgICAgIGdyID0gc2NvcmVfZXF1LCAgICAgICAgICAgIyBhbHNvIG5lZSBuZWdhdGl2ZSBzY29yZQ0KICAgICAgICAgIG1ldGhvZCA9ICJCRkdTIiwgICAgICAgICAgIyBjYWxsaW5nIEJGR1MgYWxnb3JpdGhtDQogICAgICAgICAgaGVzc2lhbiA9IFRSVUUsICAgICAgICAgICAjIHJldHVybiBIZXNzaWFuIG1hdHJpeA0KICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KCAgICAgICAgICAgIyBzb21lIGNvbnRyb2xzIGluIG51bWVyaWNhbCBpdGVyYXRpb24NCiAgICAgICAgICAgICAgICBmbnNjYWxlID0gLTEsICAgICAgICMgdHVybiB0aGUgbWluaW1pemF0aW9uIHRvIG1heGltaXphdGlvbiBwcm9ibGVtDQogICAgICAgICAgICAgICAgbWF4aXQgPSAxMDAwLCAgICAgICAjIHN0b3BwaW5nIHJ1bGUgMTogY2FwIG51bWJlciBvZiBpdGVyYXRpb25zDQogICAgICAgICAgICAgICAgcmVsdG9sID0gMWUtOCwgICAgICAjIHN0b3BwaW5nIHJ1bGU6IHByZWNpc2lvbiBjb250cm9sDQogICAgICAgICAgICAgICAgUkVQT1JUID0gMTAgICAgICAgICAjIFRoZSBhbGdvcml0aG0gd2lsbCBwcmludCBwcm9ncmVzcyB1cGRhdGVzIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBldmVyeSAxMCBpdGVyYXRpb25zDQogICAgICAgICAgKQ0KICApDQogcmVzdWx0DQpgYGANCg0KRG91YmxlIGNoZWNrIHdpdGggdGhlIGhlc3NpYW4gbWF0cml4IHVzaW5nIHRoZSBkZXJpdmVkIGZvcm11bGENCg0KYGBge3J9DQpGaXNoZXIgPC0gRmlzaGVySW5mbyhyZXN1bHQkcGFyKQ0KRmlzaGVyDQpgYGANCg0KV2hpY2ggaXMgY29uc2lzdGVudCB3aXRoIHRoZSAqKmhlc3NpYW4gbWF0cml4KiogaW4gdGhlIG91dHB1dCBvZiBgb3B0aW0oKWAuDQoNCg0KVGhlIHZhcmlhbmNlIGFuZCBjb3ZhcmlhbmNlIG1hdHJpeCBjYW4gYmUgYXBwcm94aW1hdGVkIGJ5IGludmVydGluZyB0aGUgKipGaXNoZXIgSW5mb3JtYXRpb24gTWF0cml4Kiogb3IgdGhlIGludmVyc2Ugb2YgdGhlIG5lZ2F0aXZlIEhlc3NpYW4gbWF0cml4IHJldHVybmVkIGZyb20gYG9wdGltKClgLg0KDQoNCmBgYHtyfQ0KdmFyY292IDwtIHNvbHZlKC1yZXN1bHQkaGVzc2lhbikgICAjIHNvbHZlKCkgaXMgYSBtYXRyaXggaW52ZXJzaW9uIGZ1bmN0aW9uDQp2YXJjb3YNCmBgYA0KDQpUaGF0IGlzLCAkXHRleHR7dmFyfShcYWxwaGEpID0gNC40Mlx0aW1lcyAxMF57LTJ9JCBhbmQgJFx0ZXh0e3Zhcn0oXGJldGEpID0gMi43Mlx0aW1lcyAxMF57LTd9JC4NCg0KDQojIyBUd28gJFxjaGleMiQgVGVzdHMgDQoNClRoZSB0aHJlZSAkXGNoaV4yJCB0ZXN0cyBhcmUgZ2l2ZW4gcmVzcGVjdGl2ZWx5IGluIHRoZSBmb2xsb3dpbmcuDQoNCiMjIyBMaWtlbGlob29kIFJhdGlvIFRlc3QNCg0KV2UgaGF2ZSBmb3VuZCB0aGUgdW4tcmVzdHJpY3RpdmUgTUxFcyBvZiAkXGFscGhhJCBhbmQgJFxiZXRhJDoNCg0KYGBge3J9DQpNTEUgPC0gcmVzdWx0JHBhcg0KTUxFDQpgYGANCg0KV2Ugbm93IGZpbmQgcmVzdHJpY3RpdmUgTUxFIG9mICRcYmV0YSQgIHVuZGVyICRIXzA6IFxhbHBoYSA9IDEkLiBUaGUgb3B0aW1pemF0aW9uIHByb2JsZW1zIGJlY29tZXMgc2luZ2xlIHBhcmFtZXRlciBwcm9ibGVtLg0KDQoNCmBgYHtyfQ0KIyMNCmxvZ2xpayA8LSBmdW5jdGlvbihiZXRhKSBuKmxvZyhiZXRhKS1uIC1iZXRhKnN1bSh4KQ0KIyMNCnNjb3JlIDwtIGZ1bmN0aW9uKGJldGEpIG4vYmV0YSAtIHN1bSh4KQ0KIyMNCiB4IDwtIHRpbWUyZXZlbnQkdGltZQ0KIG4gPSBsZW5ndGgoeCkNCiByZXN1bHQwIDwtIG9wdGltKA0KICAgICAgICAgIHBhciA9IDAuMDUsICAgICAgICAgICAgICMgbmVlZCB0byBwcm92aWRlIGluaXRpYWwgdmFsdWVzIHRvIHN0YXJ0IHRoZSBpdGVyYXRpb24uDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIENob29zaW5nIGFwcHJvcHJpYXRlIGluaXRpYWwgdmFsdWVzIGlzIGNyaXRpY2FsLg0KICAgICAgICAgIGZuID0gbG9nbGlrLCAgICAgICAgICAgICAgIyBDYXV0aW9uOiBuZWVkIG5lZ2F0aXZlIGxvZy1saWtlbGlob29kDQogICAgICAgICAgZ3IgPSBzY29yZSwgICAgICAgICAgICAgICAjIGFsc28gbmVlIG5lZ2F0aXZlIHNjb3JlDQogICAgICAgICAgbWV0aG9kID0gIkJGR1MiLCAgICAgICAgICAjIGNhbGxpbmcgQkZHUyBhbGdvcml0aG0NCiAgICAgICAgICBoZXNzaWFuID0gVFJVRSwgICAgICAgICAgICMgcmV0dXJuIEhlc3NpYW4gbWF0cml4DQogICAgICAgICAgY29udHJvbCA9IGxpc3QoICAgICAgICAgICAjIHNvbWUgY29udHJvbHMgaW4gbnVtZXJpY2FsIGl0ZXJhdGlvbg0KICAgICAgICAgICAgICAgIGZuc2NhbGUgPSAtMSwgICAgICAgIyB0dXJuIHRoZSBtaW5pbWl6YXRpb24gdG8gbWF4aW1pemF0aW9uIHByb2JsZW0NCiAgICAgICAgICAgICAgICBtYXhpdCA9IDEwMDAsICAgICAgICMgc3RvcHBpbmcgcnVsZSAxOiBjYXAgbnVtYmVyIG9mIGl0ZXJhdGlvbnMNCiAgICAgICAgICAgICAgICByZWx0b2wgPSAxZS04LCAgICAgICMgc3RvcHBpbmcgcnVsZTogcHJlY2lzaW9uIGNvbnRyb2wNCiAgICAgICAgICAgICAgICBSRVBPUlQgPSAxMCAgICAgICAgICMgVGhlIGFsZ29yaXRobSB3aWxsIHByaW50IHByb2dyZXNzIHVwZGF0ZXMgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGV2ZXJ5IDEwIGl0ZXJhdGlvbnMNCiAgICAgICAgICApDQogICkNCiByZXN1bHQwDQpgYGANCg0KDQpUaGF0IGlzIHRoZSByZXN0cmljdGl2ZSBNTEUgb2YgJFxiZXRhJCwgZGVub3RlZCBieSAkXGhhdHtcYmV0YX09MC4wMDIyNjkwNjckLg0KDQpUaGUgbGlrZWxpaG9vZCByYXRpbyB0ZXN0IHN0YXRpc3RpYyBpcw0KDQokJA0KTFIgPSDiiJIyW1xlbGwoXGhhdHtcYWxwaGF9LCBcaGF0e1xiZXRhfSniiJJcZWxsKDEsXGhhdHtcYmV0YX0pXSBcdG8gXGNoaV4yXzEuDQokJA0KDQpUaGUgUiBjb2RlIHRoYXQgZXZhbHVhdGVzIHRoZSBhYm92ZSB0ZXN0IHN0YXRpc3RpYyBpcyBnaXZlbiBieQ0KDQpgYGB7cn0NCiB4IDwtIHRpbWUyZXZlbnQkdGltZQ0KIG4gPSBsZW5ndGgoeCkNCiAjIw0KIExSID0gLTIqKGxvZ2xpayhyZXN1bHQwJHBhcikgLSBsb2dfbGlrZWxpaG9vZChyZXN1bHQkcGFyKSkNCiBMUg0KYGBgDQoNCg0KU2luY2UgdGhlIGNoaS1zcXVhcmUgdGVzdCBpcyBhbHdheXMgcmlnaHQtdGFpbGVkLCB0aGUgcC12YWx1ZSBiYXNlZCBvbiB0aGUgdGVzdCBzdGF0aXN0aWMgYWJvdmUgaXMgZ2l2ZW4gYnkgJHAgPSBQKFxjaGleMl8xID4gTFIpJC4gVGhlIHAtdmFsdWUgY2FuIGJlIG9idGFpbmVkIHVzaW5nIHRoZSBmb2xsb3dpbmcgUiBjb2RlLg0KDQpgYGB7cn0NCnB2YWwgPC0gMSAtIHBjaGlzcShMUiwgZGYgPSAxKQ0KcHZhbA0KYGBgDQoNClRoZSBwLXZhbHVlIGlzIG5lYXJseSB6ZXJvLCBsZWFkaW5nIHRvIHRoZSByZWplY3Rpb24gb2YgdGhlIG51bGwgaHlwb3RoZXNpcyAkSF8wOiBcYWxwaGEgPSAxJC4NCg0KDQojIyMgV2FsZCAgJFxjaGleMiQgIFRlc3QNCg0KVGhlIFdhbGQgJFxjaGleMiQgdGVzdCBzdGF0aXN0aWNzIGZvciB0aGUgbnVsbCBoeXBvdGhlc2lzICRIXzA6IFxhbHBoYSA9IDEkIGlzIGdpdmVuIGJ5DQoNCiQkDQpXX3tcdGV4dHtXYWxkfX0gPSBbXGZyYWN7XGhhdHtcYWxwaGF9IC0gMX17XHRleHR7c2V9KFxoYXR7XGFscGhhfSl9XV4yID0gXGZyYWN7KFxoYXR7XGFscGhhfS0xKV4yfXtcdGV4dHt2YXJ9KFxoYXR7XGFscGhhfSl9IFx0byBcY2hpXjJfMQ0KJCQNCg0Kd2hlcmUgJFx0ZXh0e1Zhcn0oXGhhdHtcYWxwaGF9KSQgaXMgdGhlIGRpYWdvbmFsIGVsZW1lbnQgb2YgdGhlIGludmVyc2Ugb2YgdGhlIG9ic2VydmVkIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXggKGkuZS4sIHRoZSB2YXJpYW5jZeKAk2NvdmFyaWFuY2UgbWF0cml4KS4gVGhpcyBtZWFucyB0aGF0IHRoZSBGaXNoZXIgaW5mb3JtYXRpb24gbWF0cml4IGlzIHJlcXVpcmVkIGZvciB0aGUgV2FsZCB0ZXN0Lg0KDQoNCk5leHQsIHdlIGRlZmluZSB0aGUgdGVzdCBzdGF0aXN0aWMgYW5kIGNhbGN1bGF0ZSB0aGUgcC12YWx1ZSB1c2luZyB0aGUgZm9sbG93aW5nIFIgY29kZQ0KDQpgYGB7cn0NCmFscGhhLmhhdCAgPC0gcmVzdWx0JHBhclsxXSAgICAgIyBiYXNlZCBvbiB0aGUgdW5yZXN0cmljdGVkIGxpa2VsaWhvb2QgZXN0aW1hdGlvbg0Kc2UuYWxwaGEgPC0gc3FydCh2YXJjb3ZbMSwgMV0pICAjIHRoZSBzcXVhcmUgcm9vdCBvZiB0aGUgdG9wLWxlZnQgZGlhZ29uYWwgdmFsdWUNClcgPC0gKGFscGhhLmhhdCAtIDEpXjIvKHNlLmFscGhhKV4yICAgIyBXYWxkIHRlc3Qgc3RhdGlzdGljDQojIw0KcHZhbC5XIDwtIDEgLSBwY2hpc3EoVywgZGYgPSAxKQ0KYyhXID0gVywgcHZhbC5XID0gcHZhbC5XKQ0KYGBgDQoNClRoZSBwLXZhbHVlIGlzIGFsc28gbmVhciAwIGltcGx5aW5nIHRoZSByZWplY3Rpb24gb2YgdGhlIG51bGwgaHlwb3RoZXNpcy4NCg0KDQpcDQoNCiMgUGVyZm9ybWFuY2UgQ29tcGFyaXNvbg0KDQpBdCB0aGUgaGVhcnQgb2YgbW9kZXJuIHN0YXRpc3RpY2FsIGluZmVyZW5jZSBsaWVzIGEgcG93ZXJmdWwgdHJpbzogdGhlIExpa2VsaWhvb2QgUmF0aW8sIFdhbGQsIGFuZCBTY29yZSB0ZXN0cy4gRWFjaCBwcm92aWRlcyBhIGRpc3RpbmN0IGxlbnMgZm9yIHRlc3RpbmcgaHlwb3RoZXNlcywgdHJhbnNmb3JtaW5nIHRoZSBzYW1lIGxpa2VsaWhvb2QgZnVuY3Rpb24gaW50byBhIGNoaS1zcXVhcmVkIHN0YXRpc3RpYyB0aHJvdWdoIGRpZmZlcmVudCBsb2dpY2FsIGFuZCBnZW9tZXRyaWNhbCBwcmluY2lwbGVzLiBUaGVpciBhc3ltcHRvdGljIGVxdWl2YWxlbmNlIHByb3ZpZGVzIGEgcmVhc3N1cmluZyB0aGVvcmV0aWNhbCBmb3VuZGF0aW9uLCB5ZXQgdGhlaXIgZmluaXRlLXNhbXBsZSBkaXZlcmdlbmNlIHJldmVhbHMgYSByaWNoIGxhbmRzY2FwZSBvZiBzdGF0aXN0aWNhbCB0cmFkZS1vZmZzLCB3aGVyZSB0aGUgY2hvaWNlIG9mIHRlc3QgYmFsYW5jZXMgY29uc2lkZXJhdGlvbnMgb2YgYWNjdXJhY3ksIGNvbnZlbmllbmNlLCBpbnZhcmlhbmNlLCBhbmQgY29tcHV0YXRpb25hbCBidXJkZW4uDQoNCg0KKipDb3JlIFBlcmZvcm1hbmNlIENoYXJhY3RlcmlzdGljcyoqDQoNCiogKipMaWtlbGlob29kIFJhdGlvIFRlc3QgKExSVCkqKiAtIGJlc3Qgb3ZlcmFsbCBwZXJmb3JtYW5jZSBpbiBtb3N0IHNpdHVhdGlvbnMNCiAgKyAqKkFjY3VyYWN5Kio6IE1vc3QgcmVsaWFibGUgaW4gZmluaXRlIHNhbXBsZXMsIGNsb3Nlc3QgdG8gbm9taW5hbCBUeXBlIEkgZXJyb3IgcmF0ZXMNCiAgKyAqKlJvYnVzdG5lc3MqKjogSW52YXJpYW50IHRvIHBhcmFtZXRlciB0cmFuc2Zvcm1hdGlvbnMgKHVuaXF1ZSBhZHZhbnRhZ2UpDQogICsgKipDb25zZXJ2YXRpc20qKjogU2xpZ2h0bHkgY29uc2VydmF0aXZlIGluIHZlcnkgc21hbGwgc2FtcGxlcw0KICArICoqQ29tcHV0YXRpb24qKjogTW9zdCBpbnRlbnNpdmUgKHJlcXVpcmVzIGZpdHRpbmcgYm90aCBtb2RlbHMpDQoNCg0KKiAqKldhbGQgVGVzdCoqIC0gZmFzdGVzdCBidXQgbGVhc3QgcmVsaWFibGUgaW4gbm9uLWlkZWFsIGNvbmRpdGlvbnMNCiAgKyAqKkFjY3VyYWN5Kio6IENhbiBiZSBwb29yIGluIHNtYWxsIHNhbXBsZXMsIGVzcGVjaWFsbHkgd2l0aDoNCiAgICAtIFNrZXdlZCBsaWtlbGlob29kcw0KICAgIC0gUGFyYW1ldGVycyBuZWFyIGJvdW5kYXJpZXMgKHZhcmlhbmNlcywgcHJvYmFiaWxpdGllcyBuZWFyIDAvMSkNCiAgICAtIE5vbmxpbmVhciBwYXJhbWV0ZXJzDQogICsgKipCaWFzKio6IE9mdGVuIGFudGktY29uc2VydmF0aXZlIChpbmZsYXRlcyBUeXBlIEkgZXJyb3IpDQogICsgKipDb21wdXRhdGlvbioqOiBGYXN0ZXN0IChvbmx5IG5lZWRzIGZ1bGwgbW9kZWwpDQoNCiogKipTY29yZSBUZXN0IChSYW8pKiotIGVmZmljaWVudCBjb21wcm9taXNlIHdpdGggc3BlY2lmaWMgc3RyZW5ndGhzDQogICsgKipBY2N1cmFjeSoqOiBHb29kIHdoZW4gbnVsbCBoeXBvdGhlc2lzIGlzIHRydWUsIGJ1dCBjYW4gYmUgaW5jb25zaXN0ZW50IHdoZW4gYWx0ZXJuYXRpdmUgaXMgdHJ1ZQ0KICArICoqUG93ZXIqKjogU29tZXRpbWVzIGxlc3MgcG93ZXJmdWwgdGhhbiBMUlQgaW4gc21hbGwgc2FtcGxlcw0KICArICoqQ29tcHV0YXRpb24qKjogTW9kZXJhdGUgKG9ubHkgbmVlZHMgbnVsbCBtb2RlbCkNCiAgKyAqKlNwZWNpYWwgc3RyZW5ndGgqKjogQmVzdCBmb3IgYm91bmRhcnkgdGVzdGluZyBhbmQgaW5pdGlhbCBtb2RlbCBidWlsZGluZw0KDQoNCioqR2VuZXJhbCBSZWNvbW1lbmRhdGlvbnMqKg0KDQoqIFVzZSB0aGUgTFJUIHdoZW46DQogICsgQ29tcHV0YXRpb25hbCBjb3N0IGlzIG5vdCBhIGNvbmNlcm4uDQogICsgU2FtcGxlIHNpemUgaXMgc21hbGwgdG8gbW9kZXJhdGUuDQogICsgd2hlbiBjb21wYXJpbmcgbmVzdGVkIG1vZGVscyBvZiBnZW5lcmFsIHR5cGVzIChHTE1zLCBtaXhlZCBtb2RlbHMsIGV0Yy4pLg0KDQoqIFVzZSB0aGUgV2FsZCBUZXN0IHdoZW46DQogICsgb25seSBoYXZpbmcgdGhlIHVucmVzdHJpY3RlZCBtb2RlbCBvdXRwdXQgKGUuZy4sIGZyb20gYSBzdGFuZGFyZCByZWdyZXNzaW9uIHN1bW1hcnkpLg0KICArIERvaW5nIHF1aWNrIGFwcHJveGltYXRlIGluZmVyZW5jZSBvciBjb25zdHJ1Y3RpbmcgY29uZmlkZW5jZSBpbnRlcnZhbHMuDQogICsgVGhlIHNhbXBsZSBzaXplIGlzIGxhcmdlIGFuZCB0aGUgbGlrZWxpaG9vZCBpcyB3ZWxsLWJlaGF2ZWQgKCRcYXBwcm94JCBxdWFkcmF0aWMpLg0KICArICoqQ2F1dGlvbioqOiBDYW4gYmUgbWlzbGVhZGluZyBmb3IgcGFyYW1ldGVycyBsaWtlIG9kZHMgcmF0aW9zIChhbHdheXMgZXhwb25lbnRpYXRlIGZpcnN0LCB0aGVuIGZvcm0gV2FsZCBDSSBvbiBsb2cgc2NhbGUpLg0KDQoqIFVzZSB0aGUgU2NvcmUgVGVzdCB3aGVuOg0KICArIFRoZSBudWxsIG1vZGVsIGlzIHNpbXBsZXIgdG8gZml0IChlLmcuLCB0ZXN0aW5nIGZvciBhbiBhZGRpdGlvbmFsIHJlZ3Jlc3NvciBpbiBhIGxhcmdlIGRhdGEgc2V0OyBvbmx5IGZpdCB0aGUgcmVkdWNlZCBtb2RlbCkuDQogICsgSW4gbW9kZWwgY2hlY2tpbmcgYW5kIGRpYWdub3N0aWNzIChlLmcuLCByZXNpZHVhbHMgdGVzdHMpLg0KICArIFdoZW4gdGhlIE1MRSB1bmRlciB0aGUgYWx0ZXJuYXRpdmUgaXMgaGFyZCB0byBvYnRhaW4gb3IgYXQgYSBib3VuZGFyeS4NCg0KDQoqKkxvZ2ljYWwgUGFyYWRveGVzIGFuZCBSZXNvbHV0aW9ucyoqDQoNCiogKipQYXJhZG94IDEqKjogIldhbGQgY2FuIHJlamVjdCB3aGVuIExSVCBkb2Vzbid0Ig0KICArICoqT2NjdXJzIHdoZW4qKjogTGlrZWxpaG9vZCBpcyBoaWdobHkgbm9uLXF1YWRyYXRpYw0KICArICoqTG9naWNhbCBleHBsYW5hdGlvbioqOiBXYWxkIGFzc3VtZXMgc3ltbWV0cmljIENJIGJhc2VkIG9uIGN1cnZhdHVyZSBhdCBNTEU7IExSVCB1c2VzIGFjdHVhbCBsaWtlbGlob29kIHNoYXBlDQogICsgKipSZXNvbHV0aW9uKio6IFRydXN0IExSVOKAlGl0IHJlc3BlY3RzIHRoZSB0cnVlIGxpa2VsaWhvb2QgZ2VvbWV0cnkNCg0KKiAqKlBhcmFkb3ggMioqOiAiU2NvcmUgdGVzdCBtb3JlIHBvd2VyZnVsIHRoYW4gTFJUIg0KICArICoqT2NjdXJzIHdoZW4qKjogUGFyYW1ldGVyIGF0IGJvdW5kYXJ5LCBzbWFsbCBzYW1wbGVzDQogICsgKipMb2dpY2FsIGV4cGxhbmF0aW9uKio6IFNjb3JlIHVzZXMgZXhhY3QgbnVsbCBkaXN0cmlidXRpb247IExSVCB1c2VzIGFzeW1wdG90aWMgJFxjaGleMiQgYXBwcm94aW1hdGlvbg0KICArICoqUmVzb2x1dGlvbioqOiBVc2UgZXhhY3QgZGlzdHJpYnV0aW9ucyBvciBjb3JyZWN0ZWQgTFJUICg1MDo1MCBtaXh0dXJlICRcY2hpXjIkKQ0KDQoqICoqUGFyYWRveCAzKio6ICJUZXN0cyBkaXNhZ3JlZSBhc3ltcHRvdGljYWxseSINCiAgKyAqKkxvZ2ljYWwgaW1wbGljYXRpb24qKjogTGlrZWx5IG1vZGVsIG1pc3NwZWNpZmljYXRpb24gb3IgY29tcHV0YXRpb25hbCBlcnJvcg0KICArICoqUmVzb2x1dGlvbioqOiBDaGVjayBtb2RlbCBhc3N1bXB0aW9ucyBhbmQgbnVtZXJpY2FsIHN0YWJpbGl0eQ0KDQoNCg0KDQoNCg==