For this exam, we will be estimating the parameters of a lognormal
distribution using a data set that consists of the sizes of 50 recently
drilled oil reserves.
oil <- c(17.3, 24.8, 8.2, 31.5, 14.1, 42.7, 11.9, 55.3, 21.4, 9.7, 36.2, 18.6, 63.1, 13.2, 28.9,
47.5, 19.8, 7.5, 33.4, 52.1, 16.0, 25.9, 38.7, 10.3, 44.2, 22.5, 58.6, 12.8, 30.3, 48.9,
20.1, 35.4, 15.7, 60.2, 26.7, 41.3, 18.1, 53.8, 23.9, 46.2, 29.4, 37.6, 14.9, 50.5, 32.8,
19.3, 56.7, 11.2, 39.5, 27.1)
Question 1
For this question, we will use the method of moments to estimate
\(\mu\) and \(\sigma^2\). Then we will use those
parameter estimates to estimate the mean of the lognormal
distribution.
Part A
For Part A, we will derive and set up both the system of equations
for the moments. The Derivation of the system of equations is as
follows: and then subsequently obtain the parameter estimates to use to
find the mean of the lognormal distribution. The derivations are as
follows:
Distribution moments: \(E(X^k) = \exp(k\mu
+ \frac{1}{2} k^2 \sigma^2)\)
Distribution moment 1: \(E(x) = \exp(\mu +
\frac{1}{2} \sigma^2)\)
Distribution moment 2: \(E(x^2) = \exp(2\mu
+ 2\sigma^2)\)
Sample moments: \(E(X^k) = \frac{1}{n} \sum
X_i^k = m_k\)
Sample moment 1: \(E(x) = \frac{1}{n} \sum
X_i = \bar{x} = m_1\)
Sample moment 2: \(E(x^2) = \frac{1}{n}
\sum X_i^2 = m_2\)
\(E(x) = E(x) \Rightarrow \exp(\mu +
\frac{1}{2} \sigma^2) = \frac{1}{n} \sum_{i=1}^n X_i = \bar{x} =
m_1\)
\(E(x^2) = E(x^2) = \exp(2\mu + 2\sigma^2)
= \frac{1}{n} \sum X_i^2 = m_2\)
Part B
For this part, we will now solve for both \(\mu\) and \(\sigma^2\) and obtain the estimates.
\(\exp(\mu + \frac{1}{2} \sigma^2) = m_1
\Rightarrow \mu + \frac{1}{2} \sigma^2 = \ln m_1\)
\(\exp(2\mu + 2\sigma^2) = m_2 \Rightarrow
2\mu + 2\sigma^2 = \ln m_2\)
\[\begin{align*}
2\mu + \sigma^2 &= 2 \ln m_1 \\
2\mu + 2\sigma^2 &= \ln m_2
\end{align*}\]
\(\Rightarrow \sigma^2 = \ln m_2 - 2 \ln
m_1 = \ln \frac{m_2}{m_1^2}\)
\[\begin{align*}
\mu + \frac{1}{2} (\ln m_2 - 2 \ln m_1) &= \ln m_1 \\
\mu + \frac{1}{2} \ln m_2 - \ln m_1 &= \ln m_1 \\
\mu &= 2 \ln m_1 - \frac{1}{2} \ln m_2
\end{align*}\]
Part C
For part c, we must write a function that will return the parameter
estimates and the mean of the lognormal distribution.
n <- length(oil) # sample size of oil
m1.samp <- mean(oil) # first sample moment
m2.samp <- mean(oil^2) # second sample moment
mm.param.est <- function(data) {
mm.mu.est = 2*log(m1.samp) - log(m2.samp)/2
# method of moments estimator for mu
mm.var.est = log(m2.samp) - 2*log(m1.samp)
# method of moments estimator for varianc
mm.logmean.est <- exp(mm.mu.est + mm.var.est/2)
# mm estimator for lognormal mean
return(c(as.numeric(mm.mu.est), as.numeric(mm.var.est), as.numeric(mm.logmean.est)))
# converts outputs into a numerical vector and outputs list
}
mm.param.est(oil) # oil is the data set we're using
[1] 3.3012685 0.2339652 30.5160000
According to the output, \(\widetilde{\mu}\) is 3.3013, \(\widetilde\sigma^2\) is 0.234, and the
population mean, \(\widetilde{\mu_{LN}}\), is 30.516.
Question 2
For this question, we will derive the maxmimum likelihood estimators
for \(\mu\) and \(\sigma^2\). We will then use those
estimates to generate both the maximum likelihood estimate for the mean
of the lognormal distribution. We will also use the moments from the
previous question to derive the variance estimate of the lognormal.
Part A
For Part A, we will derive the score functions, also known as the
gradient(s) of the log-likelihood function. The derivations are as
follows:
\(L(\mu, \sigma^2 | X) = \prod_{i=1}^n
f(x_i | \mu, \sigma^2) = \prod_{i=1}^n \frac{1}{x_i \sqrt{2\pi\sigma^2}}
\exp\left( -\frac{(\ln(x_i) - \mu)^2}{2\sigma^2} \right)\)
\(= \left( \prod_{i=1}^n \frac{1}{x_i}
\right) \left( \frac{1}{\sqrt{2\pi\sigma^2}} \right)^n \exp\left(
\sum_{i=1}^n -\frac{(\ln(x_i) - \mu)^2}{2\sigma^2} \right)\)
\(= \left( \prod_{i=1}^n x_i \right)^{-1}
(2\pi\sigma^2)^{-\frac{n}{2}} \exp\left( -\frac{1}{2\sigma^2}
\sum_{i=1}^n (\ln(x_i) - \mu)^2 \right)\)
\(\ln(L) = -\ln\left( \prod_{i=1}^n x_i
\right) - \frac{n}{2} \ln(2\pi\sigma^2) - \frac{1}{2\sigma^2}
\sum_{i=1}^n (\ln(x_i) - \mu)^2\)
\(= -\sum_{i=1}^n \ln(x_i) - \frac{n}{2}
\ln(2\pi) - \frac{n}{2} \ln(\sigma^2) - \frac{1}{2\sigma^2} \sum_{i=1}^n
(\ln(x_i) - \mu)^2\)
Part B
For Part B, we will now solve for both \(\mu\) and \(\sigma^2\) and obtain the maximum
likelihood estimates.
\(\frac{\partial \ln L}{\partial \mu} =
\frac{\partial}{\partial \mu} \left( -\frac{1}{2\sigma^2} \sum_{i=1}^n
(\ln(x_i) - \mu)^2 \right) = -\frac{1}{2\sigma^2} \sum_{i=1}^n
\frac{\partial}{\partial \mu} (\ln(x_i) - \mu)^2\)
\(= -\frac{1}{2\sigma^2} (2)(-1)
\sum_{i=1}^n (\ln(x_i) - \mu) = \frac{1}{\sigma^2} \sum_{i=1}^n
(\ln(x_i) - \mu) = 0\)
\(\frac{1}{\sigma^2} \sum_{i=1}^n \ln(x_i)
- \frac{1}{\sigma^2} \sum_{i=1}^n \mu = 0 \Rightarrow \sum \ln(x_i) =
n\mu \Rightarrow \mu = \frac{1}{n} \sum \ln(x_i) \text{ or }
\ln(\bar{x})\)
\(\frac{\partial \ln L}{\partial \sigma^2}
= \frac{\partial}{\partial \sigma^2} \left( -\frac{n}{2} \ln(\sigma^2) -
\frac{1}{2\sigma^2} \sum_{i=1}^n (\ln(x_i) - \mu)^2 \right) =
0\)
\(= -\frac{n}{2} \left( \frac{1}{\sigma^2}
\right) (2\sigma) - \frac{1}{2} (-2)(\sigma^{-3}) \sum_{i=1}^n (\ln(x_i)
- \mu)^2 = 0\)
\(-\frac{n}{\sigma} + \frac{1}{\sigma^3}
\sum_{i=1}^n (\ln(x_i) - \mu)^2 = 0 \Rightarrow \frac{1}{\sigma^3}
\sum_{i=1}^n (\ln(x_i) - \mu)^2 = \frac{n}{\sigma}\)
\(\sum (\ln(x_i) - \mu)^2 = n\sigma^2
\Rightarrow \sigma^2 = \frac{1}{n} \sum (\ln(x_i) - \mu)^2\)
Part C
For this section, we will use the relationship between the variance
and the moments of a distribution to derive the formula for the variance
of the lognormal distribution.
\(Var(X) = E(X^2) - (E(X))^2\)
\(= \exp(2\mu + 2\sigma^2) - (\exp(\mu +
\frac{1}{2}\sigma^2))^2\)
\(= \exp(2\mu + 2\sigma^2) - \exp(2\mu +
\sigma^2) = \exp(2\mu) \exp(2\sigma^2) - \exp(2\mu)
\exp(\sigma^2)\)
\(= \exp(2\mu + \sigma^2) [\exp(\sigma^2) -
1]\)
n <- length(oil) # sample size
mu.mle <- sum(log(oil))/n # MLE for mu
sigmasquare.mle <- sum((log(oil) - (mu.mle))^2)/n # mle for sigma^2
mu.lognorm.mle <- exp(mu.mle + sigmasquare.mle/2)
c(mu.mle, sigmasquare.mle, mu.lognorm.mle) # estimate for mean of lognormal
[1] 3.2685359 0.3271989 30.9426444
Question 3
For this question, we will estimate the mean of the lognormal
distribution nonparametrically. Specifically, we will use bootstrapping
to generate a sampling distribution of the mean and compare it to an
asymptotic distribution of the sampling mean.
Part A
For Part A, we will write a function to estimate the maximum
likelihood estimators for \(\mu\) and
\(\sigma^2\)
lognorm.loglik <- function(params, data) {
mu.mle <- params[1] # passing the parameters
ss.mle <- params[2]
n <- length(oil) # sample size
# Log-likelihood for lognormal distribution
loglik.lognorm <- -sum(log(oil)) - n*log(2*pi)/2 - n*log(ss.mle/2) - sum((log(oil) - mean(ss.mle))^2)/(2*ss.mle)
return(loglik.lognorm) # Return negative for minimization
}
## Score (gradient) equation
lognorm.score <- function(params, data) {
mu.mle <- params[1]
ss.mle <- params[2]
n <- length(oil)
# Gradient for mean is mean of ln(x)
grad_mu <- mean(log(oil))
# Gradient for variance is variance of the ln(x)
grad_ss <- (n-1)*var(log(oil))/n
# multiplying by (n-1) to cancel (n-1) in denominator then dividing by n to get gradient of variance
# Estimate of mean of lognormal
logmean.mle <- exp(grad_mu + grad_ss/2)
return(c(grad_mu, grad_ss, logmean.mle))
}
lognorm.score(oil)
[1] 3.2685359 0.3271989 30.9426444
According to the output, \(\widehat{\mu}\) is 3.2685, \(\widehat{\sigma^2}\) is 0.3272, and \(\widehat{\mu_{LN}}\) is 30.9426.
Part B
For Part B, we will take 1000 bootstrap samples and find the
bootstrap MLE for each resample.
set.seed(1) # generate same numbers every time for sample
original.sample = sample(oil, # resampling from oil sample
50, # sample size = 50
replace = FALSE) # sample without replacement
# Bootstrap sampling
bt.sample.logmean.vec = NULL # define an empty vector to hold sample means of repeated samples
for(i in 1:1000){ # starting for-loop to take bootstrap samples with n = 50
ith.bt.sample = sample(x = original.sample, # Original sample with 50 oil reserves
size = 50, # size must be equal to the sample size
replace = TRUE) # MUST use WITH REPLACEMENT!!
bt.sample.logmean.vec[i] = mean(ith.bt.sample) # calculates the mean of
# i-th bootstrap sample and saves it in the empty vector: bt.sample.logmean.vec
}
mean(bt.sample.logmean.vec)
[1] 30.45754
According to the output, \(\widehat{\mu_{LN}}\) is 30.4575. Since we
do have enough data points (\(n \gt
30\)), we could potentially apply the central limit theorem
toward this sampling distribution.
Part C
For Part C, we will use a kernel density to estimate the density of
the bootstrap sampling distribution.
hist(bt.sample.logmean.vec, # data used for histogram
breaks = 14, # specify number of vertical bars
probability = TRUE, # y values are density values
xlab = "Sample Mean of the Lognormal Distribution", # change the label of x-axis
# add a title to the histogram
main = "Histogram of Bootstrap Sampling Distribution of Lognormal Sample Means",
cex.main = 0.9,
col.main = "navy", col = "lightblue")
lines(density(bt.sample.logmean.vec, kernel = "gaussian"), col = "red", lwd = 2) # adds kernel density estimate curve to histogram

bt.density.logmean <- density(bt.sample.logmean.vec, kernel = "gaussian")
bt.density.logmean # calls gaussian kernel density estimates
Call:
density.default(x = bt.sample.logmean.vec, kernel = "gaussian")
Data: bt.sample.logmean.vec (1000 obs.); Bandwidth 'bw' = 0.5116
x y
Min. :21.89 Min. :8.770e-06
1st Qu.:26.36 1st Qu.:2.490e-03
Median :30.83 Median :2.655e-02
Mean :30.83 Mean :5.579e-02
3rd Qu.:35.31 3rd Qu.:1.121e-01
Max. :39.78 Max. :1.728e-01
According to the output of the density function, it looks like \(\widehat{\mu_{LN}}\) is 30.83. As for the
histogram, it somewhat resembles a normal distribution. The density
curve (red) resembles a very rough looking bell shape.
LS0tDQp0aXRsZTogIk1heGltdW0gTGlrZWxpaG9vZCBFc3RpbWF0aW9uIChNTEUpIg0KYXV0aG9yOiAiQ2hlbmcgUGVuZyINCmRhdGU6ICJXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lDQogICAgdGhlbWU6IHNwYWNlbGFiDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge2NzcywgZWNobyA9IEZBTFNFfQ0KI1RPQzo6YmVmb3JlIHsNCiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMS4yZW07DQogIGRpc3BsYXk6IGJsb2NrOw0KICBjb2xvcjogbmF2eTsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KDQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQp9DQoNCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovDQogIGZvbnQtc2l6ZTogMjJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCg0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxNXB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLw0KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgew0KICBjb250ZW50OiAiLiI7DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCn0NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQogIGxpYnJhcnkoZ2dwbG90MikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQoNCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgbGlicmFyeShwbG90bHkpDQp9DQppZiAoIXJlcXVpcmUoImZpdGRpc3RycGx1cyIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImZpdGRpc3RycGx1cyIpDQogIGxpYnJhcnkoZml0ZGlzdHJwbHVzKQ0KfQ0KIyMgbGlicmFyeShmaXRkaXN0cnBsdXMpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KDQpcDQoNCkZvciB0aGlzIGV4YW0sIHdlIHdpbGwgYmUgZXN0aW1hdGluZyB0aGUgcGFyYW1ldGVycyBvZiBhIGxvZ25vcm1hbCBkaXN0cmlidXRpb24gdXNpbmcgYSBkYXRhIHNldCB0aGF0IGNvbnNpc3RzIG9mIHRoZSBzaXplcyBvZiA1MCByZWNlbnRseSBkcmlsbGVkIG9pbCByZXNlcnZlcy4NCmBgYHtyfQ0Kb2lsIDwtIGMoMTcuMywgMjQuOCwgOC4yLCAzMS41LCAxNC4xLCA0Mi43LCAxMS45LCA1NS4zLCAyMS40LCA5LjcsIDM2LjIsIDE4LjYsIDYzLjEsIDEzLjIsIDI4LjksIA0KNDcuNSwgMTkuOCwgNy41LCAzMy40LCA1Mi4xLCAxNi4wLCAyNS45LCAzOC43LCAxMC4zLCA0NC4yLCAyMi41LCA1OC42LCAxMi44LCAzMC4zLCA0OC45LCANCjIwLjEsIDM1LjQsIDE1LjcsIDYwLjIsIDI2LjcsIDQxLjMsIDE4LjEsIDUzLjgsIDIzLjksIDQ2LjIsIDI5LjQsIDM3LjYsIDE0LjksIDUwLjUsIDMyLjgsIA0KMTkuMywgNTYuNywgMTEuMiwgMzkuNSwgMjcuMSkNCmBgYA0KDQojIFF1ZXN0aW9uIDENCkZvciB0aGlzIHF1ZXN0aW9uLCB3ZSB3aWxsIHVzZSB0aGUgbWV0aG9kIG9mIG1vbWVudHMgdG8gZXN0aW1hdGUgJFxtdSQgYW5kICRcc2lnbWFeMiQuIFRoZW4gd2Ugd2lsbCB1c2UgdGhvc2UgcGFyYW1ldGVyIGVzdGltYXRlcyB0byBlc3RpbWF0ZSB0aGUgbWVhbiBvZiB0aGUgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbi4NCg0KIyMgUGFydCBBDQpGb3IgUGFydCBBLCB3ZSB3aWxsIGRlcml2ZSBhbmQgc2V0IHVwIGJvdGggdGhlIHN5c3RlbSBvZiBlcXVhdGlvbnMgZm9yIHRoZSBtb21lbnRzLiBUaGUgRGVyaXZhdGlvbiBvZiB0aGUgc3lzdGVtIG9mIGVxdWF0aW9ucyBpcyBhcyBmb2xsb3dzOiBhbmQgdGhlbiBzdWJzZXF1ZW50bHkgb2J0YWluIHRoZSBwYXJhbWV0ZXIgZXN0aW1hdGVzIHRvIHVzZSB0byBmaW5kIHRoZSBtZWFuIG9mIHRoZSBsb2dub3JtYWwgZGlzdHJpYnV0aW9uLiBUaGUgZGVyaXZhdGlvbnMgYXJlIGFzIGZvbGxvd3M6DQoNCg0KRGlzdHJpYnV0aW9uIG1vbWVudHM6ICRFKFheaykgPSBcZXhwKGtcbXUgKyBcZnJhY3sxfXsyfSBrXjIgXHNpZ21hXjIpJA0KDQpEaXN0cmlidXRpb24gbW9tZW50IDE6ICRFKHgpID0gXGV4cChcbXUgKyBcZnJhY3sxfXsyfSBcc2lnbWFeMikkDQoNCkRpc3RyaWJ1dGlvbiBtb21lbnQgMjogJEUoeF4yKSA9IFxleHAoMlxtdSArIDJcc2lnbWFeMikkIA0KDQpTYW1wbGUgbW9tZW50czogJEUoWF5rKSA9IFxmcmFjezF9e259IFxzdW0gWF9pXmsgPSBtX2skDQoNClNhbXBsZSBtb21lbnQgMTogJEUoeCkgPSBcZnJhY3sxfXtufSBcc3VtIFhfaSA9IFxiYXJ7eH0gPSBtXzEkDQoNClNhbXBsZSBtb21lbnQgMjogJEUoeF4yKSA9IFxmcmFjezF9e259IFxzdW0gWF9pXjIgPSBtXzIkIA0KDQokRSh4KSA9IEUoeCkgXFJpZ2h0YXJyb3cgXGV4cChcbXUgKyBcZnJhY3sxfXsyfSBcc2lnbWFeMikgPSBcZnJhY3sxfXtufSBcc3VtX3tpPTF9Xm4gWF9pID0gXGJhcnt4fSA9IG1fMSQNCg0KJEUoeF4yKSA9IEUoeF4yKSA9IFxleHAoMlxtdSArIDJcc2lnbWFeMikgPSBcZnJhY3sxfXtufSBcc3VtIFhfaV4yID0gbV8yJCANCg0KDQojIyBQYXJ0IEINCkZvciB0aGlzIHBhcnQsIHdlIHdpbGwgbm93IHNvbHZlIGZvciBib3RoICRcbXUkIGFuZCAkXHNpZ21hXjIkIGFuZCBvYnRhaW4gdGhlIGVzdGltYXRlcy4NCg0KDQokXGV4cChcbXUgKyBcZnJhY3sxfXsyfSBcc2lnbWFeMikgPSBtXzEgXFJpZ2h0YXJyb3cgXG11ICsgXGZyYWN7MX17Mn0gXHNpZ21hXjIgPSBcbG4gbV8xJCANCg0KJFxleHAoMlxtdSArIDJcc2lnbWFeMikgPSBtXzIgXFJpZ2h0YXJyb3cgMlxtdSArIDJcc2lnbWFeMiA9IFxsbiBtXzIkIA0KDQpcYmVnaW57YWxpZ24qfQ0KMlxtdSArIFxzaWdtYV4yICY9IDIgXGxuIG1fMSAgXFwNCjJcbXUgKyAyXHNpZ21hXjIgJj0gXGxuIG1fMiANClxlbmR7YWxpZ24qfQ0KDQokXFJpZ2h0YXJyb3cgXHNpZ21hXjIgPSBcbG4gbV8yIC0gMiBcbG4gbV8xID0gXGxuIFxmcmFje21fMn17bV8xXjJ9JA0KDQpcYmVnaW57YWxpZ24qfQ0KXG11ICsgXGZyYWN7MX17Mn0gKFxsbiBtXzIgLSAyIFxsbiBtXzEpICY9IFxsbiBtXzEgXFwNClxtdSArIFxmcmFjezF9ezJ9IFxsbiBtXzIgLSBcbG4gbV8xICY9IFxsbiBtXzEgXFwNClxtdSAmPSAyIFxsbiBtXzEgLSBcZnJhY3sxfXsyfSBcbG4gbV8yIA0KXGVuZHthbGlnbip9DQoNCg0KIyMgUGFydCBDDQpGb3IgcGFydCBjLCB3ZSBtdXN0IHdyaXRlIGEgZnVuY3Rpb24gdGhhdCB3aWxsIHJldHVybiB0aGUgcGFyYW1ldGVyIGVzdGltYXRlcyBhbmQgdGhlIG1lYW4gb2YgdGhlIGxvZ25vcm1hbCBkaXN0cmlidXRpb24uDQpgYGB7cn0NCm4gPC0gbGVuZ3RoKG9pbCkgIyBzYW1wbGUgc2l6ZSBvZiBvaWwNCg0KbTEuc2FtcCA8LSBtZWFuKG9pbCkgIyBmaXJzdCBzYW1wbGUgbW9tZW50IA0KbTIuc2FtcCA8LSBtZWFuKG9pbF4yKSAjIHNlY29uZCBzYW1wbGUgbW9tZW50DQoNCm1tLnBhcmFtLmVzdCA8LSBmdW5jdGlvbihkYXRhKSB7DQoNCm1tLm11LmVzdCA9IDIqbG9nKG0xLnNhbXApIC0gbG9nKG0yLnNhbXApLzIgDQojIG1ldGhvZCBvZiBtb21lbnRzIGVzdGltYXRvciBmb3IgbXUNCm1tLnZhci5lc3QgPSBsb2cobTIuc2FtcCkgLSAyKmxvZyhtMS5zYW1wKQ0KIyBtZXRob2Qgb2YgbW9tZW50cyBlc3RpbWF0b3IgZm9yIHZhcmlhbmMNCg0KbW0ubG9nbWVhbi5lc3QgPC0gZXhwKG1tLm11LmVzdCArIG1tLnZhci5lc3QvMikNCiMgbW0gZXN0aW1hdG9yIGZvciBsb2dub3JtYWwgbWVhbg0KDQpyZXR1cm4oYyhhcy5udW1lcmljKG1tLm11LmVzdCksIGFzLm51bWVyaWMobW0udmFyLmVzdCksIGFzLm51bWVyaWMobW0ubG9nbWVhbi5lc3QpKSkNCiMgY29udmVydHMgb3V0cHV0cyBpbnRvIGEgbnVtZXJpY2FsIHZlY3RvciBhbmQgb3V0cHV0cyBsaXN0DQoNCn0NCg0KbW0ucGFyYW0uZXN0KG9pbCkgIyBvaWwgaXMgdGhlIGRhdGEgc2V0IHdlJ3JlIHVzaW5nDQoNCg0KDQpgYGANCkFjY29yZGluZyB0byB0aGUgb3V0cHV0LCAkXHdpZGV0aWxkZXtcbXV9JCBpcyAzLjMwMTMsICRcd2lkZXRpbGRlXHNpZ21hXjIkIGlzIDAuMjM0LCBhbmQgdGhlIHBvcHVsYXRpb24gbWVhbiwgJFx3aWRldGlsZGV7XG11X3tMTn19JCwgaXMgMzAuNTE2Lg0KDQojIFF1ZXN0aW9uIDINCkZvciB0aGlzIHF1ZXN0aW9uLCB3ZSB3aWxsIGRlcml2ZSB0aGUgbWF4bWltdW0gbGlrZWxpaG9vZCBlc3RpbWF0b3JzIGZvciAkXG11JCBhbmQgJFxzaWdtYV4yJC4gV2Ugd2lsbCB0aGVuIHVzZSB0aG9zZSBlc3RpbWF0ZXMgdG8gZ2VuZXJhdGUgYm90aCB0aGUgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRlIGZvciB0aGUgbWVhbiBvZiB0aGUgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbi4gV2Ugd2lsbCBhbHNvIHVzZSB0aGUgbW9tZW50cyBmcm9tIHRoZSBwcmV2aW91cyBxdWVzdGlvbiB0byBkZXJpdmUgdGhlIHZhcmlhbmNlIGVzdGltYXRlIG9mIHRoZSBsb2dub3JtYWwuDQoNCiMjIFBhcnQgQQ0KRm9yIFBhcnQgQSwgd2Ugd2lsbCBkZXJpdmUgdGhlIHNjb3JlIGZ1bmN0aW9ucywgYWxzbyBrbm93biBhcyB0aGUgZ3JhZGllbnQocykgb2YgdGhlIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uLiBUaGUgZGVyaXZhdGlvbnMgYXJlIGFzIGZvbGxvd3M6DQoNCiRMKFxtdSwgXHNpZ21hXjIgfCBYKSA9IFxwcm9kX3tpPTF9Xm4gZih4X2kgfCBcbXUsIFxzaWdtYV4yKSA9IFxwcm9kX3tpPTF9Xm4gXGZyYWN7MX17eF9pIFxzcXJ0ezJccGlcc2lnbWFeMn19IFxleHBcbGVmdCggLVxmcmFjeyhcbG4oeF9pKSAtIFxtdSleMn17MlxzaWdtYV4yfSBccmlnaHQpJA0KDQoNCiQ9IFxsZWZ0KCBccHJvZF97aT0xfV5uIFxmcmFjezF9e3hfaX0gXHJpZ2h0KSBcbGVmdCggXGZyYWN7MX17XHNxcnR7MlxwaVxzaWdtYV4yfX0gXHJpZ2h0KV5uIFxleHBcbGVmdCggXHN1bV97aT0xfV5uIC1cZnJhY3soXGxuKHhfaSkgLSBcbXUpXjJ9ezJcc2lnbWFeMn0gXHJpZ2h0KSQNCg0KJD0gXGxlZnQoIFxwcm9kX3tpPTF9Xm4geF9pIFxyaWdodCleey0xfSAoMlxwaVxzaWdtYV4yKV57LVxmcmFje259ezJ9fSBcZXhwXGxlZnQoIC1cZnJhY3sxfXsyXHNpZ21hXjJ9IFxzdW1fe2k9MX1ebiAoXGxuKHhfaSkgLSBcbXUpXjIgXHJpZ2h0KSQgDQoNCiRcbG4oTCkgPSAtXGxuXGxlZnQoIFxwcm9kX3tpPTF9Xm4geF9pIFxyaWdodCkgLSBcZnJhY3tufXsyfSBcbG4oMlxwaVxzaWdtYV4yKSAtIFxmcmFjezF9ezJcc2lnbWFeMn0gXHN1bV97aT0xfV5uIChcbG4oeF9pKSAtIFxtdSleMiQgDQoNCiQ9IC1cc3VtX3tpPTF9Xm4gXGxuKHhfaSkgLSBcZnJhY3tufXsyfSBcbG4oMlxwaSkgLSBcZnJhY3tufXsyfSBcbG4oXHNpZ21hXjIpIC0gXGZyYWN7MX17MlxzaWdtYV4yfSBcc3VtX3tpPTF9Xm4gKFxsbih4X2kpIC0gXG11KV4yJA0KDQojIyBQYXJ0IEINCkZvciBQYXJ0IEIsIHdlIHdpbGwgbm93IHNvbHZlIGZvciBib3RoICRcbXUkIGFuZCAkXHNpZ21hXjIkIGFuZCBvYnRhaW4gdGhlIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0ZXMuDQoNCiRcZnJhY3tccGFydGlhbCBcbG4gTH17XHBhcnRpYWwgXG11fSA9IFxmcmFje1xwYXJ0aWFsfXtccGFydGlhbCBcbXV9IFxsZWZ0KCAtXGZyYWN7MX17MlxzaWdtYV4yfSBcc3VtX3tpPTF9Xm4gKFxsbih4X2kpIC0gXG11KV4yIFxyaWdodCkgPSAtXGZyYWN7MX17MlxzaWdtYV4yfSBcc3VtX3tpPTF9Xm4gXGZyYWN7XHBhcnRpYWx9e1xwYXJ0aWFsIFxtdX0gKFxsbih4X2kpIC0gXG11KV4yJCANCg0KJD0gLVxmcmFjezF9ezJcc2lnbWFeMn0gKDIpKC0xKSBcc3VtX3tpPTF9Xm4gKFxsbih4X2kpIC0gXG11KSA9IFxmcmFjezF9e1xzaWdtYV4yfSBcc3VtX3tpPTF9Xm4gKFxsbih4X2kpIC0gXG11KSA9IDAkIA0KDQokXGZyYWN7MX17XHNpZ21hXjJ9IFxzdW1fe2k9MX1ebiBcbG4oeF9pKSAtIFxmcmFjezF9e1xzaWdtYV4yfSBcc3VtX3tpPTF9Xm4gXG11ID0gMCBcUmlnaHRhcnJvdyBcc3VtIFxsbih4X2kpID0gblxtdSBcUmlnaHRhcnJvdyBcbXUgPSBcZnJhY3sxfXtufSBcc3VtIFxsbih4X2kpIFx0ZXh0eyBvciB9IFxsbihcYmFye3h9KSQgDQoNCiRcZnJhY3tccGFydGlhbCBcbG4gTH17XHBhcnRpYWwgXHNpZ21hXjJ9ID0gXGZyYWN7XHBhcnRpYWx9e1xwYXJ0aWFsIFxzaWdtYV4yfSBcbGVmdCggLVxmcmFje259ezJ9IFxsbihcc2lnbWFeMikgLSBcZnJhY3sxfXsyXHNpZ21hXjJ9IFxzdW1fe2k9MX1ebiAoXGxuKHhfaSkgLSBcbXUpXjIgXHJpZ2h0KSA9IDAkIA0KDQokPSAtXGZyYWN7bn17Mn0gXGxlZnQoIFxmcmFjezF9e1xzaWdtYV4yfSBccmlnaHQpICgyXHNpZ21hKSAtIFxmcmFjezF9ezJ9ICgtMikoXHNpZ21hXnstM30pIFxzdW1fe2k9MX1ebiAoXGxuKHhfaSkgLSBcbXUpXjIgPSAwJCANCg0KJC1cZnJhY3tufXtcc2lnbWF9ICsgXGZyYWN7MX17XHNpZ21hXjN9IFxzdW1fe2k9MX1ebiAoXGxuKHhfaSkgLSBcbXUpXjIgPSAwIFxSaWdodGFycm93IFxmcmFjezF9e1xzaWdtYV4zfSBcc3VtX3tpPTF9Xm4gKFxsbih4X2kpIC0gXG11KV4yID0gXGZyYWN7bn17XHNpZ21hfSQgDQoNCiRcc3VtIChcbG4oeF9pKSAtIFxtdSleMiA9IG5cc2lnbWFeMiBcUmlnaHRhcnJvdyBcc2lnbWFeMiA9IFxmcmFjezF9e259IFxzdW0gKFxsbih4X2kpIC0gXG11KV4yJCANCg0KIyMgUGFydCBDDQpGb3IgdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIHVzZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmlhbmNlIGFuZCB0aGUgbW9tZW50cyBvZiBhIGRpc3RyaWJ1dGlvbiB0byBkZXJpdmUgdGhlIGZvcm11bGEgZm9yIHRoZSB2YXJpYW5jZSBvZiB0aGUgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbi4NCg0KJFZhcihYKSA9IEUoWF4yKSAtIChFKFgpKV4yJCANCg0KJD0gXGV4cCgyXG11ICsgMlxzaWdtYV4yKSAtIChcZXhwKFxtdSArIFxmcmFjezF9ezJ9XHNpZ21hXjIpKV4yJCANCg0KJD0gXGV4cCgyXG11ICsgMlxzaWdtYV4yKSAtIFxleHAoMlxtdSArIFxzaWdtYV4yKSA9IFxleHAoMlxtdSkgXGV4cCgyXHNpZ21hXjIpIC0gXGV4cCgyXG11KSBcZXhwKFxzaWdtYV4yKSQgDQoNCiQ9IFxleHAoMlxtdSArIFxzaWdtYV4yKSBbXGV4cChcc2lnbWFeMikgLSAxXSQgDQoNCg0KYGBge3J9DQpuIDwtIGxlbmd0aChvaWwpICMgc2FtcGxlIHNpemUgDQoNCm11Lm1sZSA8LSBzdW0obG9nKG9pbCkpL24gIyBNTEUgZm9yIG11DQpzaWdtYXNxdWFyZS5tbGUgPC0gc3VtKChsb2cob2lsKSAtIChtdS5tbGUpKV4yKS9uICMgbWxlIGZvciBzaWdtYV4yDQptdS5sb2dub3JtLm1sZSA8LSBleHAobXUubWxlICsgc2lnbWFzcXVhcmUubWxlLzIpIA0KDQpjKG11Lm1sZSwgc2lnbWFzcXVhcmUubWxlLCBtdS5sb2dub3JtLm1sZSkgIyBlc3RpbWF0ZSBmb3IgbWVhbiBvZiBsb2dub3JtYWwNCmBgYA0KDQojIFF1ZXN0aW9uIDMNCkZvciB0aGlzIHF1ZXN0aW9uLCB3ZSB3aWxsIGVzdGltYXRlIHRoZSBtZWFuIG9mIHRoZSBsb2dub3JtYWwgZGlzdHJpYnV0aW9uIG5vbnBhcmFtZXRyaWNhbGx5LiBTcGVjaWZpY2FsbHksIHdlIHdpbGwgdXNlIGJvb3RzdHJhcHBpbmcgdG8gZ2VuZXJhdGUgYSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgdGhlIG1lYW4gYW5kIGNvbXBhcmUgaXQgdG8gYW4gYXN5bXB0b3RpYyBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsaW5nIG1lYW4uDQoNCiMjIFBhcnQgQQ0KRm9yIFBhcnQgQSwgd2Ugd2lsbCB3cml0ZSBhIGZ1bmN0aW9uIHRvIGVzdGltYXRlIHRoZSBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdG9ycyBmb3IgJFxtdSQgYW5kICRcc2lnbWFeMiQNCmBgYHtyfQ0KbG9nbm9ybS5sb2dsaWsgPC0gZnVuY3Rpb24ocGFyYW1zLCBkYXRhKSB7DQoNCm11Lm1sZSA8LSBwYXJhbXNbMV0gICMgcGFzc2luZyB0aGUgcGFyYW1ldGVycw0Kc3MubWxlIDwtIHBhcmFtc1syXQ0KDQpuIDwtIGxlbmd0aChvaWwpICAgIyBzYW1wbGUgc2l6ZQ0KICANCiAgIyBMb2ctbGlrZWxpaG9vZCBmb3IgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbg0KICBsb2dsaWsubG9nbm9ybSA8LSAtc3VtKGxvZyhvaWwpKSAtIG4qbG9nKDIqcGkpLzIgLSBuKmxvZyhzcy5tbGUvMikgLSBzdW0oKGxvZyhvaWwpIC0gbWVhbihzcy5tbGUpKV4yKS8oMipzcy5tbGUpDQogIA0KICByZXR1cm4obG9nbGlrLmxvZ25vcm0pICAgICMgUmV0dXJuIG5lZ2F0aXZlIGZvciBtaW5pbWl6YXRpb24NCg0KfQ0KDQoNCiMjIFNjb3JlIChncmFkaWVudCkgZXF1YXRpb24NCg0KbG9nbm9ybS5zY29yZSA8LSBmdW5jdGlvbihwYXJhbXMsIGRhdGEpIHsNCg0KbXUubWxlIDwtIHBhcmFtc1sxXQ0Kc3MubWxlIDwtIHBhcmFtc1syXQ0KIA0KbiA8LSBsZW5ndGgob2lsKQ0KICANCiMgR3JhZGllbnQgZm9yIG1lYW4gaXMgbWVhbiBvZiBsbih4KQ0KZ3JhZF9tdSA8LSBtZWFuKGxvZyhvaWwpKQ0KICANCiMgR3JhZGllbnQgZm9yIHZhcmlhbmNlIGlzIHZhcmlhbmNlIG9mIHRoZSBsbih4KQ0KZ3JhZF9zcyA8LSAobi0xKSp2YXIobG9nKG9pbCkpL24gDQojIG11bHRpcGx5aW5nIGJ5IChuLTEpIHRvIGNhbmNlbCAobi0xKSBpbiBkZW5vbWluYXRvciB0aGVuIGRpdmlkaW5nIGJ5IG4gdG8gZ2V0IGdyYWRpZW50IG9mIHZhcmlhbmNlDQoNCiMgRXN0aW1hdGUgb2YgbWVhbiBvZiBsb2dub3JtYWwNCmxvZ21lYW4ubWxlIDwtIGV4cChncmFkX211ICsgZ3JhZF9zcy8yKQ0KDQpyZXR1cm4oYyhncmFkX211LCBncmFkX3NzLCBsb2dtZWFuLm1sZSkpDQoNCg0KfQ0KDQoNCmxvZ25vcm0uc2NvcmUob2lsKQ0KYGBgDQpBY2NvcmRpbmcgdG8gdGhlIG91dHB1dCwgJFx3aWRlaGF0e1xtdX0kIGlzIDMuMjY4NSwgJFx3aWRlaGF0e1xzaWdtYV4yfSQgaXMgMC4zMjcyLCBhbmQgJFx3aWRlaGF0e1xtdV97TE59fSQgaXMgMzAuOTQyNi4NCg0KIyMgUGFydCBCDQpGb3IgUGFydCBCLCB3ZSB3aWxsIHRha2UgMTAwMCBib290c3RyYXAgc2FtcGxlcyBhbmQgZmluZCB0aGUgYm9vdHN0cmFwIE1MRSBmb3IgZWFjaCByZXNhbXBsZS4NCmBgYHtyfQ0Kc2V0LnNlZWQoMSkgIyBnZW5lcmF0ZSBzYW1lIG51bWJlcnMgZXZlcnkgdGltZSBmb3Igc2FtcGxlDQoNCm9yaWdpbmFsLnNhbXBsZSA9IHNhbXBsZShvaWwsICAgICAgICMgcmVzYW1wbGluZyBmcm9tIG9pbCBzYW1wbGUgDQogICAgICAgICAgICAgICAgICAgICAgICAgNTAsICAgICAgICMgc2FtcGxlIHNpemUgPSA1MA0KICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlID0gRkFMU0UpICMgc2FtcGxlIHdpdGhvdXQgcmVwbGFjZW1lbnQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiMgQm9vdHN0cmFwIHNhbXBsaW5nIA0KYnQuc2FtcGxlLmxvZ21lYW4udmVjID0gTlVMTCAgICAgICMgZGVmaW5lIGFuIGVtcHR5IHZlY3RvciB0byBob2xkIHNhbXBsZSBtZWFucyBvZiByZXBlYXRlZCBzYW1wbGVzDQpmb3IoaSBpbiAxOjEwMDApeyAgICAgICAgICAgICAgIyBzdGFydGluZyBmb3ItbG9vcCB0byB0YWtlIGJvb3RzdHJhcCBzYW1wbGVzIHdpdGggbiA9IDUwDQppdGguYnQuc2FtcGxlID0gc2FtcGxlKHggPSBvcmlnaW5hbC5zYW1wbGUsICMgT3JpZ2luYWwgc2FtcGxlIHdpdGggNTAgb2lsIHJlc2VydmVzDQpzaXplID0gNTAsICMgIHNpemUgbXVzdCBiZSBlcXVhbCB0byB0aGUgc2FtcGxlIHNpemUNCnJlcGxhY2UgPSBUUlVFKSAjIE1VU1QgdXNlIFdJVEggUkVQTEFDRU1FTlQhIQ0KDQpidC5zYW1wbGUubG9nbWVhbi52ZWNbaV0gPSBtZWFuKGl0aC5idC5zYW1wbGUpICMgY2FsY3VsYXRlcyB0aGUgbWVhbiBvZiANCiMgaS10aCBib290c3RyYXAgc2FtcGxlIGFuZCBzYXZlcyBpdCBpbiB0aGUgZW1wdHkgdmVjdG9yOiBidC5zYW1wbGUubG9nbWVhbi52ZWMgDQp9DQoNCm1lYW4oYnQuc2FtcGxlLmxvZ21lYW4udmVjKQ0KYGBgDQpBY2NvcmRpbmcgdG8gdGhlIG91dHB1dCwgJFx3aWRlaGF0e1xtdV97TE59fSQgaXMgMzAuNDU3NS4gU2luY2Ugd2UgZG8gaGF2ZSBlbm91Z2ggZGF0YSBwb2ludHMgKCRuIFxndCAzMCQpLCB3ZSBjb3VsZCBwb3RlbnRpYWxseSBhcHBseSB0aGUgY2VudHJhbCBsaW1pdCB0aGVvcmVtIHRvd2FyZCB0aGlzIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbi4NCg0KIyMgUGFydCBDDQpGb3IgUGFydCBDLCB3ZSB3aWxsIHVzZSBhIGtlcm5lbCBkZW5zaXR5IHRvIGVzdGltYXRlIHRoZSBkZW5zaXR5IG9mIHRoZSBib290c3RyYXAgc2FtcGxpbmcgZGlzdHJpYnV0aW9uLg0KYGBge3J9DQpoaXN0KGJ0LnNhbXBsZS5sb2dtZWFuLnZlYywgICAjIGRhdGEgdXNlZCBmb3IgaGlzdG9ncmFtDQogICAgIGJyZWFrcyA9IDE0LCAgICMgc3BlY2lmeSBudW1iZXIgb2YgdmVydGljYWwgYmFycw0KICAgICBwcm9iYWJpbGl0eSA9IFRSVUUsICMgeSB2YWx1ZXMgYXJlIGRlbnNpdHkgdmFsdWVzDQogICAgICAgeGxhYiA9ICJTYW1wbGUgTWVhbiBvZiB0aGUgTG9nbm9ybWFsIERpc3RyaWJ1dGlvbiIsICMgY2hhbmdlIHRoZSBsYWJlbCBvZiB4LWF4aXMNCiAgICAgICMgYWRkIGEgdGl0bGUgdG8gdGhlIGhpc3RvZ3JhbQ0KICAgICAgICBtYWluID0gIkhpc3RvZ3JhbSBvZiBCb290c3RyYXAgU2FtcGxpbmcgRGlzdHJpYnV0aW9uIG9mIExvZ25vcm1hbCBTYW1wbGUgTWVhbnMiLA0KICAgICAgICAgIGNleC5tYWluID0gMC45LA0KICAgICAgIGNvbC5tYWluID0gIm5hdnkiLCBjb2wgPSAibGlnaHRibHVlIikgICANCmxpbmVzKGRlbnNpdHkoYnQuc2FtcGxlLmxvZ21lYW4udmVjLCBrZXJuZWwgPSAiZ2F1c3NpYW4iKSwgY29sID0gInJlZCIsIGx3ZCA9IDIpICMgYWRkcyBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0ZSBjdXJ2ZSB0byBoaXN0b2dyYW0NCg0KYnQuZGVuc2l0eS5sb2dtZWFuIDwtIGRlbnNpdHkoYnQuc2FtcGxlLmxvZ21lYW4udmVjLCBrZXJuZWwgPSAiZ2F1c3NpYW4iKQ0KYnQuZGVuc2l0eS5sb2dtZWFuICMgY2FsbHMgZ2F1c3NpYW4ga2VybmVsIGRlbnNpdHkgZXN0aW1hdGVzDQpgYGANCkFjY29yZGluZyB0byB0aGUgb3V0cHV0IG9mIHRoZSBkZW5zaXR5IGZ1bmN0aW9uLCBpdCBsb29rcyBsaWtlICRcd2lkZWhhdHtcbXVfe0xOfX0kIGlzIDMwLjgzLiBBcyBmb3IgdGhlIGhpc3RvZ3JhbSwgaXQgc29tZXdoYXQgcmVzZW1ibGVzIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gVGhlIGRlbnNpdHkgY3VydmUgKHJlZCkgcmVzZW1ibGVzIGEgdmVyeSByb3VnaCBsb29raW5nIGJlbGwgc2hhcGUuDQoNCg==