Problem 3
We now review k-fold cross-validation. (a) Explain how k-fold cross-validation is implemented.
The data is randomly divided into k groups. Ideally these groups are all the same size, but approximately the same will suffice. A model is then fitted k times using one of the k-folds (subsets) as the validation set and remaining subsets comprise the training set. The mean error rate is then taken, which is used as the estimate of test error for the model.
- What are the advantages and disadvantages of k-fold cross validation relative to:
- The validation set approach?
K-fold cross-validation uses more of the data set than the validation set approach, so it provides a more accurate estimate of the test error rate. One drawback of k-fold CV compared to the validation set approach is that it is more computationally time consuming when the dataset is large.
- LOOCV? K-fold CV is more computationally efficient because the model only needs to run as many times as there are folds, where as LOOCV has to run n times (n = number of observations). Additionally, when using k=5 or k=10 folds, k-fold CV has shown to obtain test error rate estimates that balance the bias-variance trade-off. This means it will provide more accurate estimates compared to LOOCV.
Problem 5
In Chapter 4, we used logistic regression to predict the probability of default using income and balance on the Default data set. We will now estimate the test error of this logistic regression model using the validation set approach. Do not forget to set a random seed before beginning your analysis.
a) Fit a logistic regression model that uses income and balance to predict default.
set.seed(17)
default_data = Default
logit_default = glm(default ~ income + balance, data = default_data, family = "binomial")
summary(logit_default)
Call:
glm(formula = default ~ income + balance, family = "binomial",
data = default_data)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.4725 -0.1444 -0.0574 -0.0211 3.7245
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -1.154e+01 4.348e-01 -26.545 < 2e-16 ***
income 2.081e-05 4.985e-06 4.174 2.99e-05 ***
balance 5.647e-03 2.274e-04 24.836 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 2920.6 on 9999 degrees of freedom
Residual deviance: 1579.0 on 9997 degrees of freedom
AIC: 1585
Number of Fisher Scoring iterations: 8
Problem 6
We continue to consider the use of a logistic regression model to predict the probability of default using income and balance on the Default data set. In particular, we will now compute estimates for the standard errors of the income and balance logistic regression coefficients in two different ways: (1) using the bootstrap, and (2) using the standard formula for computing the standard errors in the glm() function. Do not forget to set a random seed before beginning your analysis.
a) Using the summary() and glm() functions, determine the estimated standard errors for the coefficients associated with income and balance in a multiple logistic regression model that uses both predictors.
The coefficient for income (2.081e-05) has a standard error of 4.985e-06, and the coefficient for balance (5.647e-03) has a standard error of 2.274e-04.
logit_default = glm(default ~ income + balance, data = default_data, family = "binomial")
summary(logit_default)$coefficients
Estimate Std. Error z value Pr(>|z|)
(Intercept) -1.154047e+01 4.347564e-01 -26.544680 2.958355e-155
income 2.080898e-05 4.985167e-06 4.174178 2.990638e-05
balance 5.647103e-03 2.273731e-04 24.836280 3.638120e-136
c) Use the boot() function together with your boot.fn() function to estimate the standard errors of the logistic regression coefficients for income and balance.
boot(default_data, boot.fn, 1000)
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = default_data, statistic = boot.fn, R = 1000)
Bootstrap Statistics :
original bias std. error
t1* -1.154047e+01 -3.771940e-02 4.190856e-01
t2* 2.080898e-05 1.161211e-07 4.759188e-06
t3* 5.647103e-03 1.488493e-05 2.223174e-04
View(default_data)
Problem 9
We will now consider the Boston housing data set, from the MASS library.
a) Based on this data set, provide an estimate for the population mean of medv. Call this estimate \(\hat{\mu}\).
set.seed(17)
boston_data = Boston
(mu_hat = mean(boston_data$medv))
[1] 22.53281
b) Provide an estimate of the standard error of \(\hat{\mu}\). Interpret this result.
The standard error estimated is 0.4088611. Since medv represents median value of homes (in $1000s), this means the sample mean of this data set (22.53281 -> 22,533) could be off by about $410 in either direction.
sd(boston_data$medv) / sqrt(nrow(boston_data))
[1] 0.4088611
c) Now estimate the standard error of \(\hat{\mu}\) using the bootstrap. How does this compare to your answer from (b)?
The standard error estimated using bootstrap is 0.4168157, which is slightly larger than the standard error estimated in part b (0.4088611).
boot.fn <- function(data, index) {
return(mean(data[index]))
}
boot(boston_data$medv, boot.fn, 1000)
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = boston_data$medv, statistic = boot.fn, R = 1000)
Bootstrap Statistics :
original bias std. error
t1* 22.53281 -0.01082431 0.4168157
d) Based on your bootstrap estimate from (c), provide a 95% confidence interval for the mean of medv. Compare it to the results obtained using t.test(Boston$medv).
The 95% confidence interval based on the bootstrap estimate from (c) is (21.71585, 23.34977). This confidence interval is slightly wider than the confidence interval obtained using t.test(Boston$medv) which is (21.72953, 23.33608). Note: though not identical, these confidence intervals are very close to each other
t.test(boston_data$medv)
One Sample t-test
data: boston_data$medv
t = 55.111, df = 505, p-value < 2.2e-16
alternative hypothesis: true mean is not equal to 0
95 percent confidence interval:
21.72953 23.33608
sample estimates:
mean of x
22.53281
# I am choosing to use 1.96 instead of 2 while calculating my 95% confidence interval to be more precise
(conf_interval = c(mu_hat - 1.96*0.4168157, mu_hat + 1.96*0.4168157))
[1] 21.71585 23.34977
g) Based on this data set, provide an estimate for the tenth percentile of medv in Boston suburbs. Call this quantity \(\hat{\mu}_{0.1}\).
(mu_tenth_percentile = quantile(boston_data$medv, 0.1))
10%
12.75
LS0tDQp0aXRsZTogJ0hXNDogU1RBIDY1NDMtQ2FtcGJlbGwnDQphdXRob3I6ICJUb3JleSBUb25jaGUiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclbS8lZC8lWScpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCnN1YnRpdGxlOiAnQ2g1IChwZy4gMTk3KTogMywgNSwgNiwgOScNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmxpYnJhcnkoSVNMUikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGJvb3QpDQpsaWJyYXJ5KE1BU1MpDQpgYGANCg0KIyMjIFByb2JsZW0gMw0KV2Ugbm93IHJldmlldyBrLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbi4NCihhKSBFeHBsYWluIGhvdyBrLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiBpcyBpbXBsZW1lbnRlZC4NCg0KVGhlIGRhdGEgaXMgcmFuZG9tbHkgZGl2aWRlZCBpbnRvIGsgZ3JvdXBzLiBJZGVhbGx5IHRoZXNlIGdyb3VwcyBhcmUgYWxsIHRoZSBzYW1lIHNpemUsIGJ1dCBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIHdpbGwgc3VmZmljZS4gQSBtb2RlbCBpcyB0aGVuIGZpdHRlZCBrIHRpbWVzIHVzaW5nIG9uZSBvZiB0aGUgay1mb2xkcyAoc3Vic2V0cykgYXMgdGhlIHZhbGlkYXRpb24gc2V0IGFuZCByZW1haW5pbmcgc3Vic2V0cyBjb21wcmlzZSB0aGUgdHJhaW5pbmcgc2V0LiBUaGUgbWVhbiBlcnJvciByYXRlIGlzIHRoZW4gdGFrZW4sIHdoaWNoIGlzIHVzZWQgYXMgdGhlIGVzdGltYXRlIG9mIHRlc3QgZXJyb3IgZm9yIHRoZSBtb2RlbC4NCg0KKGIpIFdoYXQgYXJlIHRoZSBhZHZhbnRhZ2VzIGFuZCBkaXNhZHZhbnRhZ2VzIG9mIGstZm9sZCBjcm9zcyB2YWxpZGF0aW9uDQpyZWxhdGl2ZSB0bzoNCmkuIFRoZSB2YWxpZGF0aW9uIHNldCBhcHByb2FjaD8NCg0KSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24gdXNlcyBtb3JlIG9mIHRoZSBkYXRhIHNldCB0aGFuIHRoZSB2YWxpZGF0aW9uIHNldCBhcHByb2FjaCwgc28gaXQgcHJvdmlkZXMgYSBtb3JlIGFjY3VyYXRlIGVzdGltYXRlIG9mIHRoZSB0ZXN0IGVycm9yIHJhdGUuIE9uZSBkcmF3YmFjayBvZiBrLWZvbGQgQ1YgY29tcGFyZWQgdG8gdGhlIHZhbGlkYXRpb24gc2V0IGFwcHJvYWNoIGlzIHRoYXQgaXQgaXMgbW9yZSBjb21wdXRhdGlvbmFsbHkgdGltZSBjb25zdW1pbmcgd2hlbiB0aGUgZGF0YXNldCBpcyBsYXJnZS4NCg0KaWkuIExPT0NWPw0KSy1mb2xkIENWIGlzIG1vcmUgY29tcHV0YXRpb25hbGx5IGVmZmljaWVudCBiZWNhdXNlIHRoZSBtb2RlbCBvbmx5IG5lZWRzIHRvIHJ1biBhcyBtYW55IHRpbWVzIGFzIHRoZXJlIGFyZSBmb2xkcywgd2hlcmUgYXMgTE9PQ1YgaGFzIHRvIHJ1biBuIHRpbWVzIChuID0gbnVtYmVyIG9mIG9ic2VydmF0aW9ucykuIEFkZGl0aW9uYWxseSwgd2hlbiB1c2luZyBrPTUgb3Igaz0xMCBmb2xkcywgay1mb2xkIENWIGhhcyBzaG93biB0byBvYnRhaW4gdGVzdCBlcnJvciByYXRlIGVzdGltYXRlcyB0aGF0IGJhbGFuY2UgdGhlIGJpYXMtdmFyaWFuY2UgdHJhZGUtb2ZmLiBUaGlzIG1lYW5zIGl0IHdpbGwgcHJvdmlkZSBtb3JlIGFjY3VyYXRlIGVzdGltYXRlcyBjb21wYXJlZCB0byBMT09DVi4NCg0KDQoNCiMjIyBQcm9ibGVtIDUNCkluIENoYXB0ZXIgNCwgd2UgdXNlZCBsb2dpc3RpYyByZWdyZXNzaW9uIHRvIHByZWRpY3QgdGhlIHByb2JhYmlsaXR5IG9mIGRlZmF1bHQgdXNpbmcgaW5jb21lIGFuZCBiYWxhbmNlIG9uIHRoZSBEZWZhdWx0IGRhdGEgc2V0LiANCldlIHdpbGwgbm93IGVzdGltYXRlIHRoZSB0ZXN0IGVycm9yIG9mIHRoaXMgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB1c2luZyB0aGUgdmFsaWRhdGlvbiBzZXQgYXBwcm9hY2guIA0KRG8gbm90IGZvcmdldCB0byBzZXQgYSByYW5kb20gc2VlZCBiZWZvcmUgYmVnaW5uaW5nIHlvdXIgYW5hbHlzaXMuIA0KDQojIyMjIGEpIEZpdCBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgdGhhdCB1c2VzIGluY29tZSBhbmQgYmFsYW5jZSB0byBwcmVkaWN0IGRlZmF1bHQuDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTcpDQpkZWZhdWx0X2RhdGEgPSBEZWZhdWx0DQpsb2dpdF9kZWZhdWx0ID0gZ2xtKGRlZmF1bHQgfiBpbmNvbWUgKyBiYWxhbmNlLCBkYXRhID0gZGVmYXVsdF9kYXRhLCBmYW1pbHkgPSAiYmlub21pYWwiKQ0Kc3VtbWFyeShsb2dpdF9kZWZhdWx0KQ0KYGBgDQoNCiMjIyMgYikgVXNpbmcgdGhlIHZhbGlkYXRpb24gc2V0IGFwcHJvYWNoLCBlc3RpbWF0ZSB0aGUgdGVzdCBlcnJvciBvZiB0aGlzIG1vZGVsLiBJbiBvcmRlciB0byBkbyB0aGlzLCB5b3UgbXVzdCBwZXJmb3JtIHRoZSBmb2xsb3dpbmcgc3RlcHM6DQppLiBTcGxpdCB0aGUgc2FtcGxlIHNldCBpbnRvIGEgdHJhaW5pbmcgc2V0IGFuZCBhIHZhbGlkYXRpb24gc2V0Lg0KYGBge3J9DQp0cmFpbl9pbmRleCA9IHNhbXBsZSgxOm5yb3coZGVmYXVsdF9kYXRhKSwgMC43Km5yb3coZGVmYXVsdF9kYXRhKSkNCnRyYWluX2RlZmF1bHQgPSBkZWZhdWx0X2RhdGFbdHJhaW5faW5kZXgsIF0NCnRlc3RfZGVmYXVsdCA9IGRlZmF1bHRfZGF0YVstdHJhaW5faW5kZXgsIF0NCmBgYA0KDQoNCmlpLiBGaXQgYSBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIG9ubHkgdGhlIHRyYWluaW5nIG9ic2VydmF0aW9ucy4NCmBgYHtyfQ0KbG9naXRfZGVmYXVsdDIgPSBnbG0oZGVmYXVsdCB+IGluY29tZSArIGJhbGFuY2UsIGRhdGEgPSB0cmFpbl9kZWZhdWx0LCBmYW1pbHkgPSAiYmlub21pYWwiKQ0Kc3VtbWFyeShsb2dpdF9kZWZhdWx0MikNCmBgYA0KDQoNCmlpaS4gT2J0YWluIGEgcHJlZGljdGlvbiBvZiBkZWZhdWx0IHN0YXR1cyBmb3IgZWFjaCBpbmRpdmlkdWFsIGluIHRoZSB2YWxpZGF0aW9uIHNldCBieSBjb21wdXRpbmcgdGhlIHBvc3RlcmlvciBwcm9iYWJpbGl0eSBvZiBkZWZhdWx0IGZvciB0aGF0IGluZGl2aWR1YWwsIGFuZCBjbGFzc2lmeWluZyB0aGUgaW5kaXZpZHVhbCB0byB0aGUgZGVmYXVsdCBjYXRlZ29yeSBpZiB0aGUgcG9zdGVyaW9yIHByb2JhYmlsaXR5IGlzIGdyZWF0ZXIgdGhhbiAwLjUuDQpgYGB7cn0NCnRlc3RfcHJvYnMgPSBwcmVkaWN0KGxvZ2l0X2RlZmF1bHQyLCB0ZXN0X2RlZmF1bHQsIHR5cGUgPSAicmVzcG9uc2UiKQ0KdGVzdF9wcmVkcyA9IGlmX2Vsc2UodGVzdF9wcm9icyA+IDAuNSwgIlllcyIsICJObyIpDQpgYGANCg0KDQppdi4gQ29tcHV0ZSB0aGUgdmFsaWRhdGlvbiBzZXQgZXJyb3IsIHdoaWNoIGlzIHRoZSBmcmFjdGlvbiBvZiB0aGUgb2JzZXJ2YXRpb25zIGluIHRoZSB2YWxpZGF0aW9uIHNldCB0aGF0IGFyZSBtaXNjbGFzc2lmaWVkLg0KYGBge3J9DQp0YWJsZSh0ZXN0X3ByZWRzLCB0ZXN0X2RlZmF1bHQkZGVmYXVsdCkNCihlcnJvciA9IG1lYW4odGVzdF9wcmVkcyAhPSB0ZXN0X2RlZmF1bHQkZGVmYXVsdCkpDQpgYGANCg0KDQojIyMjIGMpIFJlcGVhdCB0aGUgcHJvY2VzcyBpbiAoYikgdGhyZWUgdGltZXMsIHVzaW5nIHRocmVlIGRpZmZlcmVudCBzcGxpdHMgb2YgdGhlIG9ic2VydmF0aW9ucyBpbnRvIGEgdHJhaW5pbmcgc2V0IGFuZCBhIHZhbGlkYXRpb24gc2V0LiBDb21tZW50IG9uIHRoZSByZXN1bHRzIG9idGFpbmVkLg0KDQpJIGNyZWF0ZWQgYSBmb3IgbG9vcCB0byByZXBlYXQgdGhlIHZhbGlkYXRpb24gYXBwcm9hY2ggb2YgZXN0aW1hdGluZyB0aGUgZXJyb3IgcmF0ZSBvZiB0aGUgbG9naXN0aWMgbW9kZWwgd2l0aCB0aHJlZSBkaWZmZXJlbnQgc3BsaXRzLiBUaGUgZXJyb3IgcmF0ZXMgZm91bmQgd2l0aCB0aGVzZSB0aHJlZSBkaWZmZXJlbnQgc3BsaXRzIHdlcmUgMC4wMjczLCAwLjAyMTcsIGFuZCAwLjAzMS4gQ29tcGFyZWQgdG8gdGhlIGVycm9yIHJhdGUgZm91bmQgaW4gdGhlIG9yaWdpbmFsIHNwbGl0ICgwLjAyNDMpLCB0aGV5IGFyZSBhbGwgc2ltaWxhci4gDQpgYGB7cn0NCmVycm9ycyA9IGMoKQ0Kc2VlZHMgPSBjKDIzLCA1NSwgOTEpDQpmb3IoaSBpbiAxOjMpew0KICBzZXQuc2VlZChzZWVkc1tpXSkNCiAgdGVtcF90cmFpbl9pbmRleCA9IHNhbXBsZSgxOm5yb3coZGVmYXVsdF9kYXRhKSwgMC43Km5yb3coZGVmYXVsdF9kYXRhKSkNCiAgdGVtcF90cmFpbiA9IGRlZmF1bHRfZGF0YVt0ZW1wX3RyYWluX2luZGV4LCBdDQogIHRlbXBfdGVzdCA9IGRlZmF1bHRfZGF0YVstdGVtcF90cmFpbl9pbmRleCwgXQ0KICB0ZW1wX2xvZ2l0ID0gZ2xtKGRlZmF1bHQgfiBpbmNvbWUgKyBiYWxhbmNlLCBkYXRhID0gdGVtcF90cmFpbiwgZmFtaWx5ID0gImJpbm9taWFsIikNCiAgdGVtcF90ZXN0X3Byb2JzID0gcHJlZGljdCh0ZW1wX2xvZ2l0LCB0ZW1wX3Rlc3QsIHR5cGUgPSAicmVzcG9uc2UiKQ0KICB0ZW1wX3Rlc3RfcHJlZHMgPSBpZl9lbHNlKHRlbXBfdGVzdF9wcm9icyA+IDAuNSwgIlllcyIsICJObyIpDQogIGVycm9yc1tpXSA9IG1lYW4odGVtcF90ZXN0X3ByZWRzICE9IHRlbXBfdGVzdCRkZWZhdWx0KQ0KfQ0KZXJyb3JzW2krMV0gPSBlcnJvcg0KYGBgDQoNCg0KIyMjIyBkKSBOb3cgY29uc2lkZXIgYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHRoYXQgcHJlZGljdHMgdGhlIHByb2JhYmlsaXR5IG9mIGRlZmF1bHQgdXNpbmcgaW5jb21lLCBiYWxhbmNlLCBhbmQgYSBkdW1teSB2YXJpYWJsZSBmb3Igc3R1ZGVudC4gRXN0aW1hdGUgdGhlIHRlc3QgZXJyb3IgZm9yIHRoaXMgbW9kZWwgdXNpbmcgdGhlIHZhbGlkYXRpb24gc2V0IGFwcHJvYWNoLiBDb21tZW50IG9uIHdoZXRoZXIgb3Igbm90IGluY2x1ZGluZyBhIGR1bW15IHZhcmlhYmxlIGZvciBzdHVkZW50IGxlYWRzIHRvIGEgcmVkdWN0aW9uIGluIHRoZSB0ZXN0IGVycm9yIHJhdGUuDQoNClRoZSBkdW1teSB2YXJpYWJsZSBgc3R1ZGVudFllc2AgaXMgZm91bmQgdG8gYmUgc2lnbmlmaWNhbnQgd2l0aCBhIHAtdmFsdWUgb2YgbGVzcyB0aGFuIDAuMDUuIEhvd2V2ZXIsIGluY2x1ZGluZyBhIGR1bW15IHZhcmlhYmxlIGRvZXMgbm90IGxlYWQgdG8gYSByZWR1Y3Rpb24gaW4gZXJyb3IgcmF0ZS4gSW4gZmFjdCwgdGhlIGVycm9yIHJhdGVzIGZvciB0aGUgdmFsaWRhdGlvbiBzZXQgZm9yIGVhY2ggdHJhaW4vdGVzdCBzcGxpdCB1c2VkIGVhcmxpZXIgd2hlbiBpbmNsdWRpbmcgc3R1ZGVudCBhcmUgYWxsIGlzIGdyZWF0ZXIgdGhhbiB0aGUgZXJyb3IgcmF0ZSB3aGVuIHN0dWRlbnQgaXMgbm90IGluY2x1ZGVkLg0KYGBge3J9DQoNCm5ld19lcnJvcnMgPSBjKCkNCnNlZWRzID0gYygyMywgNTUsIDkxLCAxNykNCmZvcihpIGluIDE6NCl7DQogIHNldC5zZWVkKHNlZWRzW2ldKQ0KICB0ZW1wX3RyYWluX2luZGV4ID0gc2FtcGxlKDE6bnJvdyhkZWZhdWx0X2RhdGEpLCAwLjcqbnJvdyhkZWZhdWx0X2RhdGEpKQ0KICB0ZW1wX3RyYWluID0gZGVmYXVsdF9kYXRhW3RlbXBfdHJhaW5faW5kZXgsIF0NCiAgdGVtcF90ZXN0ID0gZGVmYXVsdF9kYXRhWy10ZW1wX3RyYWluX2luZGV4LCBdDQogIHRlbXBfbG9naXQgPSBnbG0oZGVmYXVsdCB+IC4sIGRhdGEgPSB0ZW1wX3RyYWluLCBmYW1pbHkgPSAiYmlub21pYWwiKQ0KICBzdW1tYXJ5KHRlbXBfbG9naXQpJGNvZWZmaWNpZW50cw0KICB0ZW1wX3Rlc3RfcHJvYnMgPSBwcmVkaWN0KHRlbXBfbG9naXQsIHRlbXBfdGVzdCwgdHlwZSA9ICJyZXNwb25zZSIpDQogIHRlbXBfdGVzdF9wcmVkcyA9IGlmX2Vsc2UodGVtcF90ZXN0X3Byb2JzID4gMC41LCAiWWVzIiwgIk5vIikNCiAgbmV3X2Vycm9yc1tpXSA9IG1lYW4odGVtcF90ZXN0X3ByZWRzICE9IHRlbXBfdGVzdCRkZWZhdWx0KQ0KfQ0KDQpwcmludCgiRXJyb3JzIG5vdCBpbmNsdWRpbmcgc3R1ZGVudCIpOyBlcnJvcnMNCnByaW50KCJFcnJvcnMgaW5jbHVkaW5nIHN0dWRlbnQiKTsgbmV3X2Vycm9ycw0KYGBgDQoNCg0KIyMjIFByb2JsZW0gNg0KV2UgY29udGludWUgdG8gY29uc2lkZXIgdGhlIHVzZSBvZiBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgdG8gcHJlZGljdCB0aGUgcHJvYmFiaWxpdHkgb2YgZGVmYXVsdCB1c2luZyBpbmNvbWUgYW5kIGJhbGFuY2Ugb24gdGhlIERlZmF1bHQgZGF0YSBzZXQuIEluIHBhcnRpY3VsYXIsIHdlIHdpbGwgbm93IGNvbXB1dGUgZXN0aW1hdGVzIGZvciB0aGUgc3RhbmRhcmQgZXJyb3JzIG9mIHRoZSBpbmNvbWUgYW5kIGJhbGFuY2UgbG9naXN0aWMgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgaW4gdHdvIGRpZmZlcmVudCB3YXlzOiAoMSkgdXNpbmcgdGhlIGJvb3RzdHJhcCwgYW5kICgyKSB1c2luZyB0aGUgc3RhbmRhcmQgZm9ybXVsYSBmb3IgY29tcHV0aW5nIHRoZSBzdGFuZGFyZCBlcnJvcnMgaW4gdGhlIGdsbSgpIGZ1bmN0aW9uLiBEbyBub3QgZm9yZ2V0IHRvIHNldCBhIHJhbmRvbSBzZWVkIGJlZm9yZSBiZWdpbm5pbmcgeW91ciBhbmFseXNpcy4NCg0KDQojIyMjIGEpIFVzaW5nIHRoZSBzdW1tYXJ5KCkgYW5kIGdsbSgpIGZ1bmN0aW9ucywgZGV0ZXJtaW5lIHRoZSBlc3RpbWF0ZWQgc3RhbmRhcmQgZXJyb3JzIGZvciB0aGUgY29lZmZpY2llbnRzIGFzc29jaWF0ZWQgd2l0aCBpbmNvbWUgYW5kIGJhbGFuY2UgaW4gYSBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHRoYXQgdXNlcyBib3RoIHByZWRpY3RvcnMuDQoNClRoZSBjb2VmZmljaWVudCBmb3IgaW5jb21lICgyLjA4MWUtMDUpIGhhcyBhIHN0YW5kYXJkIGVycm9yIG9mIDQuOTg1ZS0wNiwgYW5kIHRoZSBjb2VmZmljaWVudCBmb3IgYmFsYW5jZSAoNS42NDdlLTAzKSBoYXMgYSBzdGFuZGFyZCBlcnJvciBvZiAyLjI3NGUtMDQuDQpgYGB7cn0NCmxvZ2l0X2RlZmF1bHQgPSBnbG0oZGVmYXVsdCB+IGluY29tZSArIGJhbGFuY2UsIGRhdGEgPSBkZWZhdWx0X2RhdGEsIGZhbWlseSA9ICJiaW5vbWlhbCIpDQpzdW1tYXJ5KGxvZ2l0X2RlZmF1bHQpJGNvZWZmaWNpZW50cw0KYGBgDQoNCg0KIyMjIyBiKSBXcml0ZSBhIGZ1bmN0aW9uLCBib290LmZuKCksIHRoYXQgdGFrZXMgYXMgaW5wdXQgdGhlIERlZmF1bHQgZGF0YSBzZXQgYXMgd2VsbCBhcyBhbiBpbmRleCBvZiB0aGUgb2JzZXJ2YXRpb25zLCBhbmQgdGhhdCBvdXRwdXRzIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgZm9yIGluY29tZSBhbmQgYmFsYW5jZSBpbiB0aGUgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbC4NCmBgYHtyfQ0KYm9vdC5mbiA8LSBmdW5jdGlvbihkYXRhLCBpbmRleCA9IDE6bnJvdyhkYXRhKSkgew0KICB0ZW1wX2xvZ2l0ID0gZ2xtKGRlZmF1bHQgfiBpbmNvbWUgKyBiYWxhbmNlLCBkYXRhID0gZGF0YSwgc3Vic2V0ID0gaW5kZXgsIGZhbWlseSA9ICJiaW5vbWlhbCIpDQogIHJldHVybih0ZW1wX2xvZ2l0JGNvZWZmaWNpZW50cykNCn0NCmBgYA0KDQoNCiMjIyMgYykgVXNlIHRoZSBib290KCkgZnVuY3Rpb24gdG9nZXRoZXIgd2l0aCB5b3VyIGJvb3QuZm4oKSBmdW5jdGlvbiB0byBlc3RpbWF0ZSB0aGUgc3RhbmRhcmQgZXJyb3JzIG9mIHRoZSBsb2dpc3RpYyByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyBmb3IgaW5jb21lIGFuZCBiYWxhbmNlLg0KYGBge3J9DQpib290KGRlZmF1bHRfZGF0YSwgYm9vdC5mbiwgMTAwMCkNCmBgYA0KDQoNCiMjIyMgZCkgQ29tbWVudCBvbiB0aGUgZXN0aW1hdGVkIHN0YW5kYXJkIGVycm9ycyBvYnRhaW5lZCB1c2luZyB0aGUgZ2xtKCkgZnVuY3Rpb24gYW5kIHVzaW5nIHlvdXIgYm9vdHN0cmFwIGZ1bmN0aW9uLg0KDQpUaGUgZXN0aW1hdGVkIHN0YW5kYXJkIGVycm9ycyBvYnRhaW5lZCB1c2luZyB0aGUgYGdsbWAgZnVuY3Rpb24gYXJlIGA0Ljk4NTE2N2UtMDZgIGZvciBpbmNvbWUgYW5kIGAyLjI3MzczMWUtMDRgIGZvciBiYWxhbmNlLiBUaGUgc3RhbmRhcmQgZXJyb3Igb2J0YWluZWQgdXNpbmcgdGhlIGJvb3RzdHJhcCBmdW5jdGlvbiBhcmUgY2xvc2VseSBlcXVpdmFsZW50IC0+IGA0Ljc1OTE4OGUtMDZgIGZvciBpbmNvbWUgYW5kIGAyLjIyMzE3NGUtMDRgIGZvciBiYWxhbmNlLg0KDQoNCiMjIyBQcm9ibGVtIDkNCldlIHdpbGwgbm93IGNvbnNpZGVyIHRoZSBCb3N0b24gaG91c2luZyBkYXRhIHNldCwgZnJvbSB0aGUgTUFTUyBsaWJyYXJ5Lg0KDQojIyMjIGEpIEJhc2VkIG9uIHRoaXMgZGF0YSBzZXQsIHByb3ZpZGUgYW4gZXN0aW1hdGUgZm9yIHRoZSBwb3B1bGF0aW9uIG1lYW4gb2YgbWVkdi4gQ2FsbCB0aGlzIGVzdGltYXRlICRcaGF0e1xtdX0kLg0KYGBge3J9DQpzZXQuc2VlZCgxNykNCmJvc3Rvbl9kYXRhID0gQm9zdG9uDQoobXVfaGF0ID0gbWVhbihib3N0b25fZGF0YSRtZWR2KSkNCmBgYA0KDQoNCiMjIyMgYikgUHJvdmlkZSBhbiBlc3RpbWF0ZSBvZiB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgJFxoYXR7XG11fSQuIEludGVycHJldCB0aGlzIHJlc3VsdC4NCg0KVGhlIHN0YW5kYXJkIGVycm9yIGVzdGltYXRlZCBpcyAwLjQwODg2MTEuIFNpbmNlIGBtZWR2YCByZXByZXNlbnRzIG1lZGlhbiB2YWx1ZSBvZiBob21lcyAoaW4gJDEwMDBzKSwgdGhpcyBtZWFucyB0aGUgc2FtcGxlIG1lYW4gb2YgdGhpcyBkYXRhIHNldCAoMjIuNTMyODEgLT4gMjIsNTMzKSBjb3VsZCBiZSBvZmYgYnkgYWJvdXQgXCQ0MTAgaW4gZWl0aGVyIGRpcmVjdGlvbi4NCmBgYHtyfQ0Kc2QoYm9zdG9uX2RhdGEkbWVkdikgLyBzcXJ0KG5yb3coYm9zdG9uX2RhdGEpKQ0KYGBgDQoNCg0KIyMjIyBjKSBOb3cgZXN0aW1hdGUgdGhlIHN0YW5kYXJkIGVycm9yIG9mICRcaGF0e1xtdX0kIHVzaW5nIHRoZSBib290c3RyYXAuIEhvdyBkb2VzIHRoaXMgY29tcGFyZSB0byB5b3VyIGFuc3dlciBmcm9tIChiKT8NCg0KVGhlIHN0YW5kYXJkIGVycm9yIGVzdGltYXRlZCB1c2luZyBib290c3RyYXAgaXMgMC40MTY4MTU3LCB3aGljaCBpcyBzbGlnaHRseSBsYXJnZXIgdGhhbiB0aGUgc3RhbmRhcmQgZXJyb3IgZXN0aW1hdGVkIGluIHBhcnQgYiAoMC40MDg4NjExKS4NCmBgYHtyfQ0KYm9vdC5mbiA8LSBmdW5jdGlvbihkYXRhLCBpbmRleCkgew0KICByZXR1cm4obWVhbihkYXRhW2luZGV4XSkpDQp9DQpib290KGJvc3Rvbl9kYXRhJG1lZHYsIGJvb3QuZm4sIDEwMDApDQpgYGANCg0KDQojIyMjIGQpIEJhc2VkIG9uIHlvdXIgYm9vdHN0cmFwIGVzdGltYXRlIGZyb20gKGMpLCBwcm92aWRlIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIHRoZSBtZWFuIG9mIG1lZHYuIENvbXBhcmUgaXQgdG8gdGhlIHJlc3VsdHMgb2J0YWluZWQgdXNpbmcgdC50ZXN0KEJvc3RvbiRtZWR2KS4NCg0KVGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsIGJhc2VkIG9uIHRoZSBib290c3RyYXAgZXN0aW1hdGUgZnJvbSAoYykgaXMgKDIxLjcxNTg1LCAyMy4zNDk3NykuIFRoaXMgY29uZmlkZW5jZSBpbnRlcnZhbCBpcyBzbGlnaHRseSB3aWRlciB0aGFuIHRoZSBjb25maWRlbmNlIGludGVydmFsIG9idGFpbmVkIHVzaW5nIHQudGVzdChCb3N0b24kbWVkdikgd2hpY2ggaXMgKDIxLjcyOTUzLCAyMy4zMzYwOCkuIE5vdGU6IHRob3VnaCBub3QgaWRlbnRpY2FsLCB0aGVzZSBjb25maWRlbmNlIGludGVydmFscyBhcmUgdmVyeSBjbG9zZSB0byBlYWNoIG90aGVyDQpgYGB7cn0NCnQudGVzdChib3N0b25fZGF0YSRtZWR2KQ0KIyBJIGFtIGNob29zaW5nIHRvIHVzZSAxLjk2IGluc3RlYWQgb2YgMiB3aGlsZSBjYWxjdWxhdGluZyBteSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCB0byBiZSBtb3JlIHByZWNpc2UNCihjb25mX2ludGVydmFsID0gYyhtdV9oYXQgLSAxLjk2KjAuNDE2ODE1NywgbXVfaGF0ICsgMS45NiowLjQxNjgxNTcpKQ0KYGBgDQoNCg0KIyMjIyBlKSAgQmFzZWQgb24gdGhpcyBkYXRhIHNldCwgcHJvdmlkZSBhbiBlc3RpbWF0ZSwgJFxoYXR7XG11fV97bWVkfSQsIGZvciB0aGUgbWVkaWFuIHZhbHVlIG9mIG1lZHYgaW4gdGhlIHBvcHVsYXRpb24uDQpgYGB7cn0NCihtZWRfaGF0ID0gbWVkaWFuKGJvc3Rvbl9kYXRhJG1lZHYpKQ0KYGBgDQoNCg0KIyMjIyBmKSBXZSBub3cgd291bGQgbGlrZSB0byBlc3RpbWF0ZSB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgJFxoYXR7XG11fV97bWVkfSQuIFVuZm9ydHVuYXRlbHksIHRoZXJlIGlzIG5vIHNpbXBsZSBmb3JtdWxhIGZvciBjb21wdXRpbmcgdGhlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWRpYW4uIEluc3RlYWQsIGVzdGltYXRlIHRoZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVkaWFuIHVzaW5nIHRoZSBib290c3RyYXAuIENvbW1lbnQgb24geW91ciBmaW5kaW5ncy4NCg0KVGhlIHN0YW5kYXJkIGVycm9yIG9mICRcaGF0e1xtdX1fe21lZH0kIGlzIDAuMzkzNTQ3MS4gVGhpcyBpcyBzbGlnaHRseSBsZXNzIHRoYW4gdGhlIHN0YW5kYXJkIGVycm9yIGZvciAkXGhhdHtcbXV9JCB3aGljaCBpbiB0aGVvcnkgbWVhbnMgdGhlIHNhbXBsZSBtZWRpYW4gaXMgbW9yZSBhY2N1cmF0ZSB0byB0aGUgcG9wdWxhdGlvbiBtZWRpYW4uDQpgYGB7cn0NCmJvb3QuZm4gPC0gZnVuY3Rpb24oZGF0YSwgaW5kZXgpIHsNCiAgcmV0dXJuKG1lZGlhbihkYXRhW2luZGV4XSkpDQp9DQpib290KGJvc3Rvbl9kYXRhJG1lZHYsIGJvb3QuZm4sIDEwMDApDQpgYGANCg0KDQojIyMjIGcpIEJhc2VkIG9uIHRoaXMgZGF0YSBzZXQsIHByb3ZpZGUgYW4gZXN0aW1hdGUgZm9yIHRoZSB0ZW50aCBwZXJjZW50aWxlIG9mIG1lZHYgaW4gQm9zdG9uIHN1YnVyYnMuIENhbGwgdGhpcyBxdWFudGl0eSAkXGhhdHtcbXV9X3swLjF9JC4NCmBgYHtyfQ0KKG11X3RlbnRoX3BlcmNlbnRpbGUgPSBxdWFudGlsZShib3N0b25fZGF0YSRtZWR2LCAwLjEpKQ0KYGBgDQoNCg0KIyMjIyBoKSBVc2UgdGhlIGJvb3RzdHJhcCB0byBlc3RpbWF0ZSB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgJFxoYXR7XG11fV97MC4xfSQuIENvbW1lbnQgb24geW91ciBmaW5kaW5ncy4NCg0KVGhlIHN0YW5kYXJkIGVycm9yIG9mICRcaGF0e1xtdX1fezAuMX0kIGlzIDAuNDg5Njg3OC4NCmBgYHtyfQ0KYm9vdC5mbiA8LSBmdW5jdGlvbihkYXRhLCBpbmRleCkgew0KICByZXR1cm4ocXVhbnRpbGUoZGF0YVtpbmRleF0sIDAuMSkpDQp9DQpib290KGJvc3Rvbl9kYXRhJG1lZHYsIGJvb3QuZm4sIDEwMDApDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==