Assignment Objectives
Develop a clear technical understanding of nonparametric
cumulative distribution function (CDF) estimation and various kernel
density estimators.
Translate mathematical formulas into R functions and apply them
to solve related problems.
Create effective visualizations to demonstrate your understanding
of key concepts in the following questions.
Question 1: Cumulative Distribution Function (CDF)
Estimation
The following failure times (in hours) were observed for 8 electronic
components:
23, 45, 67, 89, 112, 156, 189, 245
- Write an R function implementing the ECDF \(\hat{F}_n(t)\) according to its
mathematical definition. Validate your implementation using R’s ecdf()
function on the given data, with comparison based on their step
functions.
x <- c(23, 45, 67, 89, 112, 156, 189, 245)
# My ECDF
my_ecdf <- function(data) {
n <- length(data)
function(t) {
sum(data <= t) / n
}
}
my_ecdf <- my_ecdf(x)
I will validate my implementation of the ECDF using R’s ecf()
function. First, I will do so by using several different values as
input, and ensuring that I get the same results from both ways.
# R's ECDF
R_ecdf <- ecdf(x)
# Comparing ECDF values between my function and R's function
t_vals <- seq(0, 260, by = 50)
cbind(
t = t_vals,
my_ecdf = sapply(t_vals, my_ecdf),
builtin = R_ecdf(t_vals)
)
t my_ecdf builtin
[1,] 0 0.000 0.000
[2,] 50 0.250 0.250
[3,] 100 0.500 0.500
[4,] 150 0.625 0.625
[5,] 200 0.875 0.875
[6,] 250 1.000 1.000
The values match up perfectly between my ECDF and the built-in R ECDF
indicating that my function has been created properly.
plot(R_ecdf, verticals = TRUE, do.points = FALSE, col = "blue", lwd = 2,
main = "Comparison of MY ECDF and R's ECDF",
xlab = "Failure Times",
ylab = "ECDF")
t_grid <- seq(0, 260, length.out = 1000)
lines(t_grid, sapply(t_grid, my_ecdf), type = "s", col = "orange",
lwd = 2,lty = 2)
legend("bottomright", legend = c("R ecdf()", "My ECDF"),
col = c("blue", "orange"), lty = c(1, 2), lwd = 2, bty = "n")

As seen in the graph above, my ECDF and the built-in R ECDF match up
perfectly, thus validating my function.
- A colleague claims that the probability of failure before 100 hours
is 0.5 based on these data. Do you agree? Explain your reasoning using
the empirical cumulative distribution function (ECDF).
Yes, I do agree with this colleague’s claim. In this data set, there
are four total values that are less than 100, these values are 23, 45,
67, and 89. There are eight total values all together in the data set.
The empirical cumulative distribution function says that the probability
can be found by taking the total number of values that are less than the
desired value, in this case 100, and dividing that by the total number
of values in the whole data set.
\[
F_n(x) = \frac{[\ \text{Number of } X_i \le x]}{n} = \frac{4}{8} = 0.5
\]
The ECDF gives that the probability of failure before 100 hours is
0.5 which matches up with this colleague’s claim.
Question 2: Density Function Estimation
Consider the following failure times from a mechanical system:
12.3, 14.7, 15.2, 16.8, 18.1, 19.4, 20.6, 22.3, 23.9, 25.4
- Create a histogram of the data using 3 equally spaced bins. What is
the estimated density in each bin? Describe the shape of the histogram’s
distribution.
y <- c(12.3, 14.7, 15.2, 16.8, 18.1, 19.4, 20.6, 22.3, 23.9, 25.4)
breaks <- seq(12.3, 25.4, length.out = 4)
hist(y, breaks = breaks, probability = TRUE,
main = "Histogram",
xlab = "Failure Time")

The histogram is unimodal and symmetric, and appears to be
approximately normally distributed. In the first bin, the density
appears to be around 0.07. In the second bin, the density appears to be
around 0.09. In the third bin, the density appears to be around
0.07.
- Write an R function that computes kernel density estimates using a
Gaussian kernel with \(h=2\). Validate
your implementation against R’s built-in density() function.
\[
\hat{f}_h(t) = \frac{1}{nh}\sum_{i=1}^n K\left( \frac{t-t_i}{h}\right),
\ \ \text{ where } \ \ K(u) = \frac{1}{\sqrt{2\pi}} e^{-u^2/2}.
\]
I will begin with creating my estimation for a Gaussian kernel with
h=2.
Gaussian <- function(t, data, h) {
n <- length(data)
sapply(t, function(x) {
mean(dnorm((x - data) / h)) / h
})
}
Next, I will validate against R’s built-in density function.
t_grid <- seq(min(y) - 2, max(y) + 2, length.out = 200)
plot(t_grid, Gaussian(t_grid, y, h = 2),
type = "l", col = "orange", lwd = 2,
main = "Gaussian (h = 2)",
xlab = "Failure Time", ylab = "Density")
lines(density(y, kernel = "gaussian", bw = 2),
col = "blue", lty = 2)
legend("topright",
legend = c("My Gaussian", "R's Built-in function"),
col = c("orange", "blue"), lty = c(1, 2))

As seen above, my estimation using a Gaussian kernel with h=2 matches
up perfectly with R’s built-in density() function. This successfully
validates the function that I created.
- Write a custom R function that computes kernel density estimates
using the Epanechnikov kernel with \(h=2\). Validate your implementation by
comparing results with R’s built-in density() function for Gaussian
kernel estimation.
\[
\hat{f}_h(t) = \frac{1}{nh}\sum_{i=1}^n K\left( \frac{t-t_i}{h}\right),
\ \ \text{ where } \ \ K(u) = \frac{3}{4}(1 - u^2) \ \ \text{ for } \ \
|u| \le 1.
\]
I will begin with creating my estimation for a Epanechnikov kernel
with h=2.
Epanechnikov <- function(t, data, h) {
n <- length(data)
sapply(t, function(x) {
u <- (x - data) / h
mean(0.75 * (1 - u^2) * (abs(u) <= 1)) / h
})
}
Next, I will validate against R’s built-in density function.
plot(t_grid, Epanechnikov (t_grid, y, h = 2),
type = "l", col = "orange", lwd = 2,
main = "Kernel Density Estimates",
xlab = "Failure Time", ylab = "Density")
lines(density(y, bw = 2), col = "blue", lty = 2)
legend("topright",
legend = c("Epanechnikov KDE", "Gaussian KDE"),
col = c("orange", "blue"), lty = c(1, 2))

My Epanechnikov kernel matches up with the same patterns shown by
that of R’s built-in function’s estimation. This successfully validates
my Epanechnikov kernel function. The Epanechnikov kernel shows more
variability and sharper peaks than the smooth pattern of the Gaussian
kernel. However, the overall trends are the same between the two.
- How does the choice of kernel (Gaussian vs. Epanechnikov) affect the
density estimate? For both kernel estimators applied to this dataset,
what happens when we select \(h=1.5\)
versus \(h=2.5\)?
Both kernels provide similar information regarding this data set,
however, their appearences show some differences between one another.
The Epanechnikov kernel has a sharper peak than the Gaussian kernel,
which was seen in the graphically comparisons of both kernels. The
Gaussian kernel has a more broad range, while the Epanechnikov kernel is
more compact, with a sharper peak as opposed to a gradual curve like the
Gaussian kernel.
A lower bandwidth like h = 1.5 would have more variability, and a
less smooth estimate. On the other hand, a higher bandwidth like h = 2.5
would have a smoother estimate, but less of a noticeable peak in its
visualization. The bandwidth used in the previous parts b and c of h = 2
is a good middle ground between these two bandwidths.
LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMTogRXN0aW1hdGluZyBDREYgYW5kIFBERiINCmF1dGhvcjogIkpvc2llIEdhbGxvcCINCmRhdGU6ICIgRHVlOiAwMi0wMy0yMDI2Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0NCiNUT0M6OmJlZm9yZSB7DQogIGNvbnRlbnQ6ICJUYWJsZSBvZiBDb250ZW50cyI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXNpemU6IDEuMmVtOw0KICBkaXNwbGF5OiBibG9jazsNCiAgY29sb3I6IG5hdnk7DQogIG1hcmdpbi1ib3R0b206IDEwcHg7DQp9DQoNCg0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLw0KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLw0KICBmb250LXNpemU6IDIycHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQoNCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMTVweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8NCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsNCiAgY29udGVudDogIi4iOw0KDQpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQp9DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KICBsaWJyYXJ5KGdncGxvdDIpDQp9DQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQogIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQogIGxpYnJhcnkocGxvdGx5KQ0KfQ0KIyMjIw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BDQogICAgICAgICAgICAgICAgICAgICAgKSAgDQpgYGANCiANCiBcDQogDQojIyAqKkFzc2lnbm1lbnQgT2JqZWN0aXZlcyoqIA0KDQoqIERldmVsb3AgYSBjbGVhciB0ZWNobmljYWwgdW5kZXJzdGFuZGluZyBvZiBub25wYXJhbWV0cmljIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChDREYpIGVzdGltYXRpb24gYW5kIHZhcmlvdXMga2VybmVsIGRlbnNpdHkgZXN0aW1hdG9ycy4NCg0KKiBUcmFuc2xhdGUgbWF0aGVtYXRpY2FsIGZvcm11bGFzIGludG8gUiBmdW5jdGlvbnMgYW5kIGFwcGx5IHRoZW0gdG8gc29sdmUgcmVsYXRlZCBwcm9ibGVtcy4NCg0KKiBDcmVhdGUgZWZmZWN0aXZlIHZpc3VhbGl6YXRpb25zIHRvIGRlbW9uc3RyYXRlIHlvdXIgdW5kZXJzdGFuZGluZyBvZiBrZXkgY29uY2VwdHMgaW4gdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuDQoNCg0KDQpcDQoNCiMjICoqUXVlc3Rpb24gMTogQ3VtdWxhdGl2ZSBEaXN0cmlidXRpb24gRnVuY3Rpb24gKENERikgRXN0aW1hdGlvbioqDQoNClRoZSBmb2xsb3dpbmcgZmFpbHVyZSB0aW1lcyAoaW4gaG91cnMpIHdlcmUgb2JzZXJ2ZWQgZm9yIDggZWxlY3Ryb25pYyBjb21wb25lbnRzOg0KDQo8Y2VudGVyPiAyMywgNDUsIDY3LCA4OSwgMTEyLCAxNTYsIDE4OSwgMjQ1ICA8L2NlbnRlcj4NCg0KYSkgV3JpdGUgYW4gUiBmdW5jdGlvbiBpbXBsZW1lbnRpbmcgdGhlIEVDREYgJFxoYXR7Rn1fbih0KSQgYWNjb3JkaW5nIHRvIGl0cyBtYXRoZW1hdGljYWwgZGVmaW5pdGlvbi4gVmFsaWRhdGUgeW91ciBpbXBsZW1lbnRhdGlvbiB1c2luZyBSJ3MgZWNkZigpIGZ1bmN0aW9uIG9uIHRoZSBnaXZlbiBkYXRhLCB3aXRoIGNvbXBhcmlzb24gYmFzZWQgb24gdGhlaXIgc3RlcCBmdW5jdGlvbnMuDQoNCmBgYHtyfQ0KeCA8LSBjKDIzLCA0NSwgNjcsIDg5LCAxMTIsIDE1NiwgMTg5LCAyNDUpDQoNCiMgTXkgRUNERiANCm15X2VjZGYgPC0gZnVuY3Rpb24oZGF0YSkgew0KICBuIDwtIGxlbmd0aChkYXRhKQ0KICBmdW5jdGlvbih0KSB7DQogICAgc3VtKGRhdGEgPD0gdCkgLyBuDQogIH0NCn0NCm15X2VjZGYgPC0gbXlfZWNkZih4KQ0KYGBgDQoNCkkgd2lsbCB2YWxpZGF0ZSBteSBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgRUNERiB1c2luZyBSJ3MgZWNmKCkgZnVuY3Rpb24uIEZpcnN0LCBJIHdpbGwgZG8gc28gYnkgdXNpbmcgc2V2ZXJhbCBkaWZmZXJlbnQgdmFsdWVzIGFzIGlucHV0LCBhbmQgZW5zdXJpbmcgdGhhdCBJIGdldCB0aGUgc2FtZSByZXN1bHRzIGZyb20gYm90aCB3YXlzLg0KDQpgYGB7cn0NCiMgUidzIEVDREYgDQpSX2VjZGYgPC0gZWNkZih4KQ0KDQojIENvbXBhcmluZyBFQ0RGIHZhbHVlcyBiZXR3ZWVuIG15IGZ1bmN0aW9uIGFuZCBSJ3MgZnVuY3Rpb24NCnRfdmFscyA8LSBzZXEoMCwgMjYwLCBieSA9IDUwKQ0KY2JpbmQoDQogIHQgPSB0X3ZhbHMsDQogIG15X2VjZGYgPSBzYXBwbHkodF92YWxzLCBteV9lY2RmKSwNCiAgYnVpbHRpbiA9IFJfZWNkZih0X3ZhbHMpDQopDQoNCmBgYA0KVGhlIHZhbHVlcyBtYXRjaCB1cCBwZXJmZWN0bHkgYmV0d2VlbiBteSBFQ0RGIGFuZCB0aGUgYnVpbHQtaW4gUiBFQ0RGIGluZGljYXRpbmcgdGhhdCBteSBmdW5jdGlvbiBoYXMgYmVlbiBjcmVhdGVkIHByb3Blcmx5LiANCg0KDQpgYGB7cn0NCnBsb3QoUl9lY2RmLCB2ZXJ0aWNhbHMgPSBUUlVFLCBkby5wb2ludHMgPSBGQUxTRSwgY29sID0gImJsdWUiLCBsd2QgPSAyLA0KICAgIG1haW4gPSAiQ29tcGFyaXNvbiBvZiBNWSBFQ0RGIGFuZCBSJ3MgRUNERiIsIA0KICAgIHhsYWIgPSAiRmFpbHVyZSBUaW1lcyIsDQogICAgeWxhYiA9ICJFQ0RGIikNCg0KdF9ncmlkIDwtIHNlcSgwLCAyNjAsIGxlbmd0aC5vdXQgPSAxMDAwKQ0KDQpsaW5lcyh0X2dyaWQsIHNhcHBseSh0X2dyaWQsIG15X2VjZGYpLCB0eXBlID0gInMiLCBjb2wgPSAib3JhbmdlIiwgDQogICAgICBsd2QgPSAyLGx0eSA9IDIpDQoNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCBsZWdlbmQgPSBjKCJSIGVjZGYoKSIsICJNeSBFQ0RGIiksDQogICAgICAgIGNvbCA9IGMoImJsdWUiLCAib3JhbmdlIiksIGx0eSA9IGMoMSwgMiksIGx3ZCA9IDIsIGJ0eSA9ICJuIikNCmBgYA0KDQpBcyBzZWVuIGluIHRoZSBncmFwaCBhYm92ZSwgbXkgRUNERiBhbmQgdGhlIGJ1aWx0LWluIFIgRUNERiBtYXRjaCB1cCBwZXJmZWN0bHksIHRodXMgdmFsaWRhdGluZyBteSBmdW5jdGlvbi4NCg0KDQpiKSBBIGNvbGxlYWd1ZSBjbGFpbXMgdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZSBiZWZvcmUgMTAwIGhvdXJzIGlzIDAuNSBiYXNlZCBvbiB0aGVzZSBkYXRhLiBEbyB5b3UgYWdyZWU/IEV4cGxhaW4geW91ciByZWFzb25pbmcgdXNpbmcgdGhlIGVtcGlyaWNhbCBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiAoRUNERikuDQoNClllcywgSSBkbyBhZ3JlZSB3aXRoIHRoaXMgY29sbGVhZ3VlJ3MgY2xhaW0uIEluIHRoaXMgZGF0YSBzZXQsIHRoZXJlIGFyZSBmb3VyIHRvdGFsIHZhbHVlcyB0aGF0IGFyZSBsZXNzIHRoYW4gMTAwLCB0aGVzZSB2YWx1ZXMgYXJlIDIzLCA0NSwgNjcsIGFuZCA4OS4gVGhlcmUgYXJlIGVpZ2h0IHRvdGFsIHZhbHVlcyBhbGwgdG9nZXRoZXIgaW4gdGhlIGRhdGEgc2V0LiBUaGUgZW1waXJpY2FsIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIHNheXMgdGhhdCB0aGUgcHJvYmFiaWxpdHkgY2FuIGJlIGZvdW5kIGJ5IHRha2luZyB0aGUgdG90YWwgbnVtYmVyIG9mIHZhbHVlcyB0aGF0IGFyZSBsZXNzIHRoYW4gdGhlIGRlc2lyZWQgdmFsdWUsIGluIHRoaXMgY2FzZSAxMDAsIGFuZCBkaXZpZGluZyB0aGF0IGJ5IHRoZSB0b3RhbCBudW1iZXIgb2YgdmFsdWVzIGluIHRoZSB3aG9sZSBkYXRhIHNldC4gDQoNCiQkDQpGX24oeCkgPSBcZnJhY3tbXCBcdGV4dHtOdW1iZXIgb2YgIH0gWF9pIFxsZSB4XX17bn0gPSBcZnJhY3s0fXs4fSA9IDAuNQ0KJCQNCg0KVGhlIEVDREYgZ2l2ZXMgdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZSBiZWZvcmUgMTAwIGhvdXJzIGlzIDAuNSB3aGljaCBtYXRjaGVzIHVwIHdpdGggdGhpcyBjb2xsZWFndWUncyBjbGFpbS4gDQoNCg0KXA0KDQojIyAqKlF1ZXN0aW9uIDI6IERlbnNpdHkgRnVuY3Rpb24gRXN0aW1hdGlvbioqDQoNCkNvbnNpZGVyIHRoZSBmb2xsb3dpbmcgZmFpbHVyZSB0aW1lcyBmcm9tIGEgbWVjaGFuaWNhbCBzeXN0ZW06DQoNCjxjZW50ZXI+IDEyLjMsIDE0LjcsIDE1LjIsIDE2LjgsIDE4LjEsIDE5LjQsIDIwLjYsIDIyLjMsIDIzLjksIDI1LjQgPC9jZW50ZXI+DQoNCmEpIENyZWF0ZSBhIGhpc3RvZ3JhbSBvZiB0aGUgZGF0YSB1c2luZyAzIGVxdWFsbHkgc3BhY2VkIGJpbnMuIFdoYXQgaXMgdGhlIGVzdGltYXRlZCBkZW5zaXR5IGluIGVhY2ggYmluPyBEZXNjcmliZSB0aGUgc2hhcGUgb2YgdGhlIGhpc3RvZ3JhbSdzIGRpc3RyaWJ1dGlvbi4NCg0KDQpgYGB7cn0NCnkgPC0gYygxMi4zLCAxNC43LCAxNS4yLCAxNi44LCAxOC4xLCAxOS40LCAyMC42LCAyMi4zLCAyMy45LCAyNS40KQ0KYnJlYWtzIDwtIHNlcSgxMi4zLCAyNS40LCBsZW5ndGgub3V0ID0gNCkNCmhpc3QoeSwgYnJlYWtzID0gYnJlYWtzLCBwcm9iYWJpbGl0eSA9IFRSVUUsDQogICAgIG1haW4gPSAiSGlzdG9ncmFtIiwNCiAgICAgeGxhYiA9ICJGYWlsdXJlIFRpbWUiKQ0KYGBgDQoNClRoZSBoaXN0b2dyYW0gaXMgdW5pbW9kYWwgYW5kIHN5bW1ldHJpYywgYW5kIGFwcGVhcnMgdG8gYmUgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4gSW4gdGhlIGZpcnN0IGJpbiwgdGhlIGRlbnNpdHkgYXBwZWFycyB0byBiZSBhcm91bmQgMC4wNy4gSW4gdGhlIHNlY29uZCBiaW4sIHRoZSBkZW5zaXR5IGFwcGVhcnMgdG8gYmUgYXJvdW5kIDAuMDkuIEluIHRoZSB0aGlyZCBiaW4sIHRoZSBkZW5zaXR5IGFwcGVhcnMgdG8gYmUgYXJvdW5kIDAuMDcuDQoNCg0KYikgV3JpdGUgYW4gUiBmdW5jdGlvbiB0aGF0IGNvbXB1dGVzIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRlcyB1c2luZyBhIEdhdXNzaWFuIGtlcm5lbCB3aXRoICRoPTIkLiBWYWxpZGF0ZSB5b3VyIGltcGxlbWVudGF0aW9uIGFnYWluc3QgUidzIGJ1aWx0LWluIGRlbnNpdHkoKSBmdW5jdGlvbi4NCg0KJCQNClxoYXR7Zn1faCh0KSA9IFxmcmFjezF9e25ofVxzdW1fe2k9MX1ebiBLXGxlZnQoIFxmcmFje3QtdF9pfXtofVxyaWdodCksIFwgXCBcdGV4dHsgd2hlcmUgfSBcIFwgSyh1KSA9IFxmcmFjezF9e1xzcXJ0ezJccGl9fSBlXnstdV4yLzJ9Lg0KJCQNCg0KSSB3aWxsIGJlZ2luIHdpdGggY3JlYXRpbmcgbXkgZXN0aW1hdGlvbiBmb3IgYSBHYXVzc2lhbiBrZXJuZWwgd2l0aCBoPTIuDQoNCmBgYHtyfQ0KR2F1c3NpYW4gPC0gZnVuY3Rpb24odCwgZGF0YSwgaCkgew0KICBuIDwtIGxlbmd0aChkYXRhKQ0KICBzYXBwbHkodCwgZnVuY3Rpb24oeCkgew0KICAgIG1lYW4oZG5vcm0oKHggLSBkYXRhKSAvIGgpKSAvIGgNCiAgfSkNCn0NCmBgYA0KDQpOZXh0LCBJIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCBSJ3MgYnVpbHQtaW4gZGVuc2l0eSBmdW5jdGlvbi4NCg0KYGBge3J9DQp0X2dyaWQgPC0gc2VxKG1pbih5KSAtIDIsIG1heCh5KSArIDIsIGxlbmd0aC5vdXQgPSAyMDApDQoNCnBsb3QodF9ncmlkLCBHYXVzc2lhbih0X2dyaWQsIHksIGggPSAyKSwNCiAgICAgdHlwZSA9ICJsIiwgY29sID0gIm9yYW5nZSIsIGx3ZCA9IDIsDQogICAgIG1haW4gPSAiR2F1c3NpYW4gKGggPSAyKSIsDQogICAgIHhsYWIgPSAiRmFpbHVyZSBUaW1lIiwgeWxhYiA9ICJEZW5zaXR5IikNCg0KbGluZXMoZGVuc2l0eSh5LCBrZXJuZWwgPSAiZ2F1c3NpYW4iLCBidyA9IDIpLA0KICAgICAgY29sID0gImJsdWUiLCBsdHkgPSAyKQ0KDQpsZWdlbmQoInRvcHJpZ2h0IiwNCiAgICAgICBsZWdlbmQgPSBjKCJNeSBHYXVzc2lhbiIsICJSJ3MgQnVpbHQtaW4gZnVuY3Rpb24iKSwNCiAgICAgICBjb2wgPSBjKCJvcmFuZ2UiLCAiYmx1ZSIpLCBsdHkgPSBjKDEsIDIpKQ0KYGBgDQoNCkFzIHNlZW4gYWJvdmUsIG15IGVzdGltYXRpb24gdXNpbmcgYSBHYXVzc2lhbiBrZXJuZWwgd2l0aCBoPTIgbWF0Y2hlcyB1cCBwZXJmZWN0bHkgd2l0aCBS4oCZcyBidWlsdC1pbiBkZW5zaXR5KCkgZnVuY3Rpb24uIFRoaXMgc3VjY2Vzc2Z1bGx5IHZhbGlkYXRlcyB0aGUgZnVuY3Rpb24gdGhhdCBJIGNyZWF0ZWQuIA0KDQoNCmMpIFdyaXRlIGEgY3VzdG9tIFIgZnVuY3Rpb24gdGhhdCBjb21wdXRlcyBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0ZXMgdXNpbmcgdGhlIEVwYW5lY2huaWtvdiBrZXJuZWwgd2l0aCAkaD0yJC4gVmFsaWRhdGUgeW91ciBpbXBsZW1lbnRhdGlvbiBieSBjb21wYXJpbmcgcmVzdWx0cyB3aXRoIFIncyBidWlsdC1pbiBkZW5zaXR5KCkgZnVuY3Rpb24gZm9yIEdhdXNzaWFuIGtlcm5lbCBlc3RpbWF0aW9uLg0KDQokJA0KXGhhdHtmfV9oKHQpID0gXGZyYWN7MX17bmh9XHN1bV97aT0xfV5uIEtcbGVmdCggXGZyYWN7dC10X2l9e2h9XHJpZ2h0KSwgXCBcIFx0ZXh0eyB3aGVyZSB9IFwgXCBLKHUpID0gXGZyYWN7M317NH0oMSAtIHVeMikgXCBcIFx0ZXh0eyBmb3IgfSBcIFwgfHV8IFxsZSAxLg0KJCQNCg0KDQpJIHdpbGwgYmVnaW4gd2l0aCBjcmVhdGluZyBteSBlc3RpbWF0aW9uIGZvciBhIEVwYW5lY2huaWtvdiBrZXJuZWwgd2l0aCBoPTIuDQoNCmBgYHtyfQ0KRXBhbmVjaG5pa292ICA8LSBmdW5jdGlvbih0LCBkYXRhLCBoKSB7DQogIG4gPC0gbGVuZ3RoKGRhdGEpDQogIHNhcHBseSh0LCBmdW5jdGlvbih4KSB7DQogICAgdSA8LSAoeCAtIGRhdGEpIC8gaA0KICAgIG1lYW4oMC43NSAqICgxIC0gdV4yKSAqIChhYnModSkgPD0gMSkpIC8gaA0KICB9KQ0KfQ0KYGBgDQoNCk5leHQsIEkgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IFIncyBidWlsdC1pbiBkZW5zaXR5IGZ1bmN0aW9uLg0KDQpgYGB7cn0NCnBsb3QodF9ncmlkLCBFcGFuZWNobmlrb3YgKHRfZ3JpZCwgeSwgaCA9IDIpLA0KICAgICB0eXBlID0gImwiLCBjb2wgPSAib3JhbmdlIiwgbHdkID0gMiwNCiAgICAgbWFpbiA9ICJLZXJuZWwgRGVuc2l0eSBFc3RpbWF0ZXMiLA0KICAgICB4bGFiID0gIkZhaWx1cmUgVGltZSIsIHlsYWIgPSAiRGVuc2l0eSIpDQoNCmxpbmVzKGRlbnNpdHkoeSwgYncgPSAyKSwgY29sID0gImJsdWUiLCBsdHkgPSAyKQ0KDQpsZWdlbmQoInRvcHJpZ2h0IiwNCiAgICAgICBsZWdlbmQgPSBjKCJFcGFuZWNobmlrb3YgS0RFIiwgIkdhdXNzaWFuIEtERSIpLA0KICAgICAgIGNvbCA9IGMoIm9yYW5nZSIsICJibHVlIiksIGx0eSA9IGMoMSwgMikpDQoNCmBgYA0KDQpNeSBFcGFuZWNobmlrb3Yga2VybmVsIG1hdGNoZXMgdXAgd2l0aCB0aGUgc2FtZSBwYXR0ZXJucyBzaG93biBieSB0aGF0IG9mIFIncyBidWlsdC1pbiBmdW5jdGlvbidzIGVzdGltYXRpb24uIFRoaXMgc3VjY2Vzc2Z1bGx5IHZhbGlkYXRlcyBteSBFcGFuZWNobmlrb3Yga2VybmVsIGZ1bmN0aW9uLiBUaGUgRXBhbmVjaG5pa292IGtlcm5lbCBzaG93cyBtb3JlIHZhcmlhYmlsaXR5IGFuZCBzaGFycGVyIHBlYWtzIHRoYW4gdGhlIHNtb290aCBwYXR0ZXJuIG9mIHRoZSBHYXVzc2lhbiBrZXJuZWwuIEhvd2V2ZXIsIHRoZSBvdmVyYWxsIHRyZW5kcyBhcmUgdGhlIHNhbWUgYmV0d2VlbiB0aGUgdHdvLiANCg0KDQpkKSBIb3cgZG9lcyB0aGUgY2hvaWNlIG9mIGtlcm5lbCAoR2F1c3NpYW4gdnMuIEVwYW5lY2huaWtvdikgYWZmZWN0IHRoZSBkZW5zaXR5IGVzdGltYXRlPyBGb3IgYm90aCBrZXJuZWwgZXN0aW1hdG9ycyBhcHBsaWVkIHRvIHRoaXMgZGF0YXNldCwgd2hhdCBoYXBwZW5zIHdoZW4gd2Ugc2VsZWN0ICRoPTEuNSQgdmVyc3VzICRoPTIuNSQ/DQoNCkJvdGgga2VybmVscyBwcm92aWRlIHNpbWlsYXIgaW5mb3JtYXRpb24gcmVnYXJkaW5nIHRoaXMgZGF0YSBzZXQsIGhvd2V2ZXIsIHRoZWlyIGFwcGVhcmVuY2VzIHNob3cgc29tZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIG9uZSBhbm90aGVyLiBUaGUgRXBhbmVjaG5pa292IGtlcm5lbCBoYXMgYSBzaGFycGVyIHBlYWsgdGhhbiB0aGUgR2F1c3NpYW4ga2VybmVsLCB3aGljaCB3YXMgc2VlbiBpbiB0aGUgZ3JhcGhpY2FsbHkgY29tcGFyaXNvbnMgb2YgYm90aCBrZXJuZWxzLiBUaGUgR2F1c3NpYW4ga2VybmVsIGhhcyBhIG1vcmUgYnJvYWQgcmFuZ2UsIHdoaWxlIHRoZSBFcGFuZWNobmlrb3Yga2VybmVsIGlzIG1vcmUgY29tcGFjdCwgd2l0aCBhIHNoYXJwZXIgcGVhayBhcyBvcHBvc2VkIHRvIGEgZ3JhZHVhbCBjdXJ2ZSBsaWtlIHRoZSBHYXVzc2lhbiBrZXJuZWwuIA0KDQpBIGxvd2VyIGJhbmR3aWR0aCBsaWtlIGggPSAxLjUgd291bGQgaGF2ZSBtb3JlIHZhcmlhYmlsaXR5LCBhbmQgYSBsZXNzIHNtb290aCBlc3RpbWF0ZS4gT24gdGhlIG90aGVyIGhhbmQsIGEgaGlnaGVyIGJhbmR3aWR0aCBsaWtlIGggPSAyLjUgd291bGQgaGF2ZSBhIHNtb290aGVyIGVzdGltYXRlLCBidXQgbGVzcyBvZiBhIG5vdGljZWFibGUgcGVhayBpbiBpdHMgdmlzdWFsaXphdGlvbi4gVGhlIGJhbmR3aWR0aCB1c2VkIGluIHRoZSBwcmV2aW91cyBwYXJ0cyBiIGFuZCBjIG9mIGggPSAyIGlzIGEgZ29vZCBtaWRkbGUgZ3JvdW5kIGJldHdlZW4gdGhlc2UgdHdvIGJhbmR3aWR0aHMuDQoNCg==