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
  1. 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)
x
[1]  23  45  67  89 112 156 189 245
# ECDF based on the definition: proportion of failures by time t
Fn_hat <- function(x, t){
  n <- length(x)            # total number of observations
  sum(x <= t) / n           # fraction of failures that occur by time t
}

# R's built-in ECDF for comparison
Fn_builtin <- ecdf(x)

# Values of t used to draw the step functions
tgrid <- seq(min(x) - 10, max(x) + 10, by = 1)

# Plot the ECDF from my function
plot(tgrid, sapply(tgrid, function(tt) Fn_hat(x, tt)),
     type = "s", lwd = 2, col = "black",
     xlab = "t", ylab = expression(hat(F)[n](t)),
     main = "ECDF: Custom vs R ecdf()")

# Add R's ECDF to check that the two match
lines(tgrid, Fn_builtin(tgrid),
      type = "s", lty = 2, col = "blue", lwd = 2)

# Legend to identify each ECDF
legend("bottomright",
       c("Custom ECDF", "R ecdf()"),
       lty = c(1, 2),
       col = c("black", "blue"),
       lwd = 2)

  1. 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).
# ECDF at t = 100 using the definition
sum(x <= 100) / length(x)
[1] 0.5
# Check the same value using R's ECDF
Fn_builtin(100)
[1] 0.5

Using the ECDF, the probability of failure before 100 hours is found by looking at the proportion of observed failure times that occur by 100 hours. The failure times in this data set show 4 out of 8 occurrences before reaching 100 hours which results in an ECDF value of 0.5. The evidence confirms what the colleague has stated.


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
  1. 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)
y
 [1] 12.3 14.7 15.2 16.8 18.1 19.4 20.6 22.3 23.9 25.4
# Define break points to create 3 equally spaced bins across the data range
breaks <- seq(min(y), max(y), length.out = 4)

# Plot the histogram on the density scale
hist_y <- hist(y, breaks = breaks, probability = TRUE,
               main = "Histogram with 3 Equally Spaced Bins",
               xlab = "Failure Time")

# Compute bin width for density calculation
bin_width <- breaks[2] - breaks[1]

# Calculate the estimated density in each bin
density_per_bin <- hist_y$counts / (length(y) * bin_width)
density_per_bin
[1] 0.06870229 0.09160305 0.06870229

The estimated densities for the three equally spaced bins are approximately 0.0687 for the first bin, which covers failure times from 12.3 to 16.7 hours, 0.0916 for the middle bin, which spans 16.7 to 21.0 hours, and 0.0687 for the final bin, covering 21.0 to 25.4 hours. The histogram shows a unimodal distribution with the highest density occurring in the middle bin, indicating that most failures tend to occur around the center of the observed time range.

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

# Gaussian kernel density estimator based on the given formula
kde_gaussian <- function(y, t, h = 2){
  n <- length(y)
  u <- outer(t, y, "-") / h           # scaled distances for the kernel
  rowSums(dnorm(u)) / (n * h)         # average contribution across observations
}

# Grid of values to evaluate the density smoothly
tgrid <- seq(min(y) - 6, max(y) + 6, length.out = 200)

# Density estimate from the custom KDE with h = 2
f_hat <- kde_gaussian(y, tgrid, h = 2)

# R's built-in density estimate using the same bandwidth
f_r <- density(y, bw = 2, kernel = "gaussian",
               from = min(tgrid), to = max(tgrid), n = length(tgrid))

# Plot both estimates to compare results
plot(tgrid, f_hat, type = "l", lwd = 2,
     xlab = "Failure Time", ylab = "Estimated Density",
     main = "Gaussian KDE (h = 2): Custom vs R density()")
lines(f_r$x, f_r$y, lty = 2, lwd = 2)

legend("topright", c("Custom KDE", "R density()"),
       lty = c(1, 2), lwd = 2)

# Numerical check to confirm agreement
max(abs(f_hat - f_r$y))
[1] 5.430381e-06
  1. 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. \]

# Epanechnikov KDE from the formula in the prompt (use h = 2)
kde_epan <- function(y, t, h = 2){
  n <- length(y)
  u <- outer(t, y, "-") / h                 # scale distances by h
  K <- 0.75 * (1 - u^2) * (abs(u) <= 1)     # Epanechnikov weights
  rowSums(K) / (n * h)                      # average and rescale
}

# Grid to evaluate the density curve
tgrid <- seq(min(y) - 6, max(y) + 6, length.out = 200)

# Custom Epanechnikov KDE with h = 2
f_epan <- kde_epan(y, tgrid, h = 2)

# R's Gaussian KDE with the same bandwidth for comparison
f_gauss_r <- density(y, bw = 2, kernel = "gaussian",
                     from = min(tgrid), to = max(tgrid), n = length(tgrid))

# Compare kernel choice at the same h
plot(tgrid, f_epan, type = "l", lwd = 2,
     xlab = "Failure Time", ylab = "Estimated Density",
     main = "KDE (h = 2): Epanechnikov vs Gaussian")
lines(f_gauss_r$x, f_gauss_r$y, lty = 2, lwd = 2)

legend("topright", c("Epanechnikov KDE", "R Gaussian KDE"),
       lty = c(1, 2), lwd = 2)

The Epanechnikov kernel density estimate is slightly more peaked in the center because it uses a fixed range around each data point. The Gaussian kernel distributes its weight across all observations which results in a continuous curve that spans the entire range. Given the limited range of the data, the Epanechnikov kernel places more emphasis on the central failure times, while the Gaussian kernel spreads influence more evenly.

  1. 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 Gaussian kernel gives weight to all observations and produces a smoother density estimate, while the Epanechnikov kernel uses a fixed range and results in a slightly more peaked estimate near the center of the data. For both kernels, using a smaller bandwidth (h = 1.5) creates a more detailed and variable density, whereas a larger bandwidth (h = 2.5) smooths the estimate and reduces variability but may hide finer features of the distribution.

LS0tCnRpdGxlOiAiQXNzaWdubWVudCAxOiBFc3RpbWF0aW5nIENERiBhbmQgUERGIgphdXRob3I6ICJLYXlsYSBEeWVyIgpkYXRlOiAiIER1ZToxLzMvMjYgYnV0IGFwcHJvdmVkIGZvciBsYXRlciBkdWUgZGF0ZS4iCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHBkZl9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgZmlnX3dpZHRoOiAzCiAgICBmaWdfaGVpZ2h0OiAzCiAgd29yZF9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBrZWVwX21kOiB5ZXMKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CiNUT0M6OmJlZm9yZSB7CiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LXNpemU6IDEuMmVtOwogIGRpc3BsYXk6IGJsb2NrOwogIGNvbG9yOiBuYXZ5OwogIG1hcmdpbi1ib3R0b206IDEwcHg7Cn0KCgpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOwogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOwogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsKICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsKfQoKaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8KICBmb250LXNpemU6IDIycHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsKfQoKaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE1cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogbmF2eTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE2cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLwouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7CiAgY29udGVudDogIi4iOwoKYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9CgpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQoKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLgppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQogICBsaWJyYXJ5KGtuaXRyKQp9CmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikKICAgbGlicmFyeShwYW5kZXIpCn0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKICBsaWJyYXJ5KGdncGxvdDIpCn0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgewogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpCiAgbGlicmFyeSh0aWR5dmVyc2UpCn0KCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQogIGxpYnJhcnkocGxvdGx5KQp9CiMjIyMKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUKICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEKICAgICAgICAgICAgICAgICAgICAgICkgIApgYGAKIAogXAogCiMjICoqQXNzaWdubWVudCBPYmplY3RpdmVzKiogCgoqIERldmVsb3AgYSBjbGVhciB0ZWNobmljYWwgdW5kZXJzdGFuZGluZyBvZiBub25wYXJhbWV0cmljIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChDREYpIGVzdGltYXRpb24gYW5kIHZhcmlvdXMga2VybmVsIGRlbnNpdHkgZXN0aW1hdG9ycy4KCiogVHJhbnNsYXRlIG1hdGhlbWF0aWNhbCBmb3JtdWxhcyBpbnRvIFIgZnVuY3Rpb25zIGFuZCBhcHBseSB0aGVtIHRvIHNvbHZlIHJlbGF0ZWQgcHJvYmxlbXMuCgoqIENyZWF0ZSBlZmZlY3RpdmUgdmlzdWFsaXphdGlvbnMgdG8gZGVtb25zdHJhdGUgeW91ciB1bmRlcnN0YW5kaW5nIG9mIGtleSBjb25jZXB0cyBpbiB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucy4KCgoKXAoKIyMgKipRdWVzdGlvbiAxOiBDdW11bGF0aXZlIERpc3RyaWJ1dGlvbiBGdW5jdGlvbiAoQ0RGKSBFc3RpbWF0aW9uKioKClRoZSBmb2xsb3dpbmcgZmFpbHVyZSB0aW1lcyAoaW4gaG91cnMpIHdlcmUgb2JzZXJ2ZWQgZm9yIDggZWxlY3Ryb25pYyBjb21wb25lbnRzOgoKPGNlbnRlcj4gMjMsIDQ1LCA2NywgODksIDExMiwgMTU2LCAxODksIDI0NSAgPC9jZW50ZXI+CgphKSBXcml0ZSBhbiBSIGZ1bmN0aW9uIGltcGxlbWVudGluZyB0aGUgRUNERiAkXGhhdHtGfV9uKHQpJCBhY2NvcmRpbmcgdG8gaXRzIG1hdGhlbWF0aWNhbCBkZWZpbml0aW9uLiBWYWxpZGF0ZSB5b3VyIGltcGxlbWVudGF0aW9uIHVzaW5nIFIncyBlY2RmKCkgZnVuY3Rpb24gb24gdGhlIGdpdmVuIGRhdGEsIHdpdGggY29tcGFyaXNvbiBiYXNlZCBvbiB0aGVpciBzdGVwIGZ1bmN0aW9ucy4KCmBgYHtyfQp4IDwtIGMoMjMsIDQ1LCA2NywgODksIDExMiwgMTU2LCAxODksIDI0NSkKeApgYGAKYGBge3J9CiMgRUNERiBiYXNlZCBvbiB0aGUgZGVmaW5pdGlvbjogcHJvcG9ydGlvbiBvZiBmYWlsdXJlcyBieSB0aW1lIHQKRm5faGF0IDwtIGZ1bmN0aW9uKHgsIHQpewogIG4gPC0gbGVuZ3RoKHgpICAgICAgICAgICAgIyB0b3RhbCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zCiAgc3VtKHggPD0gdCkgLyBuICAgICAgICAgICAjIGZyYWN0aW9uIG9mIGZhaWx1cmVzIHRoYXQgb2NjdXIgYnkgdGltZSB0Cn0KCiMgUidzIGJ1aWx0LWluIEVDREYgZm9yIGNvbXBhcmlzb24KRm5fYnVpbHRpbiA8LSBlY2RmKHgpCgojIFZhbHVlcyBvZiB0IHVzZWQgdG8gZHJhdyB0aGUgc3RlcCBmdW5jdGlvbnMKdGdyaWQgPC0gc2VxKG1pbih4KSAtIDEwLCBtYXgoeCkgKyAxMCwgYnkgPSAxKQoKIyBQbG90IHRoZSBFQ0RGIGZyb20gbXkgZnVuY3Rpb24KcGxvdCh0Z3JpZCwgc2FwcGx5KHRncmlkLCBmdW5jdGlvbih0dCkgRm5faGF0KHgsIHR0KSksCiAgICAgdHlwZSA9ICJzIiwgbHdkID0gMiwgY29sID0gImJsYWNrIiwKICAgICB4bGFiID0gInQiLCB5bGFiID0gZXhwcmVzc2lvbihoYXQoRilbbl0odCkpLAogICAgIG1haW4gPSAiRUNERjogQ3VzdG9tIHZzIFIgZWNkZigpIikKCiMgQWRkIFIncyBFQ0RGIHRvIGNoZWNrIHRoYXQgdGhlIHR3byBtYXRjaApsaW5lcyh0Z3JpZCwgRm5fYnVpbHRpbih0Z3JpZCksCiAgICAgIHR5cGUgPSAicyIsIGx0eSA9IDIsIGNvbCA9ICJibHVlIiwgbHdkID0gMikKCiMgTGVnZW5kIHRvIGlkZW50aWZ5IGVhY2ggRUNERgpsZWdlbmQoImJvdHRvbXJpZ2h0IiwKICAgICAgIGMoIkN1c3RvbSBFQ0RGIiwgIlIgZWNkZigpIiksCiAgICAgICBsdHkgPSBjKDEsIDIpLAogICAgICAgY29sID0gYygiYmxhY2siLCAiYmx1ZSIpLAogICAgICAgbHdkID0gMikKYGBgCgpiKSBBIGNvbGxlYWd1ZSBjbGFpbXMgdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZSBiZWZvcmUgMTAwIGhvdXJzIGlzIDAuNSBiYXNlZCBvbiB0aGVzZSBkYXRhLiBEbyB5b3UgYWdyZWU/IEV4cGxhaW4geW91ciByZWFzb25pbmcgdXNpbmcgdGhlIGVtcGlyaWNhbCBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiAoRUNERikuCgpgYGB7cn0KIyBFQ0RGIGF0IHQgPSAxMDAgdXNpbmcgdGhlIGRlZmluaXRpb24Kc3VtKHggPD0gMTAwKSAvIGxlbmd0aCh4KQoKIyBDaGVjayB0aGUgc2FtZSB2YWx1ZSB1c2luZyBSJ3MgRUNERgpGbl9idWlsdGluKDEwMCkKYGBgClVzaW5nIHRoZSBFQ0RGLCB0aGUgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZSBiZWZvcmUgMTAwIGhvdXJzIGlzIGZvdW5kIGJ5IGxvb2tpbmcgYXQgdGhlIHByb3BvcnRpb24gb2Ygb2JzZXJ2ZWQgZmFpbHVyZSB0aW1lcyB0aGF0IG9jY3VyIGJ5IDEwMCBob3Vycy4gVGhlIGZhaWx1cmUgdGltZXMgaW4gdGhpcyBkYXRhIHNldCBzaG93IDQgb3V0IG9mIDggb2NjdXJyZW5jZXMgYmVmb3JlIHJlYWNoaW5nIDEwMCBob3VycyB3aGljaCByZXN1bHRzIGluIGFuIEVDREYgdmFsdWUgb2YgMC41LiBUaGUgZXZpZGVuY2UgY29uZmlybXMgd2hhdCB0aGUgY29sbGVhZ3VlIGhhcyBzdGF0ZWQuCgpcCgojIyAqKlF1ZXN0aW9uIDI6IERlbnNpdHkgRnVuY3Rpb24gRXN0aW1hdGlvbioqCgpDb25zaWRlciB0aGUgZm9sbG93aW5nIGZhaWx1cmUgdGltZXMgZnJvbSBhIG1lY2hhbmljYWwgc3lzdGVtOgoKPGNlbnRlcj4gMTIuMywgMTQuNywgMTUuMiwgMTYuOCwgMTguMSwgMTkuNCwgMjAuNiwgMjIuMywgMjMuOSwgMjUuNCA8L2NlbnRlcj4KCmEpIENyZWF0ZSBhIGhpc3RvZ3JhbSBvZiB0aGUgZGF0YSB1c2luZyAzIGVxdWFsbHkgc3BhY2VkIGJpbnMuIFdoYXQgaXMgdGhlIGVzdGltYXRlZCBkZW5zaXR5IGluIGVhY2ggYmluPyBEZXNjcmliZSB0aGUgc2hhcGUgb2YgdGhlIGhpc3RvZ3JhbSdzIGRpc3RyaWJ1dGlvbi4KCmBgYHtyfQp5IDwtIGMoMTIuMywgMTQuNywgMTUuMiwgMTYuOCwgMTguMSwgMTkuNCwgMjAuNiwgMjIuMywgMjMuOSwgMjUuNCkKeQoKIyBEZWZpbmUgYnJlYWsgcG9pbnRzIHRvIGNyZWF0ZSAzIGVxdWFsbHkgc3BhY2VkIGJpbnMgYWNyb3NzIHRoZSBkYXRhIHJhbmdlCmJyZWFrcyA8LSBzZXEobWluKHkpLCBtYXgoeSksIGxlbmd0aC5vdXQgPSA0KQoKIyBQbG90IHRoZSBoaXN0b2dyYW0gb24gdGhlIGRlbnNpdHkgc2NhbGUKaGlzdF95IDwtIGhpc3QoeSwgYnJlYWtzID0gYnJlYWtzLCBwcm9iYWJpbGl0eSA9IFRSVUUsCiAgICAgICAgICAgICAgIG1haW4gPSAiSGlzdG9ncmFtIHdpdGggMyBFcXVhbGx5IFNwYWNlZCBCaW5zIiwKICAgICAgICAgICAgICAgeGxhYiA9ICJGYWlsdXJlIFRpbWUiKQoKIyBDb21wdXRlIGJpbiB3aWR0aCBmb3IgZGVuc2l0eSBjYWxjdWxhdGlvbgpiaW5fd2lkdGggPC0gYnJlYWtzWzJdIC0gYnJlYWtzWzFdCgojIENhbGN1bGF0ZSB0aGUgZXN0aW1hdGVkIGRlbnNpdHkgaW4gZWFjaCBiaW4KZGVuc2l0eV9wZXJfYmluIDwtIGhpc3RfeSRjb3VudHMgLyAobGVuZ3RoKHkpICogYmluX3dpZHRoKQpkZW5zaXR5X3Blcl9iaW4KYGBgClRoZSBlc3RpbWF0ZWQgZGVuc2l0aWVzIGZvciB0aGUgdGhyZWUgZXF1YWxseSBzcGFjZWQgYmlucyBhcmUgYXBwcm94aW1hdGVseSAwLjA2ODcgZm9yIHRoZSBmaXJzdCBiaW4sIHdoaWNoIGNvdmVycyBmYWlsdXJlIHRpbWVzIGZyb20gMTIuMyB0byAxNi43IGhvdXJzLCAwLjA5MTYgZm9yIHRoZSBtaWRkbGUgYmluLCB3aGljaCBzcGFucyAxNi43IHRvIDIxLjAgaG91cnMsIGFuZCAwLjA2ODcgZm9yIHRoZSBmaW5hbCBiaW4sIGNvdmVyaW5nIDIxLjAgdG8gMjUuNCBob3Vycy4gVGhlIGhpc3RvZ3JhbSBzaG93cyBhIHVuaW1vZGFsIGRpc3RyaWJ1dGlvbiB3aXRoIHRoZSBoaWdoZXN0IGRlbnNpdHkgb2NjdXJyaW5nIGluIHRoZSBtaWRkbGUgYmluLCBpbmRpY2F0aW5nIHRoYXQgbW9zdCBmYWlsdXJlcyB0ZW5kIHRvIG9jY3VyIGFyb3VuZCB0aGUgY2VudGVyIG9mIHRoZSBvYnNlcnZlZCB0aW1lIHJhbmdlLgoKYikgV3JpdGUgYW4gUiBmdW5jdGlvbiB0aGF0IGNvbXB1dGVzIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRlcyB1c2luZyBhIEdhdXNzaWFuIGtlcm5lbCB3aXRoICRoPTIkLiBWYWxpZGF0ZSB5b3VyIGltcGxlbWVudGF0aW9uIGFnYWluc3QgUidzIGJ1aWx0LWluIGRlbnNpdHkoKSBmdW5jdGlvbi4KCiQkClxoYXR7Zn1faCh0KSA9IFxmcmFjezF9e25ofVxzdW1fe2k9MX1ebiBLXGxlZnQoIFxmcmFje3QtdF9pfXtofVxyaWdodCksIFwgXCBcdGV4dHsgd2hlcmUgfSBcIFwgSyh1KSA9IFxmcmFjezF9e1xzcXJ0ezJccGl9fSBlXnstdV4yLzJ9LgokJApgYGB7cn0KIyBHYXVzc2lhbiBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0b3IgYmFzZWQgb24gdGhlIGdpdmVuIGZvcm11bGEKa2RlX2dhdXNzaWFuIDwtIGZ1bmN0aW9uKHksIHQsIGggPSAyKXsKICBuIDwtIGxlbmd0aCh5KQogIHUgPC0gb3V0ZXIodCwgeSwgIi0iKSAvIGggICAgICAgICAgICMgc2NhbGVkIGRpc3RhbmNlcyBmb3IgdGhlIGtlcm5lbAogIHJvd1N1bXMoZG5vcm0odSkpIC8gKG4gKiBoKSAgICAgICAgICMgYXZlcmFnZSBjb250cmlidXRpb24gYWNyb3NzIG9ic2VydmF0aW9ucwp9CgojIEdyaWQgb2YgdmFsdWVzIHRvIGV2YWx1YXRlIHRoZSBkZW5zaXR5IHNtb290aGx5CnRncmlkIDwtIHNlcShtaW4oeSkgLSA2LCBtYXgoeSkgKyA2LCBsZW5ndGgub3V0ID0gMjAwKQoKIyBEZW5zaXR5IGVzdGltYXRlIGZyb20gdGhlIGN1c3RvbSBLREUgd2l0aCBoID0gMgpmX2hhdCA8LSBrZGVfZ2F1c3NpYW4oeSwgdGdyaWQsIGggPSAyKQoKIyBSJ3MgYnVpbHQtaW4gZGVuc2l0eSBlc3RpbWF0ZSB1c2luZyB0aGUgc2FtZSBiYW5kd2lkdGgKZl9yIDwtIGRlbnNpdHkoeSwgYncgPSAyLCBrZXJuZWwgPSAiZ2F1c3NpYW4iLAogICAgICAgICAgICAgICBmcm9tID0gbWluKHRncmlkKSwgdG8gPSBtYXgodGdyaWQpLCBuID0gbGVuZ3RoKHRncmlkKSkKCiMgUGxvdCBib3RoIGVzdGltYXRlcyB0byBjb21wYXJlIHJlc3VsdHMKcGxvdCh0Z3JpZCwgZl9oYXQsIHR5cGUgPSAibCIsIGx3ZCA9IDIsCiAgICAgeGxhYiA9ICJGYWlsdXJlIFRpbWUiLCB5bGFiID0gIkVzdGltYXRlZCBEZW5zaXR5IiwKICAgICBtYWluID0gIkdhdXNzaWFuIEtERSAoaCA9IDIpOiBDdXN0b20gdnMgUiBkZW5zaXR5KCkiKQpsaW5lcyhmX3IkeCwgZl9yJHksIGx0eSA9IDIsIGx3ZCA9IDIpCgpsZWdlbmQoInRvcHJpZ2h0IiwgYygiQ3VzdG9tIEtERSIsICJSIGRlbnNpdHkoKSIpLAogICAgICAgbHR5ID0gYygxLCAyKSwgbHdkID0gMikKCiMgTnVtZXJpY2FsIGNoZWNrIHRvIGNvbmZpcm0gYWdyZWVtZW50Cm1heChhYnMoZl9oYXQgLSBmX3IkeSkpCmBgYAoKYykgV3JpdGUgYSBjdXN0b20gUiBmdW5jdGlvbiB0aGF0IGNvbXB1dGVzIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRlcyB1c2luZyB0aGUgRXBhbmVjaG5pa292IGtlcm5lbCB3aXRoICRoPTIkLiBWYWxpZGF0ZSB5b3VyIGltcGxlbWVudGF0aW9uIGJ5IGNvbXBhcmluZyByZXN1bHRzIHdpdGggUidzIGJ1aWx0LWluIGRlbnNpdHkoKSBmdW5jdGlvbiBmb3IgR2F1c3NpYW4ga2VybmVsIGVzdGltYXRpb24uCgokJApcaGF0e2Z9X2godCkgPSBcZnJhY3sxfXtuaH1cc3VtX3tpPTF9Xm4gS1xsZWZ0KCBcZnJhY3t0LXRfaX17aH1ccmlnaHQpLCBcIFwgXHRleHR7IHdoZXJlIH0gXCBcIEsodSkgPSBcZnJhY3szfXs0fSgxIC0gdV4yKSBcIFwgXHRleHR7IGZvciB9IFwgXCB8dXwgXGxlIDEuCiQkCmBgYHtyfQojIEVwYW5lY2huaWtvdiBLREUgZnJvbSB0aGUgZm9ybXVsYSBpbiB0aGUgcHJvbXB0ICh1c2UgaCA9IDIpCmtkZV9lcGFuIDwtIGZ1bmN0aW9uKHksIHQsIGggPSAyKXsKICBuIDwtIGxlbmd0aCh5KQogIHUgPC0gb3V0ZXIodCwgeSwgIi0iKSAvIGggICAgICAgICAgICAgICAgICMgc2NhbGUgZGlzdGFuY2VzIGJ5IGgKICBLIDwtIDAuNzUgKiAoMSAtIHVeMikgKiAoYWJzKHUpIDw9IDEpICAgICAjIEVwYW5lY2huaWtvdiB3ZWlnaHRzCiAgcm93U3VtcyhLKSAvIChuICogaCkgICAgICAgICAgICAgICAgICAgICAgIyBhdmVyYWdlIGFuZCByZXNjYWxlCn0KCiMgR3JpZCB0byBldmFsdWF0ZSB0aGUgZGVuc2l0eSBjdXJ2ZQp0Z3JpZCA8LSBzZXEobWluKHkpIC0gNiwgbWF4KHkpICsgNiwgbGVuZ3RoLm91dCA9IDIwMCkKCiMgQ3VzdG9tIEVwYW5lY2huaWtvdiBLREUgd2l0aCBoID0gMgpmX2VwYW4gPC0ga2RlX2VwYW4oeSwgdGdyaWQsIGggPSAyKQoKIyBSJ3MgR2F1c3NpYW4gS0RFIHdpdGggdGhlIHNhbWUgYmFuZHdpZHRoIGZvciBjb21wYXJpc29uCmZfZ2F1c3NfciA8LSBkZW5zaXR5KHksIGJ3ID0gMiwga2VybmVsID0gImdhdXNzaWFuIiwKICAgICAgICAgICAgICAgICAgICAgZnJvbSA9IG1pbih0Z3JpZCksIHRvID0gbWF4KHRncmlkKSwgbiA9IGxlbmd0aCh0Z3JpZCkpCgojIENvbXBhcmUga2VybmVsIGNob2ljZSBhdCB0aGUgc2FtZSBoCnBsb3QodGdyaWQsIGZfZXBhbiwgdHlwZSA9ICJsIiwgbHdkID0gMiwKICAgICB4bGFiID0gIkZhaWx1cmUgVGltZSIsIHlsYWIgPSAiRXN0aW1hdGVkIERlbnNpdHkiLAogICAgIG1haW4gPSAiS0RFIChoID0gMik6IEVwYW5lY2huaWtvdiB2cyBHYXVzc2lhbiIpCmxpbmVzKGZfZ2F1c3NfciR4LCBmX2dhdXNzX3IkeSwgbHR5ID0gMiwgbHdkID0gMikKCmxlZ2VuZCgidG9wcmlnaHQiLCBjKCJFcGFuZWNobmlrb3YgS0RFIiwgIlIgR2F1c3NpYW4gS0RFIiksCiAgICAgICBsdHkgPSBjKDEsIDIpLCBsd2QgPSAyKQpgYGAKVGhlIEVwYW5lY2huaWtvdiBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0ZSBpcyBzbGlnaHRseSBtb3JlIHBlYWtlZCBpbiB0aGUgY2VudGVyIGJlY2F1c2UgaXQgdXNlcyBhIGZpeGVkIHJhbmdlIGFyb3VuZCBlYWNoIGRhdGEgcG9pbnQuIFRoZSBHYXVzc2lhbiBrZXJuZWwgZGlzdHJpYnV0ZXMgaXRzIHdlaWdodCBhY3Jvc3MgYWxsIG9ic2VydmF0aW9ucyB3aGljaCByZXN1bHRzIGluIGEgY29udGludW91cyBjdXJ2ZSB0aGF0IHNwYW5zIHRoZSBlbnRpcmUgcmFuZ2UuIEdpdmVuIHRoZSBsaW1pdGVkIHJhbmdlIG9mIHRoZSBkYXRhLCB0aGUgRXBhbmVjaG5pa292IGtlcm5lbCBwbGFjZXMgbW9yZSBlbXBoYXNpcyBvbiB0aGUgY2VudHJhbCBmYWlsdXJlIHRpbWVzLCB3aGlsZSB0aGUgR2F1c3NpYW4ga2VybmVsIHNwcmVhZHMgaW5mbHVlbmNlIG1vcmUgZXZlbmx5LgoKZCkgSG93IGRvZXMgdGhlIGNob2ljZSBvZiBrZXJuZWwgKEdhdXNzaWFuIHZzLiBFcGFuZWNobmlrb3YpIGFmZmVjdCB0aGUgZGVuc2l0eSBlc3RpbWF0ZT8gRm9yIGJvdGgga2VybmVsIGVzdGltYXRvcnMgYXBwbGllZCB0byB0aGlzIGRhdGFzZXQsIHdoYXQgaGFwcGVucyB3aGVuIHdlIHNlbGVjdCAkaD0xLjUkIHZlcnN1cyAkaD0yLjUkPwoKVGhlIEdhdXNzaWFuIGtlcm5lbCBnaXZlcyB3ZWlnaHQgdG8gYWxsIG9ic2VydmF0aW9ucyBhbmQgcHJvZHVjZXMgYSBzbW9vdGhlciBkZW5zaXR5IGVzdGltYXRlLCB3aGlsZSB0aGUgRXBhbmVjaG5pa292IGtlcm5lbCB1c2VzIGEgZml4ZWQgcmFuZ2UgYW5kIHJlc3VsdHMgaW4gYSBzbGlnaHRseSBtb3JlIHBlYWtlZCBlc3RpbWF0ZSBuZWFyIHRoZSBjZW50ZXIgb2YgdGhlIGRhdGEuIEZvciBib3RoIGtlcm5lbHMsIHVzaW5nIGEgc21hbGxlciBiYW5kd2lkdGggKGggPSAxLjUpIGNyZWF0ZXMgYSBtb3JlIGRldGFpbGVkIGFuZCB2YXJpYWJsZSBkZW5zaXR5LCB3aGVyZWFzIGEgbGFyZ2VyIGJhbmR3aWR0aCAoaCA9IDIuNSkgc21vb3RocyB0aGUgZXN0aW1hdGUgYW5kIHJlZHVjZXMgdmFyaWFiaWxpdHkgYnV0IG1heSBoaWRlIGZpbmVyIGZlYXR1cmVzIG9mIHRoZSBkaXN0cmlidXRpb24uCgoKCgoKCgo=