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)

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.

1.1 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\)

1.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*}\]

1.3 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.

2 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.

2.1 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\)

2.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\)

2.3 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

3 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.

3.1 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.

3.2 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.

3.3 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==