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.

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.

  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).

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
  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.

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.

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

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.

  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. \] # 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.

  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\)?

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=