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.
Work for Part A:
times <- c(23, 45, 67, 89, 112, 156, 189, 245)
uniq.time <- sort(unique(times)) #Used to sort data values and remove dublicates
my.ECDF <- function(indat, outx){ #Used to define function
freq.table <- table(indat) #Used to create frequency table
uniq <- as.numeric(names(freq.table)) #Gives unique values
rep.time <- as.vector(freq.table) #Turns frequencies into numeric vector
cum.rel.feq <- cumsum(rep.time)/sum(rep.time) #Gets the cumulative relative frequency
cum.prob <- NULL
for (i in 1:length(outx)){
intvl.id <- which(uniq <= outx[i]) #Used to identify the index meeting the condition
cum.prob[i] <- cum.rel.feq[max(intvl.id)] #Used to get cumulative probability
}
cum.prob #Used to get vector of ECDF values
}
plot(uniq.time, my.ECDF(indat=times, outx=uniq.time), #Assigns uniq.time to x-value, my.ECDF to y-values
type ="s", #Indicates it should be a step function
main = "ECDF using Mathematical Definition",
xlab = "Failure Times",
ylab = "Cumulative Probability")

r.ECDF <- ecdf(times) #Uses ecdf function on times
plot(r.ECDF, verticals = TRUE, pch=46, #indicates there should be vertical jumps
main = "ECDF using R",
xlab = "Failure Times",
ylab = "Cumulative Probability")
Comparing the ECDF using the Mathematical Definition and the ECDF using
the ecdf() r function, the resulting step functions appear to be the
same.
- 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).
Work for Part B:
I would say that based on the ECDF functions presented in the graphs
above, it makes sense that probability of failure before 100 hours is
0.5, since the cumulative probability at 100 hours is approximately
0.5.
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.
Work for Part A:
times2 <- c(12.3, 14.7, 15.2, 16.8, 18.1, 19.4, 20.6, 22.3, 23.9, 25.4)
#Creates histogram with 3 bins ranging from min of times2 and max of times2
hist(times2, breaks = seq(min(times2), max(times2), length.out = 4), main = "Histogram of Failure Times")

In the histogram above, the distribution seems to center around 19,
with the majority of observations being in the center bin. The two bins
to the side of the center bin are the same height, indicating that this
seems to be a symmetric distribution.
- 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}.
\]
Work for Part B:
gauss.kde <- function(t, data, h) { #defines function
n <- length(data) #gets size of n
K <- function(u) (1 / sqrt(2 * pi)) * exp(-0.5 * u^2) #Used to compute Gaussian kernel
sapply(t, function(x) (1 / (n * h)) * sum(K((x - data) / h))) #Used to apply kernel to scaled data
}
plot(density(times2, kernel = "gaussian", bw = 2), #Used to plot kde using R's function
main = "My Function vs. Built-In", lwd = 2)
lines(seq(10, 30, 0.1), gauss.kde(seq(10, 30, 0.1), #Used to plot kde using my function
times2, 2), lwd = 2, col = "orange")

The function I made follows the R’s density function very
closely.
- 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.
\] # Work for Part C:
epan.kde <- function(t, data, h) { #defines function
n <- length(data) #gets size of n
K <- function(u) ifelse(abs(u) <= 1, 0.75 * (1 - u^2), 0) #Used to compute Epanechnikov kernel
sapply(t, function(x) (1 / (n * h)) * sum(K((x - data) / h))) #Used to apply kernel to scaled data
}
plot(density(times2, kernel = "epanechnikov", bw = 2),
#Used to plot kde using R's function
main = "My Function vs. Built-In", lwd = 2)
lines(seq(10, 30, 0.1), epan.kde(seq(10, 30, 0.1),
#Used to plot kde using my function
times2, 2), lwd = 2, col = "orange")

The function I made does not seem to follow the R function as closely
as in the previous example.
- 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\)?
Work for Part D:
#Used to plot kde's using my function for various h values
plot(gauss.kde(seq(10, 30, 0.1), times2, 1.5), type = "l", main = "Gaussian with h = 1.5", ylab = "Density")

plot(gauss.kde(seq(10, 30, 0.1), times2, 2.5), type = "l", main = "Gaussian with h = 2.5", ylab = "Density")

plot(epan.kde(seq(10, 30, 0.1), times2, 1.5), type = "l", main = "Epanechnikov with h = 1.5", ylab = "Density")

plot(epan.kde(seq(10, 30, 0.1), times2, 2.5), type = "l", main = "Epanechnikov with h = 2.5", ylab = "Density")

When h = 1.5, both of the density estimates become less smooth. On
the other hand when h = 2.5, the density estimates become more
smooth.
LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMTogRXN0aW1hdGluZyBDREYgYW5kIFBERiINCmF1dGhvcjogIkdyYWNlIExpcHBlcnQiDQpkYXRlOiAiIER1ZTogMi8zLzIwMjYiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgdGhlbWU6IGx1bWVuDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge2NzcywgZWNobyA9IEZBTFNFfQ0KI1RPQzo6YmVmb3JlIHsNCiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMS4yZW07DQogIGRpc3BsYXk6IGJsb2NrOw0KICBjb2xvcjogbmF2eTsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KDQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQp9DQoNCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovDQogIGZvbnQtc2l6ZTogMjJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCg0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxNXB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLw0KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgew0KICBjb250ZW50OiAiLiI7DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCn0NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQogIGxpYnJhcnkoZ2dwbG90MikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQoNCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgbGlicmFyeShwbG90bHkpDQp9DQojIyMjDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KIA0KIFwNCiANCiMjICoqQXNzaWdubWVudCBPYmplY3RpdmVzKiogDQoNCiogRGV2ZWxvcCBhIGNsZWFyIHRlY2huaWNhbCB1bmRlcnN0YW5kaW5nIG9mIG5vbnBhcmFtZXRyaWMgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24gKENERikgZXN0aW1hdGlvbiBhbmQgdmFyaW91cyBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0b3JzLg0KDQoqIFRyYW5zbGF0ZSBtYXRoZW1hdGljYWwgZm9ybXVsYXMgaW50byBSIGZ1bmN0aW9ucyBhbmQgYXBwbHkgdGhlbSB0byBzb2x2ZSByZWxhdGVkIHByb2JsZW1zLg0KDQoqIENyZWF0ZSBlZmZlY3RpdmUgdmlzdWFsaXphdGlvbnMgdG8gZGVtb25zdHJhdGUgeW91ciB1bmRlcnN0YW5kaW5nIG9mIGtleSBjb25jZXB0cyBpbiB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucy4NCg0KDQoNClwNCg0KIyMgKipRdWVzdGlvbiAxOiBDdW11bGF0aXZlIERpc3RyaWJ1dGlvbiBGdW5jdGlvbiAoQ0RGKSBFc3RpbWF0aW9uKioNCg0KVGhlIGZvbGxvd2luZyBmYWlsdXJlIHRpbWVzIChpbiBob3Vycykgd2VyZSBvYnNlcnZlZCBmb3IgOCBlbGVjdHJvbmljIGNvbXBvbmVudHM6DQoNCjxjZW50ZXI+IDIzLCA0NSwgNjcsIDg5LCAxMTIsIDE1NiwgMTg5LCAyNDUgIDwvY2VudGVyPg0KDQphKSBXcml0ZSBhbiBSIGZ1bmN0aW9uIGltcGxlbWVudGluZyB0aGUgRUNERiAkXGhhdHtGfV9uKHQpJCBhY2NvcmRpbmcgdG8gaXRzIG1hdGhlbWF0aWNhbCBkZWZpbml0aW9uLiBWYWxpZGF0ZSB5b3VyIGltcGxlbWVudGF0aW9uIHVzaW5nIFIncyBlY2RmKCkgZnVuY3Rpb24gb24gdGhlIGdpdmVuIGRhdGEsIHdpdGggY29tcGFyaXNvbiBiYXNlZCBvbiB0aGVpciBzdGVwIGZ1bmN0aW9ucy4NCg0KIyBXb3JrIGZvciBQYXJ0IEE6DQoNCmBgYHtyfQ0KdGltZXMgPC0gYygyMywgNDUsIDY3LCA4OSwgMTEyLCAxNTYsIDE4OSwgMjQ1KQ0KdW5pcS50aW1lIDwtIHNvcnQodW5pcXVlKHRpbWVzKSkgI1VzZWQgdG8gc29ydCBkYXRhIHZhbHVlcyBhbmQgcmVtb3ZlIGR1YmxpY2F0ZXMNCm15LkVDREYgPC0gZnVuY3Rpb24oaW5kYXQsIG91dHgpeyAjVXNlZCB0byBkZWZpbmUgZnVuY3Rpb24NCiAgZnJlcS50YWJsZSA8LSB0YWJsZShpbmRhdCkgI1VzZWQgdG8gY3JlYXRlIGZyZXF1ZW5jeSB0YWJsZQ0KICB1bmlxIDwtIGFzLm51bWVyaWMobmFtZXMoZnJlcS50YWJsZSkpICNHaXZlcyB1bmlxdWUgdmFsdWVzDQogIHJlcC50aW1lIDwtIGFzLnZlY3RvcihmcmVxLnRhYmxlKSAjVHVybnMgZnJlcXVlbmNpZXMgaW50byBudW1lcmljIHZlY3Rvcg0KICBjdW0ucmVsLmZlcSA8LSBjdW1zdW0ocmVwLnRpbWUpL3N1bShyZXAudGltZSkgI0dldHMgdGhlIGN1bXVsYXRpdmUgcmVsYXRpdmUgZnJlcXVlbmN5DQogIGN1bS5wcm9iIDwtIE5VTEwNCiAgZm9yIChpIGluIDE6bGVuZ3RoKG91dHgpKXsgDQogICAgaW50dmwuaWQgPC0gd2hpY2godW5pcSA8PSBvdXR4W2ldKSAjVXNlZCB0byBpZGVudGlmeSB0aGUgaW5kZXggbWVldGluZyB0aGUgY29uZGl0aW9uDQogICAgY3VtLnByb2JbaV0gPC0gY3VtLnJlbC5mZXFbbWF4KGludHZsLmlkKV0gI1VzZWQgdG8gZ2V0IGN1bXVsYXRpdmUgcHJvYmFiaWxpdHkNCiAgfQ0KICBjdW0ucHJvYiAjVXNlZCB0byBnZXQgdmVjdG9yIG9mIEVDREYgdmFsdWVzDQp9DQoNCnBsb3QodW5pcS50aW1lLCBteS5FQ0RGKGluZGF0PXRpbWVzLCBvdXR4PXVuaXEudGltZSksICNBc3NpZ25zIHVuaXEudGltZSB0byB4LXZhbHVlLCBteS5FQ0RGIHRvIHktdmFsdWVzDQogICAgIHR5cGUgPSJzIiwgI0luZGljYXRlcyBpdCBzaG91bGQgYmUgYSBzdGVwIGZ1bmN0aW9uDQogICAgIG1haW4gPSAiRUNERiB1c2luZyBNYXRoZW1hdGljYWwgRGVmaW5pdGlvbiIsDQogICAgIHhsYWIgPSAiRmFpbHVyZSBUaW1lcyIsDQogICAgIHlsYWIgPSAiQ3VtdWxhdGl2ZSBQcm9iYWJpbGl0eSIpIA0KDQpyLkVDREYgPC0gZWNkZih0aW1lcykgI1VzZXMgZWNkZiBmdW5jdGlvbiBvbiB0aW1lcw0KDQpwbG90KHIuRUNERiwgdmVydGljYWxzID0gVFJVRSwgcGNoPTQ2LCAjaW5kaWNhdGVzIHRoZXJlIHNob3VsZCBiZSB2ZXJ0aWNhbCBqdW1wcw0KICAgICBtYWluID0gIkVDREYgdXNpbmcgUiIsDQogICAgIHhsYWIgPSAiRmFpbHVyZSBUaW1lcyIsDQogICAgIHlsYWIgPSAiQ3VtdWxhdGl2ZSBQcm9iYWJpbGl0eSIpDQoNCmBgYA0KQ29tcGFyaW5nIHRoZSBFQ0RGIHVzaW5nIHRoZSBNYXRoZW1hdGljYWwgRGVmaW5pdGlvbiBhbmQgdGhlIEVDREYgdXNpbmcgdGhlIGVjZGYoKSByIGZ1bmN0aW9uLCB0aGUgcmVzdWx0aW5nIHN0ZXAgZnVuY3Rpb25zIGFwcGVhciB0byBiZSB0aGUgc2FtZS4gIA0KDQpiKSBBIGNvbGxlYWd1ZSBjbGFpbXMgdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZSBiZWZvcmUgMTAwIGhvdXJzIGlzIDAuNSBiYXNlZCBvbiB0aGVzZSBkYXRhLiBEbyB5b3UgYWdyZWU/IEV4cGxhaW4geW91ciByZWFzb25pbmcgdXNpbmcgdGhlIGVtcGlyaWNhbCBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiAoRUNERikuDQoNCiMgV29yayBmb3IgUGFydCBCOg0KDQpJIHdvdWxkIHNheSB0aGF0IGJhc2VkIG9uIHRoZSBFQ0RGIGZ1bmN0aW9ucyBwcmVzZW50ZWQgaW4gdGhlIGdyYXBocyBhYm92ZSwgaXQgbWFrZXMgc2Vuc2UgdGhhdCBwcm9iYWJpbGl0eSBvZiBmYWlsdXJlIGJlZm9yZSAxMDAgaG91cnMgaXMgMC41LCBzaW5jZSB0aGUgY3VtdWxhdGl2ZSBwcm9iYWJpbGl0eSBhdCAxMDAgaG91cnMgaXMgYXBwcm94aW1hdGVseSAwLjUuICANCg0KIyMgKipRdWVzdGlvbiAyOiBEZW5zaXR5IEZ1bmN0aW9uIEVzdGltYXRpb24qKg0KDQpDb25zaWRlciB0aGUgZm9sbG93aW5nIGZhaWx1cmUgdGltZXMgZnJvbSBhIG1lY2hhbmljYWwgc3lzdGVtOg0KDQo8Y2VudGVyPiAxMi4zLCAxNC43LCAxNS4yLCAxNi44LCAxOC4xLCAxOS40LCAyMC42LCAyMi4zLCAyMy45LCAyNS40IDwvY2VudGVyPg0KDQphKSBDcmVhdGUgYSBoaXN0b2dyYW0gb2YgdGhlIGRhdGEgdXNpbmcgMyBlcXVhbGx5IHNwYWNlZCBiaW5zLiBXaGF0IGlzIHRoZSBlc3RpbWF0ZWQgZGVuc2l0eSBpbiBlYWNoIGJpbj8gRGVzY3JpYmUgdGhlIHNoYXBlIG9mIHRoZSBoaXN0b2dyYW0ncyBkaXN0cmlidXRpb24uDQoNCiMgV29yayBmb3IgUGFydCBBOg0KDQpgYGB7cn0NCnRpbWVzMiA8LSBjKDEyLjMsIDE0LjcsIDE1LjIsIDE2LjgsIDE4LjEsIDE5LjQsIDIwLjYsIDIyLjMsIDIzLjksIDI1LjQpDQoNCiNDcmVhdGVzIGhpc3RvZ3JhbSB3aXRoIDMgYmlucyByYW5naW5nIGZyb20gbWluIG9mIHRpbWVzMiBhbmQgbWF4IG9mIHRpbWVzMg0KaGlzdCh0aW1lczIsIGJyZWFrcyA9IHNlcShtaW4odGltZXMyKSwgbWF4KHRpbWVzMiksIGxlbmd0aC5vdXQgPSA0KSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgRmFpbHVyZSBUaW1lcyIpDQpgYGANCg0KSW4gdGhlIGhpc3RvZ3JhbSBhYm92ZSwgdGhlIGRpc3RyaWJ1dGlvbiBzZWVtcyB0byBjZW50ZXIgYXJvdW5kIDE5LCB3aXRoIHRoZSBtYWpvcml0eSBvZiBvYnNlcnZhdGlvbnMgYmVpbmcgaW4gdGhlIGNlbnRlciBiaW4uICBUaGUgdHdvIGJpbnMgdG8gdGhlIHNpZGUgb2YgdGhlIGNlbnRlciBiaW4gYXJlIHRoZSBzYW1lIGhlaWdodCwgaW5kaWNhdGluZyB0aGF0IHRoaXMgc2VlbXMgdG8gYmUgYSBzeW1tZXRyaWMgZGlzdHJpYnV0aW9uLiAgDQoNCg0KYikgV3JpdGUgYW4gUiBmdW5jdGlvbiB0aGF0IGNvbXB1dGVzIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRlcyB1c2luZyBhIEdhdXNzaWFuIGtlcm5lbCB3aXRoICRoPTIkLiBWYWxpZGF0ZSB5b3VyIGltcGxlbWVudGF0aW9uIGFnYWluc3QgUidzIGJ1aWx0LWluIGRlbnNpdHkoKSBmdW5jdGlvbi4NCg0KJCQNClxoYXR7Zn1faCh0KSA9IFxmcmFjezF9e25ofVxzdW1fe2k9MX1ebiBLXGxlZnQoIFxmcmFje3QtdF9pfXtofVxyaWdodCksIFwgXCBcdGV4dHsgd2hlcmUgfSBcIFwgSyh1KSA9IFxmcmFjezF9e1xzcXJ0ezJccGl9fSBlXnstdV4yLzJ9Lg0KJCQNCg0KIyBXb3JrIGZvciBQYXJ0IEI6DQoNCmBgYHtyfQ0KZ2F1c3Mua2RlIDwtIGZ1bmN0aW9uKHQsIGRhdGEsIGgpIHsgI2RlZmluZXMgZnVuY3Rpb24NCiAgbiA8LSBsZW5ndGgoZGF0YSkgI2dldHMgc2l6ZSBvZiBuDQogIEsgPC0gZnVuY3Rpb24odSkgKDEgLyBzcXJ0KDIgKiBwaSkpICogZXhwKC0wLjUgKiB1XjIpICNVc2VkIHRvIGNvbXB1dGUgR2F1c3NpYW4ga2VybmVsDQogIHNhcHBseSh0LCBmdW5jdGlvbih4KSAoMSAvIChuICogaCkpICogc3VtKEsoKHggLSBkYXRhKSAvIGgpKSkgI1VzZWQgdG8gYXBwbHkga2VybmVsIHRvIHNjYWxlZCBkYXRhDQp9DQoNCnBsb3QoZGVuc2l0eSh0aW1lczIsIGtlcm5lbCA9ICJnYXVzc2lhbiIsIGJ3ID0gMiksICNVc2VkIHRvIHBsb3Qga2RlIHVzaW5nIFIncyBmdW5jdGlvbg0KbWFpbiA9ICJNeSBGdW5jdGlvbiB2cy4gQnVpbHQtSW4iLCBsd2QgPSAyKSANCmxpbmVzKHNlcSgxMCwgMzAsIDAuMSksIGdhdXNzLmtkZShzZXEoMTAsIDMwLCAwLjEpLCAjVXNlZCB0byBwbG90IGtkZSB1c2luZyBteSBmdW5jdGlvbg0KdGltZXMyLCAyKSwgbHdkID0gMiwgY29sID0gIm9yYW5nZSIpDQoNCmBgYA0KDQpUaGUgZnVuY3Rpb24gSSBtYWRlIGZvbGxvd3MgdGhlIFIncyBkZW5zaXR5IGZ1bmN0aW9uIHZlcnkgY2xvc2VseS4gIA0KDQpjKSBXcml0ZSBhIGN1c3RvbSBSIGZ1bmN0aW9uIHRoYXQgY29tcHV0ZXMga2VybmVsIGRlbnNpdHkgZXN0aW1hdGVzIHVzaW5nIHRoZSBFcGFuZWNobmlrb3Yga2VybmVsIHdpdGggJGg9MiQuIFZhbGlkYXRlIHlvdXIgaW1wbGVtZW50YXRpb24gYnkgY29tcGFyaW5nIHJlc3VsdHMgd2l0aCBSJ3MgYnVpbHQtaW4gZGVuc2l0eSgpIGZ1bmN0aW9uIGZvciBHYXVzc2lhbiBrZXJuZWwgZXN0aW1hdGlvbi4NCg0KJCQNClxoYXR7Zn1faCh0KSA9IFxmcmFjezF9e25ofVxzdW1fe2k9MX1ebiBLXGxlZnQoIFxmcmFje3QtdF9pfXtofVxyaWdodCksIFwgXCBcdGV4dHsgd2hlcmUgfSBcIFwgSyh1KSA9IFxmcmFjezN9ezR9KDEgLSB1XjIpIFwgXCBcdGV4dHsgZm9yIH0gXCBcIHx1fCBcbGUgMS4NCiQkDQojIFdvcmsgZm9yIFBhcnQgQzoNCg0KYGBge3J9DQplcGFuLmtkZSA8LSBmdW5jdGlvbih0LCBkYXRhLCBoKSB7ICNkZWZpbmVzIGZ1bmN0aW9uDQogIG4gPC0gbGVuZ3RoKGRhdGEpICNnZXRzIHNpemUgb2Ygbg0KICBLIDwtIGZ1bmN0aW9uKHUpIGlmZWxzZShhYnModSkgPD0gMSwgMC43NSAqICgxIC0gdV4yKSwgMCkgICNVc2VkIHRvIGNvbXB1dGUgRXBhbmVjaG5pa292IGtlcm5lbA0KICBzYXBwbHkodCwgZnVuY3Rpb24oeCkgKDEgLyAobiAqIGgpKSAqIHN1bShLKCh4IC0gZGF0YSkgLyBoKSkpICNVc2VkIHRvIGFwcGx5IGtlcm5lbCB0byBzY2FsZWQgZGF0YQ0KfQ0KcGxvdChkZW5zaXR5KHRpbWVzMiwga2VybmVsID0gImVwYW5lY2huaWtvdiIsIGJ3ID0gMiksDQojVXNlZCB0byBwbG90IGtkZSB1c2luZyBSJ3MgZnVuY3Rpb24NCm1haW4gPSAiTXkgRnVuY3Rpb24gdnMuIEJ1aWx0LUluIiwgbHdkID0gMikNCmxpbmVzKHNlcSgxMCwgMzAsIDAuMSksIGVwYW4ua2RlKHNlcSgxMCwgMzAsIDAuMSksDQojVXNlZCB0byBwbG90IGtkZSB1c2luZyBteSBmdW5jdGlvbg0KdGltZXMyLCAyKSwgbHdkID0gMiwgY29sID0gIm9yYW5nZSIpDQoNCg0KYGBgDQoNClRoZSBmdW5jdGlvbiBJIG1hZGUgZG9lcyBub3Qgc2VlbSB0byBmb2xsb3cgdGhlIFIgZnVuY3Rpb24gYXMgY2xvc2VseSBhcyBpbiB0aGUgcHJldmlvdXMgZXhhbXBsZS4gIA0KDQpkKSBIb3cgZG9lcyB0aGUgY2hvaWNlIG9mIGtlcm5lbCAoR2F1c3NpYW4gdnMuIEVwYW5lY2huaWtvdikgYWZmZWN0IHRoZSBkZW5zaXR5IGVzdGltYXRlPyBGb3IgYm90aCBrZXJuZWwgZXN0aW1hdG9ycyBhcHBsaWVkIHRvIHRoaXMgZGF0YXNldCwgd2hhdCBoYXBwZW5zIHdoZW4gd2Ugc2VsZWN0ICRoPTEuNSQgdmVyc3VzICRoPTIuNSQ/DQoNCiMgV29yayBmb3IgUGFydCBEOg0KDQpgYGB7cn0NCg0KI1VzZWQgdG8gcGxvdCBrZGUncyB1c2luZyBteSBmdW5jdGlvbiBmb3IgdmFyaW91cyBoIHZhbHVlcw0KcGxvdChnYXVzcy5rZGUoc2VxKDEwLCAzMCwgMC4xKSwgdGltZXMyLCAxLjUpLCB0eXBlID0gImwiLCBtYWluID0gIkdhdXNzaWFuIHdpdGggaCA9IDEuNSIsIHlsYWIgPSAiRGVuc2l0eSIpIA0KcGxvdChnYXVzcy5rZGUoc2VxKDEwLCAzMCwgMC4xKSwgdGltZXMyLCAyLjUpLCB0eXBlID0gImwiLCBtYWluID0gIkdhdXNzaWFuIHdpdGggaCA9IDIuNSIsIHlsYWIgPSAiRGVuc2l0eSIpDQoNCnBsb3QoZXBhbi5rZGUoc2VxKDEwLCAzMCwgMC4xKSwgdGltZXMyLCAxLjUpLCB0eXBlID0gImwiLCBtYWluID0gIkVwYW5lY2huaWtvdiB3aXRoIGggPSAxLjUiLCB5bGFiID0gIkRlbnNpdHkiKQ0KDQpwbG90KGVwYW4ua2RlKHNlcSgxMCwgMzAsIDAuMSksIHRpbWVzMiwgMi41KSwgdHlwZSA9ICJsIiwgbWFpbiA9ICJFcGFuZWNobmlrb3Ygd2l0aCBoID0gMi41IiwgeWxhYiA9ICJEZW5zaXR5IikNCg0KYGBgDQoNCldoZW4gaCA9IDEuNSwgYm90aCBvZiB0aGUgZGVuc2l0eSBlc3RpbWF0ZXMgYmVjb21lIGxlc3Mgc21vb3RoLiAgT24gdGhlIG90aGVyIGhhbmQgd2hlbiBoID0gMi41LCB0aGUgZGVuc2l0eSBlc3RpbWF0ZXMgYmVjb21lIG1vcmUgc21vb3RoLg0KDQo=