Assignment Objectives
Master the fundamental concepts of point estimation and
performance metrics
Understand the theoretical foundation of the method of moments
estimator (MME)
Implement MME in R, incorporating numerical approximation
methods
Use of AI Tools
Policy on AI Tool Use: Students must adhere to the
AI tool policy specified in the course syllabus. The direct copying of
AI-generated content is strictly prohibited. All submitted work must
reflect your own understanding; where external tools are consulted,
content must be thoroughly rephrased and synthesized in your own
words.
Code Inclusion Requirement: Any code included in
your essay must be properly commented to explain the purpose and/or
expected output of key code lines. Submitting AI-generated code without
meaningful, student-added comments will not be accepted.
Log-logistic Distribution
The log-logistic distribution (also known as the Fisk distribution)
is a continuous probability distribution that is particularly useful in
contexts where data exhibit non-negative, skewed behavior and where the
hazard rate is unimodal (increases to a peak and then decreases). It has
been widely used in the areas such as survival analysis and reliability
engineering, environmental science, economics, pharmacology, finance and
risk management, etc.
For given shape parameter \(\beta\)
and scale parameter \(\alpha\), the
cumulative distribution function
\[
F(x) = \frac{1}{1+(x/\alpha)^{-\beta}}
\]
As an exercise, you can derive the density in the following form
\[
f(x) =
\frac{(\beta/\alpha)(x/\alpha)^{\beta-1}}{[1+(x/\alpha)^\beta]^2}, \ \
\text{ for } \ \ x > 0.
\]
After some algebra, we can find the \(k\)th moment
\[
\mu_k = E[X^k] = \alpha^k B\left(1+\frac{k}{\beta}, 1 - \frac{k}{\beta}
\right).
\]
This assignment will focus on finding MME of parameters \(\alpha\) and \(\beta\) based on a real-world application
data set.
Question 2: Distribution of Recovery Time from A
Surgery
Time to recovery (in days) after a specific knee surgery procedure.
This follows a typical log-logistic pattern in medical
survival/recovery analysis:
8.23, 12.74, 14.83, 16.61, 18.16, 19.55, 20.80, 21.94, 23.00, 23.98, 24.89, 25.75, 26.56,
27.34, 28.08, 28.79, 29.48, 30.15, 30.81, 31.45, 32.08, 32.70, 33.31, 33.92, 34.53, 35.13,
35.73, 36.33, 36.93, 37.53, 38.14, 38.75, 39.37, 40.00, 40.64, 41.29, 41.95, 42.63, 43.33,
44.05, 44.79, 45.56, 46.36, 47.20, 48.08, 49.02, 50.03, 51.12, 52.32, 53.65
Based on the above data to perform the following analysis.
- Using method of moment estimation to estimate \(\alpha\) and \(\beta\), denoted by \(\hat{\alpha}\) and \(\hat{\beta}\), respectively.
recovery = c(8.23, 12.74, 14.83, 16.61, 18.16, 19.55, 20.80, 21.94, 23.00, 23.98, 24.89, 25.75, 26.56,
27.34, 28.08, 28.79, 29.48, 30.15, 30.81, 31.45, 32.08, 32.70, 33.31, 33.92, 34.53, 35.13,
35.73, 36.33, 36.93, 37.53, 38.14, 38.75, 39.37, 40.00, 40.64, 41.29, 41.95, 42.63, 43.33,
44.05, 44.79, 45.56, 46.36, 47.20, 48.08, 49.02, 50.03, 51.12, 52.32, 53.65)
hist(recovery)

s.recovery= sort(recovery)
#a
length(recovery) #n = 50
[1] 50
m1 = mean(recovery) #sample mean x_bar=34.1922
m2 =mean(recovery^2) #second moment #1288
mom_beta <- function(beta, m1, m2)
{
term1 <- ( 2 * pi/ beta) /sin(2 * pi/beta) #second moment
term2 <- ((pi / beta) /sin (pi /beta))^2 #square of mean divided by alpha squared
return(term1 / term2 - (m2 / m1^2))
}
#info found: ://efaidnbmnnnibpcajpcglclefindmkaj/https://www.math.wm.edu/~leemis/chart/UDR/PDFs/Loglogistic.pdf
#nonlinear function must solve for beta
sol_beta <- uniroot(mom_beta, interval = c(2.1, 20), m1 = m1, m2 = m2)$root
#subsitute beta to find alpha
sol_alpha <- m1 / ((pi / sol_beta) / sin(pi / sol_beta))
# Print Results
cat("Estimated Alpha (Scale/Median):", sol_alpha, "\n") #Estimated Alpha (Scale/Median): 32.6543
Estimated Alpha (Scale/Median): 32.6543
cat("Estimated Beta (Shape/Width):", sol_beta, "\n") #Estimated Beta (Shape/Width): 6.006232
Estimated Beta (Shape/Width): 6.006232
Estimated Alpha (Scale/Median): 32.6543 Estimated Beta (Shape/Width):
6.006232
The median recovery time for a patient is 32.65 days. As a lower beta
value at 6 we know that recovery time over all in our sample have
similar times. In other words the shape of our distribution is not very
wide, suggesting there is large variety of time differences in the data;
this does not occur.
- Since the moment estimates \(\hat{\alpha}\) and \(\hat{\beta}\) are random, construct
bootstrap sampling distributions for each. To visualize these
distributions, plot separate bootstrap histograms for \(\hat{\alpha}\) and \(\hat{\beta}\). hen, overlay a smooth
density curve on each histogram using Gaussian kernel density
estimation. Finally, describe the patterns of these density curves.
set.seed(325)
boot_alpha = NULL
boot_beta = NULL
for(i in 1:1000)
{
sample_i = sample(recovery, size=50, replace = TRUE) #random sample from the sample recovery
#calculate moments from the specific samples
m1_i = mean(sample_i) #first moment
m2_i = mean(sample_i^2) #second moment
boot_beta[i] = uniroot(mom_beta, interval = c(2.1, 20), m1 = m1_i, m2 = m2_i)$root
#subsitute beta to find alpha
boot_alpha[i] = m1_i / ((pi /boot_beta[i]) / sin(pi / boot_beta[i]))
}
# Create data frame for plotting
boot_results <- data.frame(alpha = boot_alpha, beta = boot_beta)
# Plotting the boot straps of alpha and beta parameters (boot_results data frame)
bootsggp <- ggplot(boot_results) +
#Graph the Alpha density
geom_density(aes(x = alpha, color = "alpha"), size = 1) +
# Graph the Beta density
geom_density(aes(x = beta, color = "beta"), size = 1) +
labs(title = "Bootstrap Distributions for Alpha (Recovery time) and Beta Log-Logistic Parameters",
x = "Estimate Value",
y = "Density") +
scale_color_manual(name = "Parameters",
values = c("alpha" = "red", "beta" = "blue")) +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))
# Interactive graph
ggplotly(bootsggp)
This graph places the distributions of both the alpha distribution
and the beta distribution on the same place. We see the estimated
bootstrap value of the beta (\(\beta\)
= 5.837965) is far lower than the estimated bootstrap alpha (\(\alpha\) = 30.89606). Additionally the
alpha take on a wider range of values than the beta distribution,
suggesting the beta value has more precision in our distribution. In
other words, the shape of our data set, or how similar our data set to
like recovery times is likely more consistent than the spread of our
data, the distance between the ends of our data.
Additionally, our bootstrap estimated alpha values are similar to the
moment of estimation value of 32.6542985 as well as the beta bootstrap
and moment of estimation at 6.0062322, suggesting both the moment of
estimations hold little bias.
The Bootstrap Parameter’s Alpha and Beta graphed separately with
their respective kernels are below.
#To visualize these distributions, plot separate bootstrap histograms for $\hat{\alpha}$ and $\hat{\beta}$. hen, overlay a smooth density curve on each histogram using Gaussian kernel density estimation. Finally, describe the patterns of these density curves.
#graphing the Bootstrap Parameter's separately with their respective kernels
# Plotting Parameter Alpha (Scale)
p_alpha <- ggplot(boot_results, aes(x = alpha)) +
# The raw data (Histogram)
geom_histogram(aes(y = ..density..), bins = 30, fill = "gray80", color = "white") +
# The Smoothing Line (Gaussian Kernel)
geom_density(color = "red", size = 1, kernel = "gaussian") +
labs(title = "Bootstrap Distribution for Alpha - Recovery Time",
subtitle = "Red line = Gaussian Kernel Smoothing",
x = "Alpha (Days)", y = "Density") +
theme_minimal()
# Separate plot for Parameter Beta (Shape)
p_beta <- ggplot(boot_results, aes(x = beta)) +
# The raw data (Histogram)
geom_histogram(aes(y = ..density..), bins = 30, fill = "gray80", color = "white") +
# The Smoothing Line (Gaussian Kernel)
geom_density(color = "blue", size = 1, kernel = "gaussian") +
labs(title = "Bootstrap Distribution for Beta",
subtitle = "Blue line = Gaussian Kernel Smoothing",
x = "Beta (Shape Parameter)", y = "Density") +
theme_minimal()
#Print interactive graphs
ggplotly(p_alpha)
ggplotly(p_beta)
The alpha parameter, the parameter providing scale for the bootstrap
distribution with its gaussian kernel looks approximately normal,
meeting the assumption of mean of a bootstrap distribution. In other
words, the bootstrap distribution looks as expected.
The beta parameter also looks to take a generally normal
distribution, although may have slight skew. May suggest our normal
based approximation may have some noise in the data, may not be the best
estimation possible. An additional recommendation could be to alter the
bandwidth of the smoothing of the Gaussian kernel, although the kernel
looks generally smooth.
In respect to the recovery time data set, knee surgery recovery time,
alpha, is about 31 days, and through the beta value, this is a
consistent number across most patients.
LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMzogTWV0aG9kcyBvZiBNb21lbnQgRXN0aW1hdGlvbiINCmF1dGhvcjogIkV6YW5hIFJpdmVycyINCmRhdGU6ICIgRHVlOiAyLTI0LTI2Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0NCiNUT0M6OmJlZm9yZSB7DQogIGNvbnRlbnQ6ICJUYWJsZSBvZiBDb250ZW50cyI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXNpemU6IDEuMmVtOw0KICBkaXNwbGF5OiBibG9jazsNCiAgY29sb3I6IG5hdnk7DQogIG1hcmdpbi1ib3R0b206IDEwcHg7DQp9DQoNCg0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLw0KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLw0KICBmb250LXNpemU6IDIycHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQoNCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMTVweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8NCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsNCiAgY29udGVudDogIi4iOw0KDQpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQp9DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KICBsaWJyYXJ5KGdncGxvdDIpDQp9DQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQogIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQogIGxpYnJhcnkocGxvdGx5KQ0KfQ0KIyMjIw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BDQogICAgICAgICAgICAgICAgICAgICAgKSAgDQpgYGANCiANCiBcDQogDQojIyAqKkFzc2lnbm1lbnQgT2JqZWN0aXZlcyoqIA0KDQoqIE1hc3RlciB0aGUgZnVuZGFtZW50YWwgY29uY2VwdHMgb2YgcG9pbnQgZXN0aW1hdGlvbiBhbmQgcGVyZm9ybWFuY2UgbWV0cmljcw0KDQoqIFVuZGVyc3RhbmQgdGhlIHRoZW9yZXRpY2FsIGZvdW5kYXRpb24gb2YgdGhlIG1ldGhvZCBvZiBtb21lbnRzIGVzdGltYXRvciAoTU1FKQ0KDQoqIEltcGxlbWVudCBNTUUgaW4gUiwgaW5jb3Jwb3JhdGluZyBudW1lcmljYWwgYXBwcm94aW1hdGlvbiBtZXRob2RzDQoNClwNCg0KKipVc2Ugb2YgQUkgVG9vbHMqKg0KDQoqKlBvbGljeSBvbiBBSSBUb29sIFVzZSoqOiBTdHVkZW50cyBtdXN0IGFkaGVyZSB0byB0aGUgQUkgdG9vbCBwb2xpY3kgc3BlY2lmaWVkIGluIHRoZSBjb3Vyc2Ugc3lsbGFidXMuIFRoZSBkaXJlY3QgY29weWluZyBvZiBBSS1nZW5lcmF0ZWQgY29udGVudCBpcyBzdHJpY3RseSBwcm9oaWJpdGVkLiBBbGwgc3VibWl0dGVkIHdvcmsgbXVzdCByZWZsZWN0IHlvdXIgb3duIHVuZGVyc3RhbmRpbmc7IHdoZXJlIGV4dGVybmFsIHRvb2xzIGFyZSBjb25zdWx0ZWQsIGNvbnRlbnQgbXVzdCBiZSB0aG9yb3VnaGx5IHJlcGhyYXNlZCBhbmQgc3ludGhlc2l6ZWQgaW4geW91ciBvd24gd29yZHMuDQoNCioqQ29kZSBJbmNsdXNpb24gUmVxdWlyZW1lbnQqKjogQW55IGNvZGUgaW5jbHVkZWQgaW4geW91ciBlc3NheSBtdXN0IGJlIHByb3Blcmx5IGNvbW1lbnRlZCB0byBleHBsYWluIHRoZSBwdXJwb3NlIGFuZC9vciBleHBlY3RlZCBvdXRwdXQgb2Yga2V5IGNvZGUgbGluZXMuIFN1Ym1pdHRpbmcgQUktZ2VuZXJhdGVkIGNvZGUgd2l0aG91dCBtZWFuaW5nZnVsLCBzdHVkZW50LWFkZGVkIGNvbW1lbnRzIHdpbGwgbm90IGJlIGFjY2VwdGVkLg0KDQpcDQoNCioqTG9nLWxvZ2lzdGljIERpc3RyaWJ1dGlvbioqDQoNClRoZSBsb2ctbG9naXN0aWMgZGlzdHJpYnV0aW9uIChhbHNvIGtub3duIGFzIHRoZSBGaXNrIGRpc3RyaWJ1dGlvbikgaXMgYSBjb250aW51b3VzIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiB0aGF0IGlzIHBhcnRpY3VsYXJseSB1c2VmdWwgaW4gY29udGV4dHMgd2hlcmUgZGF0YSBleGhpYml0IG5vbi1uZWdhdGl2ZSwgc2tld2VkIGJlaGF2aW9yIGFuZCB3aGVyZSB0aGUgaGF6YXJkIHJhdGUgaXMgdW5pbW9kYWwgKGluY3JlYXNlcyB0byBhIHBlYWsgYW5kIHRoZW4gZGVjcmVhc2VzKS4gSXQgaGFzIGJlZW4gd2lkZWx5IHVzZWQgaW4gdGhlIGFyZWFzIHN1Y2ggYXMgc3Vydml2YWwgYW5hbHlzaXMgYW5kIHJlbGlhYmlsaXR5IGVuZ2luZWVyaW5nLCBlbnZpcm9ubWVudGFsIHNjaWVuY2UsIGVjb25vbWljcywgcGhhcm1hY29sb2d5LCBmaW5hbmNlIGFuZCByaXNrIG1hbmFnZW1lbnQsIGV0Yy4gDQoNCkZvciBnaXZlbiBzaGFwZSBwYXJhbWV0ZXIgJFxiZXRhJCBhbmQgc2NhbGUgcGFyYW1ldGVyICRcYWxwaGEkLCB0aGUgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24NCg0KJCQNCkYoeCkgPSBcZnJhY3sxfXsxKyh4L1xhbHBoYSleey1cYmV0YX19DQokJA0KDQpBcyBhbiBleGVyY2lzZSwgeW91IGNhbiBkZXJpdmUgdGhlIGRlbnNpdHkgaW4gdGhlIGZvbGxvd2luZyBmb3JtDQoNCiQkDQpmKHgpID0gXGZyYWN7KFxiZXRhL1xhbHBoYSkoeC9cYWxwaGEpXntcYmV0YS0xfX17WzErKHgvXGFscGhhKV5cYmV0YV1eMn0sIFwgXCBcdGV4dHsgZm9yIH0gXCBcIHggPiAwLg0KJCQNCg0KQWZ0ZXIgc29tZSBhbGdlYnJhLCB3ZSBjYW4gZmluZCB0aGUgJGskdGggbW9tZW50DQoNCiQkDQpcbXVfayA9IEVbWF5rXSA9IFxhbHBoYV5rIEJcbGVmdCgxK1xmcmFje2t9e1xiZXRhfSwgMSAtIFxmcmFje2t9e1xiZXRhfSBccmlnaHQpLg0KJCQNCg0KVGhpcyBhc3NpZ25tZW50IHdpbGwgZm9jdXMgb24gZmluZGluZyBNTUUgb2YgcGFyYW1ldGVycyAkXGFscGhhJCBhbmQgJFxiZXRhJCBiYXNlZCBvbiBhIHJlYWwtd29ybGQgYXBwbGljYXRpb24gZGF0YSBzZXQuDQoNCg0KXA0KDQojIyAqKlF1ZXN0aW9uIDE6IERlcml2ZSB0aGUgbG9nLWxvZ2lzdGljIGRlbnNpdHkgZnVuY3Rpb24gKioNCg0KR2l2ZW4gdGhlIENERiBvZiB0aGUgdHdvLXBhcmFtZXRlciBsb2ctbG9naXN0aWMgZGlzdHJpYnV0aW9uDQoNCiQkDQpGKHgpID0gXGZyYWN7MX17MSsoeC9cYWxwaGEpXnstXGJldGF9fS4NCiQkDQoNCg0KVGhlIHByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb24gaXMgdGhlIGRlcml2YXRpdmUgb2YgdGhlIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIG9mIHRoZSBsb2ctbG9naXN0aWMgZnVuY3Rpb24uIA0KDQpgYGB7cn0NCg0KY2RmID0gZXhwcmVzc2lvbigoMSkgLygxICsgKHgvYWxwaGEpKV4oLWJldGEpKSAjd3JpdGUgdGhlIENERiBmb3JtdWxhIGFzIGFuIGV4cHJlc3Npb24gDQpwZGYgPSBEKGNkZiwgIngiKSAjdGFrZSB0aGUgZGVyaXZhdGl2ZSBvZiB0aGUgY2RmDQoNCnByaW50KHBkZikNCg0KYGBgDQoNCg0KXA0KDQojIyAqKlF1ZXN0aW9uIDI6IERpc3RyaWJ1dGlvbiBvZiBSZWNvdmVyeSBUaW1lIGZyb20gQSBTdXJnZXJ5KioNCg0KVGltZSB0byByZWNvdmVyeSAoaW4gZGF5cykgYWZ0ZXIgYSBzcGVjaWZpYyBrbmVlIHN1cmdlcnkgcHJvY2VkdXJlLiBUaGlzIGZvbGxvd3MgYSB0eXBpY2FsICoqbG9nLWxvZ2lzdGljIHBhdHRlcm4qKiBpbiBtZWRpY2FsIHN1cnZpdmFsL3JlY292ZXJ5IGFuYWx5c2lzOg0KDQpgYGANCjguMjMsIDEyLjc0LCAxNC44MywgMTYuNjEsIDE4LjE2LCAxOS41NSwgMjAuODAsIDIxLjk0LCAyMy4wMCwgMjMuOTgsIDI0Ljg5LCAyNS43NSwgMjYuNTYsIA0KMjcuMzQsIDI4LjA4LCAyOC43OSwgMjkuNDgsIDMwLjE1LCAzMC44MSwgMzEuNDUsIDMyLjA4LCAzMi43MCwgMzMuMzEsIDMzLjkyLCAzNC41MywgMzUuMTMsIA0KMzUuNzMsIDM2LjMzLCAzNi45MywgMzcuNTMsIDM4LjE0LCAzOC43NSwgMzkuMzcsIDQwLjAwLCA0MC42NCwgNDEuMjksIDQxLjk1LCA0Mi42MywgNDMuMzMsIA0KNDQuMDUsIDQ0Ljc5LCA0NS41NiwgNDYuMzYsIDQ3LjIwLCA0OC4wOCwgNDkuMDIsIDUwLjAzLCA1MS4xMiwgNTIuMzIsIDUzLjY1DQpgYGANCkJhc2VkIG9uIHRoZSBhYm92ZSBkYXRhIHRvIHBlcmZvcm0gdGhlIGZvbGxvd2luZyBhbmFseXNpcy4NCg0KYSkgVXNpbmcgbWV0aG9kIG9mIG1vbWVudCBlc3RpbWF0aW9uIHRvIGVzdGltYXRlICRcYWxwaGEkIGFuZCAkXGJldGEkLCBkZW5vdGVkIGJ5ICRcaGF0e1xhbHBoYX0kIGFuZCAkXGhhdHtcYmV0YX0kLCByZXNwZWN0aXZlbHkuIA0KDQoNCg0KYGBge3J9DQpyZWNvdmVyeSA9IGMoOC4yMywgMTIuNzQsIDE0LjgzLCAxNi42MSwgMTguMTYsIDE5LjU1LCAyMC44MCwgMjEuOTQsIDIzLjAwLCAyMy45OCwgMjQuODksIDI1Ljc1LCAyNi41NiwgDQoyNy4zNCwgMjguMDgsIDI4Ljc5LCAyOS40OCwgMzAuMTUsIDMwLjgxLCAzMS40NSwgMzIuMDgsIDMyLjcwLCAzMy4zMSwgMzMuOTIsIDM0LjUzLCAzNS4xMywgDQozNS43MywgMzYuMzMsIDM2LjkzLCAzNy41MywgMzguMTQsIDM4Ljc1LCAzOS4zNywgNDAuMDAsIDQwLjY0LCA0MS4yOSwgNDEuOTUsIDQyLjYzLCA0My4zMywgDQo0NC4wNSwgNDQuNzksIDQ1LjU2LCA0Ni4zNiwgNDcuMjAsIDQ4LjA4LCA0OS4wMiwgNTAuMDMsIDUxLjEyLCA1Mi4zMiwgNTMuNjUpDQoNCmhpc3QocmVjb3ZlcnkpDQoNCnMucmVjb3Zlcnk9IHNvcnQocmVjb3ZlcnkpDQojYQ0KDQpsZW5ndGgocmVjb3ZlcnkpICNuID0gNTANCm0xID0gbWVhbihyZWNvdmVyeSkgI3NhbXBsZSBtZWFuIHhfYmFyPTM0LjE5MjINCm0yID1tZWFuKHJlY292ZXJ5XjIpICNzZWNvbmQgbW9tZW50ICMxMjg4DQoNCm1vbV9iZXRhIDwtIGZ1bmN0aW9uKGJldGEsIG0xLCBtMikNCnsNCiAgdGVybTEgPC0gKCAyICogcGkvIGJldGEpIC9zaW4oMiAqIHBpL2JldGEpICAjc2Vjb25kIG1vbWVudA0KICB0ZXJtMiA8LSAoKHBpIC8gYmV0YSkgL3NpbiAocGkgL2JldGEpKV4yICAjc3F1YXJlIG9mIG1lYW4gZGl2aWRlZCBieSBhbHBoYSBzcXVhcmVkDQogIA0KICByZXR1cm4odGVybTEgLyB0ZXJtMiAtIChtMiAvIG0xXjIpKQ0KfQ0KI2luZm8gZm91bmQ6IDovL2VmYWlkbmJtbm5uaWJwY2FqcGNnbGNsZWZpbmRta2FqL2h0dHBzOi8vd3d3Lm1hdGgud20uZWR1L35sZWVtaXMvY2hhcnQvVURSL1BERnMvTG9nbG9naXN0aWMucGRmDQoNCiNub25saW5lYXIgZnVuY3Rpb24gbXVzdCBzb2x2ZSBmb3IgYmV0YQ0KICAgIHNvbF9iZXRhIDwtIHVuaXJvb3QobW9tX2JldGEsIGludGVydmFsID0gYygyLjEsIDIwKSwgbTEgPSBtMSwgbTIgPSBtMikkcm9vdA0KI3N1YnNpdHV0ZSBiZXRhIHRvIGZpbmQgYWxwaGENCiAgICBzb2xfYWxwaGEgPC0gbTEgLyAoKHBpIC8gc29sX2JldGEpIC8gc2luKHBpIC8gc29sX2JldGEpKQ0KICAgIA0KIyBQcmludCBSZXN1bHRzDQpjYXQoIkVzdGltYXRlZCBBbHBoYSAoU2NhbGUvTWVkaWFuKToiLCBzb2xfYWxwaGEsICJcbiIpICNFc3RpbWF0ZWQgQWxwaGEgKFNjYWxlL01lZGlhbik6IDMyLjY1NDMgDQpjYXQoIkVzdGltYXRlZCBCZXRhIChTaGFwZS9XaWR0aCk6Iiwgc29sX2JldGEsICJcbiIpICAjRXN0aW1hdGVkIEJldGEgKFNoYXBlL1dpZHRoKTogNi4wMDYyMzIgDQoNCg0KDQoNCg0KYGBgDQpFc3RpbWF0ZWQgQWxwaGEgKFNjYWxlL01lZGlhbik6IDMyLjY1NDMgDQpFc3RpbWF0ZWQgQmV0YSAoU2hhcGUvV2lkdGgpOiA2LjAwNjIzMg0KDQpUaGUgbWVkaWFuIHJlY292ZXJ5IHRpbWUgZm9yIGEgcGF0aWVudCBpcyAzMi42NSBkYXlzLiBBcyBhIGxvd2VyIGJldGEgdmFsdWUgYXQgNiB3ZSBrbm93IHRoYXQgcmVjb3ZlcnkgdGltZSBvdmVyIGFsbCBpbiBvdXIgc2FtcGxlIGhhdmUgc2ltaWxhciB0aW1lcy4gSW4gb3RoZXIgd29yZHMgdGhlIHNoYXBlIG9mIG91ciBkaXN0cmlidXRpb24gaXMgbm90IHZlcnkgd2lkZSwgc3VnZ2VzdGluZyB0aGVyZSBpcyBsYXJnZSB2YXJpZXR5IG9mIHRpbWUgZGlmZmVyZW5jZXMgaW4gdGhlIGRhdGE7IHRoaXMgZG9lcyBub3Qgb2NjdXIuDQoNCmIpIFNpbmNlIHRoZSBtb21lbnQgZXN0aW1hdGVzICRcaGF0e1xhbHBoYX0kIGFuZCAkXGhhdHtcYmV0YX0kIGFyZSByYW5kb20sIGNvbnN0cnVjdCBib290c3RyYXAgc2FtcGxpbmcgZGlzdHJpYnV0aW9ucyBmb3IgZWFjaC4gVG8gdmlzdWFsaXplIHRoZXNlIGRpc3RyaWJ1dGlvbnMsIHBsb3Qgc2VwYXJhdGUgYm9vdHN0cmFwIGhpc3RvZ3JhbXMgZm9yICRcaGF0e1xhbHBoYX0kIGFuZCAkXGhhdHtcYmV0YX0kLiAgaGVuLCBvdmVybGF5IGEgc21vb3RoIGRlbnNpdHkgY3VydmUgb24gZWFjaCBoaXN0b2dyYW0gdXNpbmcgR2F1c3NpYW4ga2VybmVsIGRlbnNpdHkgZXN0aW1hdGlvbi4gRmluYWxseSwgZGVzY3JpYmUgdGhlIHBhdHRlcm5zIG9mIHRoZXNlIGRlbnNpdHkgY3VydmVzLg0KDQpgYGB7cn0NCnNldC5zZWVkKDMyNSkNCg0KYm9vdF9hbHBoYSA9IE5VTEwNCmJvb3RfYmV0YSA9IE5VTEwNCg0KZm9yKGkgaW4gMToxMDAwKQ0Kew0KICBzYW1wbGVfaSA9IHNhbXBsZShyZWNvdmVyeSwgc2l6ZT01MCwgcmVwbGFjZSA9IFRSVUUpICNyYW5kb20gc2FtcGxlIGZyb20gdGhlIHNhbXBsZSByZWNvdmVyeQ0KICANCiAgI2NhbGN1bGF0ZSBtb21lbnRzIGZyb20gdGhlIHNwZWNpZmljIHNhbXBsZXMNCiAgDQptMV9pID0gbWVhbihzYW1wbGVfaSkgICNmaXJzdCBtb21lbnQNCm0yX2kgPSBtZWFuKHNhbXBsZV9pXjIpICNzZWNvbmQgbW9tZW50DQogIA0KICBib290X2JldGFbaV0gPSB1bmlyb290KG1vbV9iZXRhLCBpbnRlcnZhbCA9IGMoMi4xLCAyMCksIG0xID0gbTFfaSwgbTIgPSBtMl9pKSRyb290DQojc3Vic2l0dXRlIGJldGEgdG8gZmluZCBhbHBoYQ0KICBib290X2FscGhhW2ldID0gbTFfaSAvICgocGkgL2Jvb3RfYmV0YVtpXSkgLyBzaW4ocGkgLyBib290X2JldGFbaV0pKQ0KDQoNCn0NCg0KDQoNCiMgQ3JlYXRlIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nDQpib290X3Jlc3VsdHMgPC0gZGF0YS5mcmFtZShhbHBoYSA9IGJvb3RfYWxwaGEsIGJldGEgPSBib290X2JldGEpDQogDQoNCmBgYA0KYGBge3J9DQojIFBsb3R0aW5nIHRoZSBib290IHN0cmFwcyBvZiBhbHBoYSBhbmQgYmV0YSBwYXJhbWV0ZXJzIChib290X3Jlc3VsdHMgZGF0YSBmcmFtZSkNCmJvb3RzZ2dwIDwtIGdncGxvdChib290X3Jlc3VsdHMpICsNCiAgI0dyYXBoIHRoZSBBbHBoYSBkZW5zaXR5DQogIGdlb21fZGVuc2l0eShhZXMoeCA9IGFscGhhLCBjb2xvciA9ICJhbHBoYSIpLCBzaXplID0gMSkgKw0KICAjIEdyYXBoIHRoZSBCZXRhIGRlbnNpdHkNCiAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gYmV0YSwgY29sb3IgPSAiYmV0YSIpLCBzaXplID0gMSkgKw0KICANCiAgbGFicyh0aXRsZSA9ICJCb290c3RyYXAgRGlzdHJpYnV0aW9ucyBmb3IgQWxwaGEgKFJlY292ZXJ5IHRpbWUpIGFuZCBCZXRhIExvZy1Mb2dpc3RpYyBQYXJhbWV0ZXJzIiwNCiAgICAgICB4ID0gIkVzdGltYXRlIFZhbHVlIiwgDQogICAgICAgeSA9ICJEZW5zaXR5IikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJhbWV0ZXJzIiwgDQogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbHBoYSIgPSAicmVkIiwgImJldGEiID0gImJsdWUiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KIyBJbnRlcmFjdGl2ZSBncmFwaA0KZ2dwbG90bHkoYm9vdHNnZ3ApDQpgYGANCg0KVGhpcyBncmFwaCBwbGFjZXMgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgYm90aCB0aGUgYWxwaGEgZGlzdHJpYnV0aW9uIGFuZCB0aGUgYmV0YSBkaXN0cmlidXRpb24gb24gdGhlIHNhbWUgcGxhY2UuIFdlIHNlZSB0aGUgZXN0aW1hdGVkIGJvb3RzdHJhcCB2YWx1ZSBvZiB0aGUgYmV0YSAoJFxiZXRhJCA9IDUuODM3OTY1KSBpcyBmYXIgbG93ZXIgdGhhbiB0aGUgZXN0aW1hdGVkIGJvb3RzdHJhcCBhbHBoYSAoJFxhbHBoYSQgPSAzMC44OTYwNikuIEFkZGl0aW9uYWxseSB0aGUgYWxwaGEgdGFrZSBvbiBhIHdpZGVyIHJhbmdlIG9mIHZhbHVlcyB0aGFuIHRoZSBiZXRhIGRpc3RyaWJ1dGlvbiwgc3VnZ2VzdGluZyB0aGUgYmV0YSB2YWx1ZSBoYXMgbW9yZSBwcmVjaXNpb24gaW4gb3VyIGRpc3RyaWJ1dGlvbi4gSW4gb3RoZXIgd29yZHMsIHRoZSBzaGFwZSBvZiBvdXIgZGF0YSBzZXQsIG9yIGhvdyBzaW1pbGFyIG91ciBkYXRhIHNldCB0byBsaWtlIHJlY292ZXJ5IHRpbWVzIGlzIGxpa2VseSBtb3JlIGNvbnNpc3RlbnQgdGhhbiB0aGUgc3ByZWFkIG9mIG91ciBkYXRhLCB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGUgZW5kcyBvZiBvdXIgZGF0YS4NCg0KQWRkaXRpb25hbGx5LCBvdXIgYm9vdHN0cmFwIGVzdGltYXRlZCBhbHBoYSB2YWx1ZXMgYXJlIHNpbWlsYXIgdG8gdGhlIG1vbWVudCBvZiBlc3RpbWF0aW9uIHZhbHVlIG9mICBgciBzb2xfYWxwaGFgIGFzIHdlbGwgYXMgdGhlIGJldGEgYm9vdHN0cmFwIGFuZCBtb21lbnQgb2YgZXN0aW1hdGlvbiBhdCBgciBzb2xfYmV0YWAsIHN1Z2dlc3RpbmcgYm90aCB0aGUgbW9tZW50IG9mIGVzdGltYXRpb25zIGhvbGQgbGl0dGxlIGJpYXMuDQoNCg0KDQpUaGUgQm9vdHN0cmFwIFBhcmFtZXRlcidzIEFscGhhIGFuZCBCZXRhIGdyYXBoZWQgc2VwYXJhdGVseSB3aXRoIHRoZWlyIHJlc3BlY3RpdmUga2VybmVscyBhcmUgYmVsb3cuDQoNCmBgYHtyfQ0KI1RvIHZpc3VhbGl6ZSB0aGVzZSBkaXN0cmlidXRpb25zLCBwbG90IHNlcGFyYXRlIGJvb3RzdHJhcCBoaXN0b2dyYW1zIGZvciAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JC4gIGhlbiwgb3ZlcmxheSBhIHNtb290aCBkZW5zaXR5IGN1cnZlIG9uIGVhY2ggaGlzdG9ncmFtIHVzaW5nIEdhdXNzaWFuIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRpb24uIEZpbmFsbHksIGRlc2NyaWJlIHRoZSBwYXR0ZXJucyBvZiB0aGVzZSBkZW5zaXR5IGN1cnZlcy4NCg0KI2dyYXBoaW5nIHRoZSBCb290c3RyYXAgUGFyYW1ldGVyJ3Mgc2VwYXJhdGVseSB3aXRoIHRoZWlyIHJlc3BlY3RpdmUga2VybmVscw0KDQojIFBsb3R0aW5nIFBhcmFtZXRlciBBbHBoYSAoU2NhbGUpDQpwX2FscGhhIDwtIGdncGxvdChib290X3Jlc3VsdHMsIGFlcyh4ID0gYWxwaGEpKSArDQogICMgVGhlIHJhdyBkYXRhIChIaXN0b2dyYW0pDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBiaW5zID0gMzAsIGZpbGwgPSAiZ3JheTgwIiwgY29sb3IgPSAid2hpdGUiKSArDQogICMgVGhlIFNtb290aGluZyBMaW5lIChHYXVzc2lhbiBLZXJuZWwpDQogIGdlb21fZGVuc2l0eShjb2xvciA9ICJyZWQiLCBzaXplID0gMSwga2VybmVsID0gImdhdXNzaWFuIikgKw0KICBsYWJzKHRpdGxlID0gIkJvb3RzdHJhcCBEaXN0cmlidXRpb24gZm9yIEFscGhhIC0gUmVjb3ZlcnkgVGltZSIsDQogICAgICAgc3VidGl0bGUgPSAiUmVkIGxpbmUgPSBHYXVzc2lhbiBLZXJuZWwgU21vb3RoaW5nIiwNCiAgICAgICB4ID0gIkFscGhhIChEYXlzKSIsIHkgPSAiRGVuc2l0eSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgU2VwYXJhdGUgcGxvdCBmb3IgUGFyYW1ldGVyIEJldGEgKFNoYXBlKQ0KcF9iZXRhIDwtIGdncGxvdChib290X3Jlc3VsdHMsIGFlcyh4ID0gYmV0YSkpICsNCiAgIyBUaGUgcmF3IGRhdGEgKEhpc3RvZ3JhbSkNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLiksIGJpbnMgPSAzMCwgZmlsbCA9ICJncmF5ODAiLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgIyBUaGUgU21vb3RoaW5nIExpbmUgKEdhdXNzaWFuIEtlcm5lbCkNCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gImJsdWUiLCBzaXplID0gMSwga2VybmVsID0gImdhdXNzaWFuIikgKw0KICBsYWJzKHRpdGxlID0gIkJvb3RzdHJhcCBEaXN0cmlidXRpb24gZm9yIEJldGEiLA0KICAgICAgIHN1YnRpdGxlID0gIkJsdWUgbGluZSA9IEdhdXNzaWFuIEtlcm5lbCBTbW9vdGhpbmciLA0KICAgICAgIHggPSAiQmV0YSAoU2hhcGUgUGFyYW1ldGVyKSIsIHkgPSAiRGVuc2l0eSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiNQcmludCBpbnRlcmFjdGl2ZSBncmFwaHMNCmdncGxvdGx5KHBfYWxwaGEpIA0KZ2dwbG90bHkocF9iZXRhKQ0KIA0KYGBgDQoNClRoZSBhbHBoYSBwYXJhbWV0ZXIsIHRoZSBwYXJhbWV0ZXIgcHJvdmlkaW5nIHNjYWxlIGZvciB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiB3aXRoIGl0cyBnYXVzc2lhbiBrZXJuZWwgbG9va3MgYXBwcm94aW1hdGVseSBub3JtYWwsIG1lZXRpbmcgdGhlIGFzc3VtcHRpb24gb2YgbWVhbiBvZiBhIGJvb3RzdHJhcCBkaXN0cmlidXRpb24uIEluIG90aGVyIHdvcmRzLCB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiBsb29rcyBhcyBleHBlY3RlZC4NCg0KDQpUaGUgYmV0YSBwYXJhbWV0ZXIgYWxzbyBsb29rcyB0byB0YWtlIGEgZ2VuZXJhbGx5IG5vcm1hbCBkaXN0cmlidXRpb24sIGFsdGhvdWdoIG1heSBoYXZlIHNsaWdodCBza2V3LiBNYXkgc3VnZ2VzdCBvdXIgbm9ybWFsIGJhc2VkIGFwcHJveGltYXRpb24gbWF5IGhhdmUgc29tZSBub2lzZSBpbiB0aGUgZGF0YSwgbWF5IG5vdCBiZSB0aGUgYmVzdCBlc3RpbWF0aW9uIHBvc3NpYmxlLiBBbiBhZGRpdGlvbmFsIHJlY29tbWVuZGF0aW9uIGNvdWxkIGJlIHRvIGFsdGVyIHRoZSBiYW5kd2lkdGggb2YgdGhlIHNtb290aGluZyBvZiB0aGUgR2F1c3NpYW4ga2VybmVsLCBhbHRob3VnaCB0aGUga2VybmVsIGxvb2tzIGdlbmVyYWxseSBzbW9vdGguIA0KDQpJbiByZXNwZWN0IHRvIHRoZSByZWNvdmVyeSB0aW1lIGRhdGEgc2V0LCBrbmVlIHN1cmdlcnkgcmVjb3ZlcnkgdGltZSwgYWxwaGEsIGlzIGFib3V0IDMxIGRheXMsIGFuZCB0aHJvdWdoIHRoZSBiZXRhIHZhbHVlLCB0aGlzIGlzIGEgY29uc2lzdGVudCBudW1iZXIgYWNyb3NzIG1vc3QgcGF0aWVudHMu