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_f <- function(x){
n <- length(x)
function(t){
vapply(t, function(tt) sum(x <= tt) / n, numeric(1))
}
}
F_r <- ecdf(x)
F_mine <- my_ecdf_f(x)
t_grid <- seq(min(x) - 10, max(x) + 10, length.out = 1000)
plot_df <- data.frame(
t = t_grid,
R_ecdf = F_r(t_grid),
My_ecdf = F_mine(t_grid)
)
plot_df_long <- plot_df %>%
pivot_longer(
cols = c(R_ecdf, My_ecdf),
names_to = "Type",
values_to = "CDF"
)
Fn.plt <- ggplot(plot_df_long, aes(x = t, y = CDF, color = Type)) +
geom_step(linewidth = 1) +
scale_color_manual(values = c("R_ecdf" = "blue", "My_ecdf" = "red")) +
labs(
title = "Empirical CDF: My Implementation vs R ecdf()",
subtitle = paste("Sample size n =", length(x)),
x = "t",
y = "F̂(t)"
) +
theme(
plot.title = element_text(hjust = 0.5),
plot.margin = margin(t = 35, r = 20, b = 30, l = 30, unit = "pt")
)
ggplotly(Fn.plt)
The ECDF computed using my custom ECDF implementation closely matches
the estimate produced by R’s ecdf() function, indicating that the
implementation is correct.
- 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).
I agree with the claim because the ECDF evaluated at 100 hours is
0.5, meaning that about 50% of the observed failures occurred before 100
hours. Therefore, the ECDF supports this 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.
x <- c(12.3, 14.7, 15.2, 16.8, 18.1, 19.4, 20.6, 22.3, 23.9, 25.4)
h <- hist(x, breaks = seq(min(x), max(x), length.out = 4), freq = FALSE)

The estimated density of each bin in order is 0.0687023, 0.0916031,
0.0687023. The distribution is roughly symmetrical and unimodal.
- 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}.
\]
my_kde <- function(x,h){
n <- length(x)
function(t){
vapply(t, function(xi) 1/(n*h) * sum(dnorm((xi - x)/h)), numeric(1))
}
}
F_mine <- my_kde(x, h = 2)
F_r <- density(x, bw = 2)
t_grid <- F_r$x
plot_df <- data.frame(
t = t_grid,
R_density = F_r$y,
My_density = F_mine(t_grid)
)
plot_df_long <- plot_df %>%
pivot_longer(
cols = c(R_density, My_density),
names_to = "Type",
values_to = "Density"
)
kde_plt <- ggplot(plot_df_long, aes(x = t, y = Density, color = Type)) +
geom_line(linewidth = 1) +
labs(
title = "KDE: My Implementation vs R density()",
subtitle = paste("Gaussian kernel, h =", 2, ", n =", length(x)),
x = "t",
y = "Density"
) +
theme(plot.title = element_text(hjust = 0.5))
ggplotly(kde_plt)
The KDE computed using my custom Gaussian kernel implementation
closely matches the estimate produced by R’s density() function,
indicating that the implementation is correct.
- 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.
\]
my_kde <- function(x,h){
n <- length(x)
function(t){
vapply(t, function(tt) {
u <- (tt - x)/h
K <- ifelse(abs(u) <= 1, (3/4)*(1 - u^2), 0)
1/(n*h) * sum(K)}, numeric(1))
}
}
F_mine <- my_kde(x, h = 2)
F_r <- density(x, bw = 2, kernel = "epanechnikov")
t_grid <- F_r$x
plot_df <- data.frame(
t = t_grid,
R_density = F_r$y,
My_density = F_mine(t_grid)
)
plot_df_long <- plot_df %>%
pivot_longer(
cols = c(R_density, My_density),
names_to = "Type",
values_to = "Density"
)
kde_plt <- ggplot(plot_df_long, aes(x = t, y = Density, color = Type)) +
geom_line(linewidth = 1) +
labs(
title = "KDE: My Implementation vs R density()",
subtitle = paste("Gaussian kernel, h =", 2, ", n =", length(x)),
x = "t",
y = "Density"
) +
theme(plot.title = element_text(hjust = 0.5))
ggplotly(kde_plt)
The KDE computed using my custom Epanechnikov kernel implementation
closely matches the estimate produced by R’s density() function,
indicating that the implementation is correct. However, the two curves
don’t completely overlap this time, I’m assuming the density() function
must go above and beyond just the mathematical equation.
- 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\)?
The Guassian curve is much more smooth than the Epanechnikov curve.
Epanechnikov densities are allowed to be zero at the tails, this doesn’t
seem to be true for Gaussian densities. For both kernels, the density
curves become more rigid when h is decreased to 1.5 and more smooth when
its increased to 2.5.
LS0tCnRpdGxlOiAiQXNzaWdubWVudCAxOiBFc3RpbWF0aW5nIENERiBhbmQgUERGIgphdXRob3I6ICJDaGFybGllIE1vcmdhbiIKZGF0ZTogIiBEdWU6IDAyLzAyLzI2IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICB0b2NfZmxvYXQ6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgdG9jX2NvbGxhcHNlZDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgc21vb3RoX3Njcm9sbDogeWVzCiAgICB0aGVtZTogbHVtZW4KICBwZGZfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIGZpZ193aWR0aDogMwogICAgZmlnX2hlaWdodDogMwogIHdvcmRfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAga2VlcF9tZDogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge2NzcywgZWNobyA9IEZBTFNFfQojVE9DOjpiZWZvcmUgewogIGNvbnRlbnQ6ICJUYWJsZSBvZiBDb250ZW50cyI7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1zaXplOiAxLjJlbTsKICBkaXNwbGF5OiBibG9jazsKICBjb2xvcjogbmF2eTsKICBtYXJnaW4tYm90dG9tOiAxMHB4Owp9CgoKZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLwogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsKICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsKICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7CiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7Cn0KCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovCiAgZm9udC1zaXplOiAyMnB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7Cn0KCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxNXB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7CiAgY29sb3I6IG5hdnk7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwogIGNvbG9yOiBEYXJrQmx1ZTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNnB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9CgouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQoKcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCn0KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikKICAgbGlicmFyeShrbml0cikKfQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpCiAgIGxpYnJhcnkocGFuZGVyKQp9CmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCiAgbGlicmFyeShnZ3Bsb3QyKQp9CmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQogIGxpYnJhcnkodGlkeXZlcnNlKQp9CgppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikKICBsaWJyYXJ5KHBsb3RseSkKfQojIyMjCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIAogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLgogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BCiAgICAgICAgICAgICAgICAgICAgICApICAKYGBgCiAKIFwKIAojIyAqKkFzc2lnbm1lbnQgT2JqZWN0aXZlcyoqIAoKKiBEZXZlbG9wIGEgY2xlYXIgdGVjaG5pY2FsIHVuZGVyc3RhbmRpbmcgb2Ygbm9ucGFyYW1ldHJpYyBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiAoQ0RGKSBlc3RpbWF0aW9uIGFuZCB2YXJpb3VzIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRvcnMuCgoqIFRyYW5zbGF0ZSBtYXRoZW1hdGljYWwgZm9ybXVsYXMgaW50byBSIGZ1bmN0aW9ucyBhbmQgYXBwbHkgdGhlbSB0byBzb2x2ZSByZWxhdGVkIHByb2JsZW1zLgoKKiBDcmVhdGUgZWZmZWN0aXZlIHZpc3VhbGl6YXRpb25zIHRvIGRlbW9uc3RyYXRlIHlvdXIgdW5kZXJzdGFuZGluZyBvZiBrZXkgY29uY2VwdHMgaW4gdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuCgoKClwKCiMjICoqUXVlc3Rpb24gMTogQ3VtdWxhdGl2ZSBEaXN0cmlidXRpb24gRnVuY3Rpb24gKENERikgRXN0aW1hdGlvbioqCgpUaGUgZm9sbG93aW5nIGZhaWx1cmUgdGltZXMgKGluIGhvdXJzKSB3ZXJlIG9ic2VydmVkIGZvciA4IGVsZWN0cm9uaWMgY29tcG9uZW50czoKCjxjZW50ZXI+IDIzLCA0NSwgNjcsIDg5LCAxMTIsIDE1NiwgMTg5LCAyNDUgIDwvY2VudGVyPgoKYSkgV3JpdGUgYW4gUiBmdW5jdGlvbiBpbXBsZW1lbnRpbmcgdGhlIEVDREYgJFxoYXR7Rn1fbih0KSQgYWNjb3JkaW5nIHRvIGl0cyBtYXRoZW1hdGljYWwgZGVmaW5pdGlvbi4gVmFsaWRhdGUgeW91ciBpbXBsZW1lbnRhdGlvbiB1c2luZyBSJ3MgZWNkZigpIGZ1bmN0aW9uIG9uIHRoZSBnaXZlbiBkYXRhLCB3aXRoIGNvbXBhcmlzb24gYmFzZWQgb24gdGhlaXIgc3RlcCBmdW5jdGlvbnMuCgpgYGB7cn0KeCA8LSBjKDIzLCA0NSwgNjcsIDg5LCAxMTIsIDE1NiwgMTg5LCAyNDUpCgpteV9lY2RmX2YgPC0gZnVuY3Rpb24oeCl7CiAgbiA8LSBsZW5ndGgoeCkKICBmdW5jdGlvbih0KXsKICAgIHZhcHBseSh0LCBmdW5jdGlvbih0dCkgc3VtKHggPD0gdHQpIC8gbiwgbnVtZXJpYygxKSkKICB9Cn0KCkZfciA8LSBlY2RmKHgpCkZfbWluZSA8LSBteV9lY2RmX2YoeCkKCnRfZ3JpZCA8LSBzZXEobWluKHgpIC0gMTAsIG1heCh4KSArIDEwLCBsZW5ndGgub3V0ID0gMTAwMCkKCnBsb3RfZGYgPC0gZGF0YS5mcmFtZSgKICB0ID0gdF9ncmlkLAogIFJfZWNkZiA9IEZfcih0X2dyaWQpLAogIE15X2VjZGYgPSBGX21pbmUodF9ncmlkKQopCgpwbG90X2RmX2xvbmcgPC0gcGxvdF9kZiAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYyhSX2VjZGYsIE15X2VjZGYpLAogICAgbmFtZXNfdG8gPSAiVHlwZSIsCiAgICB2YWx1ZXNfdG8gPSAiQ0RGIgogICkKCkZuLnBsdCA8LSBnZ3Bsb3QocGxvdF9kZl9sb25nLCBhZXMoeCA9IHQsIHkgPSBDREYsIGNvbG9yID0gVHlwZSkpICsKICBnZW9tX3N0ZXAobGluZXdpZHRoID0gMSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJSX2VjZGYiID0gImJsdWUiLCAiTXlfZWNkZiIgPSAicmVkIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRW1waXJpY2FsIENERjogTXkgSW1wbGVtZW50YXRpb24gdnMgUiBlY2RmKCkiLAogICAgc3VidGl0bGUgPSBwYXN0ZSgiU2FtcGxlIHNpemUgbiA9IiwgbGVuZ3RoKHgpKSwKICAgIHggPSAidCIsCiAgICB5ID0gIkbMgih0KSIKICApICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDM1LCByID0gMjAsIGIgPSAzMCwgbCA9IDMwLCB1bml0ID0gInB0IikKICApCgpnZ3Bsb3RseShGbi5wbHQpCmBgYAoKVGhlIEVDREYgY29tcHV0ZWQgdXNpbmcgbXkgY3VzdG9tIEVDREYgaW1wbGVtZW50YXRpb24gY2xvc2VseSBtYXRjaGVzIHRoZSBlc3RpbWF0ZSBwcm9kdWNlZCBieSBS4oCZcyBlY2RmKCkgZnVuY3Rpb24sIGluZGljYXRpbmcgdGhhdCB0aGUgaW1wbGVtZW50YXRpb24gaXMgY29ycmVjdC4KCmIpIEEgY29sbGVhZ3VlIGNsYWltcyB0aGF0IHRoZSBwcm9iYWJpbGl0eSBvZiBmYWlsdXJlIGJlZm9yZSAxMDAgaG91cnMgaXMgMC41IGJhc2VkIG9uIHRoZXNlIGRhdGEuIERvIHlvdSBhZ3JlZT8gRXhwbGFpbiB5b3VyIHJlYXNvbmluZyB1c2luZyB0aGUgZW1waXJpY2FsIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChFQ0RGKS4KYGBge3IsIGluY2x1ZGU9RkFMU0V9CkZfcigxMDApCmBgYApJIGFncmVlIHdpdGggdGhlIGNsYWltIGJlY2F1c2UgdGhlIEVDREYgZXZhbHVhdGVkIGF0IDEwMCBob3VycyBpcyBgciBGX3IoMTAwKWAsIG1lYW5pbmcgdGhhdCBhYm91dCBgciBGX3IoMTAwKSoxMDBgJSBvZiB0aGUgb2JzZXJ2ZWQgZmFpbHVyZXMgb2NjdXJyZWQgYmVmb3JlIDEwMCBob3Vycy4gVGhlcmVmb3JlLCB0aGUgRUNERiBzdXBwb3J0cyB0aGlzIGNsYWltLgpcCgojIyAqKlF1ZXN0aW9uIDI6IERlbnNpdHkgRnVuY3Rpb24gRXN0aW1hdGlvbioqCgpDb25zaWRlciB0aGUgZm9sbG93aW5nIGZhaWx1cmUgdGltZXMgZnJvbSBhIG1lY2hhbmljYWwgc3lzdGVtOgoKPGNlbnRlcj4gMTIuMywgMTQuNywgMTUuMiwgMTYuOCwgMTguMSwgMTkuNCwgMjAuNiwgMjIuMywgMjMuOSwgMjUuNCA8L2NlbnRlcj4KCmEpIENyZWF0ZSBhIGhpc3RvZ3JhbSBvZiB0aGUgZGF0YSB1c2luZyAzIGVxdWFsbHkgc3BhY2VkIGJpbnMuIFdoYXQgaXMgdGhlIGVzdGltYXRlZCBkZW5zaXR5IGluIGVhY2ggYmluPyBEZXNjcmliZSB0aGUgc2hhcGUgb2YgdGhlIGhpc3RvZ3JhbSdzIGRpc3RyaWJ1dGlvbi4KYGBge3J9CnggPC0gYygxMi4zLCAxNC43LCAxNS4yLCAxNi44LCAxOC4xLCAxOS40LCAyMC42LCAyMi4zLCAyMy45LCAyNS40KQpoIDwtIGhpc3QoeCwgYnJlYWtzID0gc2VxKG1pbih4KSwgbWF4KHgpLCBsZW5ndGgub3V0ID0gNCksIGZyZXEgPSBGQUxTRSkKYGBgCgpUaGUgZXN0aW1hdGVkIGRlbnNpdHkgb2YgZWFjaCBiaW4gaW4gb3JkZXIgaXMgYHIgaCRkZW5zaXR5YC4gVGhlIGRpc3RyaWJ1dGlvbiBpcyByb3VnaGx5IHN5bW1ldHJpY2FsIGFuZCB1bmltb2RhbC4KCmIpIFdyaXRlIGFuIFIgZnVuY3Rpb24gdGhhdCBjb21wdXRlcyBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0ZXMgdXNpbmcgYSBHYXVzc2lhbiBrZXJuZWwgd2l0aCAkaD0yJC4gVmFsaWRhdGUgeW91ciBpbXBsZW1lbnRhdGlvbiBhZ2FpbnN0IFIncyBidWlsdC1pbiBkZW5zaXR5KCkgZnVuY3Rpb24uCgokJApcaGF0e2Z9X2godCkgPSBcZnJhY3sxfXtuaH1cc3VtX3tpPTF9Xm4gS1xsZWZ0KCBcZnJhY3t0LXRfaX17aH1ccmlnaHQpLCBcIFwgXHRleHR7IHdoZXJlIH0gXCBcIEsodSkgPSBcZnJhY3sxfXtcc3FydHsyXHBpfX0gZV57LXVeMi8yfS4KJCQKYGBge3J9Cm15X2tkZSA8LSBmdW5jdGlvbih4LGgpewogIG4gPC0gbGVuZ3RoKHgpCiAgZnVuY3Rpb24odCl7CiAgICB2YXBwbHkodCwgZnVuY3Rpb24oeGkpIDEvKG4qaCkgKiBzdW0oZG5vcm0oKHhpIC0geCkvaCkpLCBudW1lcmljKDEpKQogIH0KfQoKRl9taW5lIDwtIG15X2tkZSh4LCBoID0gMikKRl9yIDwtIGRlbnNpdHkoeCwgYncgPSAyKQoKdF9ncmlkIDwtIEZfciR4CgpwbG90X2RmIDwtIGRhdGEuZnJhbWUoCiAgdCA9IHRfZ3JpZCwKICBSX2RlbnNpdHkgPSBGX3IkeSwKICBNeV9kZW5zaXR5ID0gRl9taW5lKHRfZ3JpZCkKKQoKcGxvdF9kZl9sb25nIDwtIHBsb3RfZGYgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IGMoUl9kZW5zaXR5LCBNeV9kZW5zaXR5KSwKICAgIG5hbWVzX3RvID0gIlR5cGUiLAogICAgdmFsdWVzX3RvID0gIkRlbnNpdHkiCiAgKQoKa2RlX3BsdCA8LSBnZ3Bsb3QocGxvdF9kZl9sb25nLCBhZXMoeCA9IHQsIHkgPSBEZW5zaXR5LCBjb2xvciA9IFR5cGUpKSArCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEpICsKICBsYWJzKAogICAgdGl0bGUgPSAiS0RFOiBNeSBJbXBsZW1lbnRhdGlvbiB2cyBSIGRlbnNpdHkoKSIsCiAgICBzdWJ0aXRsZSA9IHBhc3RlKCJHYXVzc2lhbiBrZXJuZWwsIGggPSIsIDIsICIsIG4gPSIsIGxlbmd0aCh4KSksCiAgICB4ID0gInQiLAogICAgeSA9ICJEZW5zaXR5IgogICkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKZ2dwbG90bHkoa2RlX3BsdCkKYGBgCgpUaGUgS0RFIGNvbXB1dGVkIHVzaW5nIG15IGN1c3RvbSBHYXVzc2lhbiBrZXJuZWwgaW1wbGVtZW50YXRpb24gY2xvc2VseSBtYXRjaGVzIHRoZSBlc3RpbWF0ZSBwcm9kdWNlZCBieSBS4oCZcyBkZW5zaXR5KCkgZnVuY3Rpb24sIGluZGljYXRpbmcgdGhhdCB0aGUgaW1wbGVtZW50YXRpb24gaXMgY29ycmVjdC4KCmMpIFdyaXRlIGEgY3VzdG9tIFIgZnVuY3Rpb24gdGhhdCBjb21wdXRlcyBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0ZXMgdXNpbmcgdGhlIEVwYW5lY2huaWtvdiBrZXJuZWwgd2l0aCAkaD0yJC4gVmFsaWRhdGUgeW91ciBpbXBsZW1lbnRhdGlvbiBieSBjb21wYXJpbmcgcmVzdWx0cyB3aXRoIFIncyBidWlsdC1pbiBkZW5zaXR5KCkgZnVuY3Rpb24gZm9yIEdhdXNzaWFuIGtlcm5lbCBlc3RpbWF0aW9uLgoKJCQKXGhhdHtmfV9oKHQpID0gXGZyYWN7MX17bmh9XHN1bV97aT0xfV5uIEtcbGVmdCggXGZyYWN7dC10X2l9e2h9XHJpZ2h0KSwgXCBcIFx0ZXh0eyB3aGVyZSB9IFwgXCBLKHUpID0gXGZyYWN7M317NH0oMSAtIHVeMikgXCBcIFx0ZXh0eyBmb3IgfSBcIFwgfHV8IFxsZSAxLgokJAoKYGBge3J9Cm15X2tkZSA8LSBmdW5jdGlvbih4LGgpewogIG4gPC0gbGVuZ3RoKHgpCiAgZnVuY3Rpb24odCl7CiAgICB2YXBwbHkodCwgZnVuY3Rpb24odHQpIHsKICAgICAgdSA8LSAodHQgLSB4KS9oCiAgICAgIEsgPC0gaWZlbHNlKGFicyh1KSA8PSAxLCAoMy80KSooMSAtIHVeMiksIDApCiAgICAgIDEvKG4qaCkgKiBzdW0oSyl9LCBudW1lcmljKDEpKQogIH0KfQoKRl9taW5lIDwtIG15X2tkZSh4LCBoID0gMikKRl9yIDwtIGRlbnNpdHkoeCwgYncgPSAyLCBrZXJuZWwgPSAiZXBhbmVjaG5pa292IikKCnRfZ3JpZCA8LSBGX3IkeAoKcGxvdF9kZiA8LSBkYXRhLmZyYW1lKAogIHQgPSB0X2dyaWQsCiAgUl9kZW5zaXR5ID0gRl9yJHksCiAgTXlfZGVuc2l0eSA9IEZfbWluZSh0X2dyaWQpCikKCnBsb3RfZGZfbG9uZyA8LSBwbG90X2RmICU+JQogIHBpdm90X2xvbmdlcigKICAgIGNvbHMgPSBjKFJfZGVuc2l0eSwgTXlfZGVuc2l0eSksCiAgICBuYW1lc190byA9ICJUeXBlIiwKICAgIHZhbHVlc190byA9ICJEZW5zaXR5IgogICkKCmtkZV9wbHQgPC0gZ2dwbG90KHBsb3RfZGZfbG9uZywgYWVzKHggPSB0LCB5ID0gRGVuc2l0eSwgY29sb3IgPSBUeXBlKSkgKwogIGdlb21fbGluZShsaW5ld2lkdGggPSAxKSArCiAgbGFicygKICAgIHRpdGxlID0gIktERTogTXkgSW1wbGVtZW50YXRpb24gdnMgUiBkZW5zaXR5KCkiLAogICAgc3VidGl0bGUgPSBwYXN0ZSgiR2F1c3NpYW4ga2VybmVsLCBoID0iLCAyLCAiLCBuID0iLCBsZW5ndGgoeCkpLAogICAgeCA9ICJ0IiwKICAgIHkgPSAiRGVuc2l0eSIKICApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCmdncGxvdGx5KGtkZV9wbHQpCmBgYAoKVGhlIEtERSBjb21wdXRlZCB1c2luZyBteSBjdXN0b20gRXBhbmVjaG5pa292IGtlcm5lbCBpbXBsZW1lbnRhdGlvbiBjbG9zZWx5IG1hdGNoZXMgdGhlIGVzdGltYXRlIHByb2R1Y2VkIGJ5IFLigJlzIGRlbnNpdHkoKSBmdW5jdGlvbiwgaW5kaWNhdGluZyB0aGF0IHRoZSBpbXBsZW1lbnRhdGlvbiBpcyBjb3JyZWN0LiBIb3dldmVyLCB0aGUgdHdvIGN1cnZlcyBkb24ndCBjb21wbGV0ZWx5IG92ZXJsYXAgdGhpcyB0aW1lLCBJJ20gYXNzdW1pbmcgdGhlIGRlbnNpdHkoKSBmdW5jdGlvbiBtdXN0IGdvIGFib3ZlIGFuZCBiZXlvbmQganVzdCB0aGUgbWF0aGVtYXRpY2FsIGVxdWF0aW9uLgoKZCkgSG93IGRvZXMgdGhlIGNob2ljZSBvZiBrZXJuZWwgKEdhdXNzaWFuIHZzLiBFcGFuZWNobmlrb3YpIGFmZmVjdCB0aGUgZGVuc2l0eSBlc3RpbWF0ZT8gRm9yIGJvdGgga2VybmVsIGVzdGltYXRvcnMgYXBwbGllZCB0byB0aGlzIGRhdGFzZXQsIHdoYXQgaGFwcGVucyB3aGVuIHdlIHNlbGVjdCAkaD0xLjUkIHZlcnN1cyAkaD0yLjUkPwoKVGhlIEd1YXNzaWFuIGN1cnZlIGlzIG11Y2ggbW9yZSBzbW9vdGggdGhhbiB0aGUgRXBhbmVjaG5pa292IGN1cnZlLiBFcGFuZWNobmlrb3YgZGVuc2l0aWVzIGFyZSBhbGxvd2VkIHRvIGJlIHplcm8gYXQgdGhlIHRhaWxzLCB0aGlzIGRvZXNuJ3Qgc2VlbSB0byBiZSB0cnVlIGZvciBHYXVzc2lhbiBkZW5zaXRpZXMuIEZvciBib3RoIGtlcm5lbHMsIHRoZSBkZW5zaXR5IGN1cnZlcyBiZWNvbWUgbW9yZSByaWdpZCB3aGVuIGggaXMgZGVjcmVhc2VkIHRvIDEuNSBhbmQgbW9yZSBzbW9vdGggd2hlbiBpdHMgaW5jcmVhc2VkIHRvIDIuNS4KCgoKCg==