Problem 2
For parts (a) through (c), indicate which of i. through iv.
is correct. Justify your answer.
(a) The lasso, relative to least squares, is:
i. More flexible and hence will give improved prediction
accuracy when its increase in bias is less than its decrease in
variance.
ii. More flexible and hence will give improved prediction
accuracy when its increase in variance is less than its decrease in
bias.
iii. Less flexible and hence will give improved prediction
accuracy when its increase in bias is less than its decrease in
variance.
iv. Less flexible and hence will give improved prediction
accuracy when its increase in variance is less than its decrease in
bias.
- iii is correct. Compared to least Squares, The
Lasso adds a penalty to the regression coefficients,
shrinking some toward zero and even setting some exactly to zero. That
makes the model less flexible, higher bias because of the constrained
coefficients and lower variance because it’s less sensitive to training
data.
(b) Repeat (a) for ridge regression relative to least
squares.
- iii is correct. Ridge regression works the same way
as the lasso in this regard. It shrinks coefficients toward zero but
never actually zero, making it less flexible than least squares.With the
same high bias and low variance trade off.
(c) Repeat (a) for non-linear methods relative to least
squares.
- ii is correct. Non-linear methods are different
though, they are more flexible than least squares. With the increase in
flexibility it will make the bias decrease and the variance increase.
They work better when the decrease in bias is larger then the increase
in variance, especially when the relationship in not linear.
Problem 9
In this exercise, we will predict the number of applications
received using the other variables in the College data set.
(a) Split the data set into a training set and a test
set.
library(ISLR2)
library(glmnet)
library(pls)
set.seed(1)
n <- nrow(College)
train_idx <- sample(1:n, size = floor(0.60 * n))
college_train <- College[train_idx, ]
college_test <- College[-train_idx, ]
(b) Fit a linear model using least squares on the training
set, and report the test error obtained.
lm_fit <- lm(Apps ~ ., data = college_train)
lm_pred <- predict(lm_fit, college_test)
mean((lm_pred - college_test$Apps)^2)
[1] 1124482
(c) Fit a ridge regression model on the training set, with λ
chosen by cross-validation. Report the test error obtained.
x_train <- model.matrix(Apps ~ ., college_train)[, -1]
y_train <- college_train$Apps
x_test <- model.matrix(Apps ~ ., college_test)[, -1]
y_test <- college_test$Apps
set.seed(1)
cv_ridge <- cv.glmnet(x_train, y_train, alpha = 0)
best_lam <- cv_ridge$lambda.min
ridge_pred <- predict(cv_ridge, s = best_lam, newx = x_test)
ridge_mse <- mean((ridge_pred - y_test)^2)
cat("Best Lam:", best_lam, "\n")
Best Lam: 382.881
cat("Ridge test MSE:", ridge_mse, "\n")
Ridge test MSE: 1032921
(d) Fit a lasso model on the training set, with λ chosen by
cross-validation. Report the test error obtained, along with the number
of non-zero coefficient estimates.
set.seed(1)
cv_lasso <- cv.glmnet(x_train, y_train, alpha = 1)
best_lam_lasso <- cv_lasso$lambda.min
lasso_pred <- predict(cv_lasso, s = best_lam_lasso, newx = x_test)
lasso_mse <- mean((lasso_pred - y_test)^2)
lasso_coef <- predict(cv_lasso,type = "coefficients", s = best_lam_lasso)
nonzero <- sum(lasso_coef != 0) - 1
cat("Best Lam:", best_lam_lasso, "\n")
Best Lam: 17.36319
cat("Lasso test MSE:", lasso_mse, "\n")
Lasso test MSE: 1076820
cat("Number fo non-zero coef:", nonzero, "\n")
Number fo non-zero coef: 13
(e) Fit a PCR model on the training set, with M chosen by
cross-validation. Report the test error obtained, along with the value
of M selected by cross-validation.
set.seed(1)
pcr_fit <- pcr(Apps ~ ., data = college_train, scale = TRUE, validation = "CV")
validationplot(pcr_fit, val.type = "MSEP")

summary(pcr_fit)
Data: X dimension: 466 17
Y dimension: 466 1
Fit method: svdpc
Number of components considered: 17
VALIDATION: RMSEP
Cross-validated using 10 random segments.
(Intercept) 1 comps 2 comps 3 comps 4 comps 5 comps 6 comps 7 comps 8 comps 9 comps 10 comps
CV 4061 3921 2228 2215 1942 1781 1773 1757 1724 1668 1652
adjCV 4061 3920 2224 2213 1920 1774 1768 1767 1710 1663 1646
11 comps 12 comps 13 comps 14 comps 15 comps 16 comps 17 comps
CV 1650 1659 1653 1680 1655 1242 1209
adjCV 1645 1653 1648 1684 1635 1230 1199
TRAINING: % variance explained
1 comps 2 comps 3 comps 4 comps 5 comps 6 comps 7 comps 8 comps 9 comps 10 comps 11 comps
X 32.483 57.59 64.96 70.64 75.98 80.99 84.43 87.80 90.66 92.92 95.01
Apps 8.553 71.18 71.47 80.53 82.20 82.57 82.66 84.02 84.54 84.94 84.95
12 comps 13 comps 14 comps 15 comps 16 comps 17 comps
X 96.78 97.82 98.69 99.37 99.85 100.00
Apps 84.99 85.19 85.23 89.92 93.18 93.39
# Select M with lowest CV error
cv_errs <- MSEP(pcr_fit)$val[1, 1, ]
best_M <- which.min(cv_errs[-1]) # exclude intercept-only
pcr_pred <- predict(pcr_fit, college_test, ncomp = best_M)
pcr_mse <- mean((pcr_pred - college_test$Apps)^2)
cat("Best M (PCR):", best_M, "\n")
Best M (PCR): 17
cat("PCR Test MSE:", pcr_mse, "\n")
PCR Test MSE: 1124482
(f) Fit a PLS model on the training set, with M chosen by
cross-validation. Report the test error obtained, along with the value
of M selected by cross-validation.
set.seed(1)
pls_fit <- plsr(Apps ~ ., data = college_train, scale = TRUE, validation = "CV")
validationplot(pls_fit, val.type = "MSEP")

summary(pls_fit)
Data: X dimension: 466 17
Y dimension: 466 1
Fit method: kernelpls
Number of components considered: 17
VALIDATION: RMSEP
Cross-validated using 10 random segments.
(Intercept) 1 comps 2 comps 3 comps 4 comps 5 comps 6 comps 7 comps 8 comps 9 comps 10 comps
CV 4061 2058 1844 1586 1536 1404 1286 1246 1223 1215 1213
adjCV 4061 2053 1838 1578 1514 1384 1269 1233 1212 1204 1202
11 comps 12 comps 13 comps 14 comps 15 comps 16 comps 17 comps
CV 1214 1211 1210 1209 1209 1209 1209
adjCV 1203 1200 1199 1199 1199 1199 1199
TRAINING: % variance explained
1 comps 2 comps 3 comps 4 comps 5 comps 6 comps 7 comps 8 comps 9 comps 10 comps 11 comps
X 26.31 50.01 62.94 65.76 70.18 74.34 77.94 81.22 83.06 86.39 89.37
Apps 75.94 81.67 87.08 90.72 92.44 93.14 93.24 93.29 93.34 93.36 93.37
12 comps 13 comps 14 comps 15 comps 16 comps 17 comps
X 91.15 92.33 94.24 97.03 98.16 100.00
Apps 93.38 93.39 93.39 93.39 93.39 93.39
cv_errs_pls <- MSEP(pls_fit)$val[1, 1, ]
best_M_pls <- which.min(cv_errs_pls[-1])
pls_pred <- predict(pls_fit, college_test, ncomp = best_M_pls)
pls_mse <- mean((pls_pred - college_test$Apps)^2)
cat("Best M (PLS):", best_M_pls, "\n")
Best M (PLS): 15
cat("PLS Test MSE:", pls_mse, "\n")
PLS Test MSE: 1124526
(g) Comment on the results obtained. How accurately can we
predict the number of college applications received? Is there much
difference among the test errors resulting from these five
approaches?
- The different methods produced similar test MSE values, all
performed similarly when predicting the number of college applications
received. Ridge regression had the lowest test MSE (1032921), followed
by lasso (1076820), while PCR and PLS had slightly higher errors (around
1124000). Overall, the models were able to predict applications
reasonably well, but no single method provided a major improvement over
the others.
Problem 11
(a) Try out some of the regression methods explored in this
chapter, such as best subset selection, the lasso, ridge regression, and
PCR. Present and discuss results for the approaches that you
consider.
library(leaps)
set.seed(1)
n_bos <- nrow(Boston)
bos_train_idx <- sample(1:n_bos, size = floor(0.65 * n_bos))
bos_train <- Boston[bos_train_idx, ]
bos_test <- Boston[-bos_train_idx, ]
x_bos_train <- model.matrix(crim ~ ., bos_train)[, -1]
y_bos_train <- bos_train$crim
x_bos_test <- model.matrix(crim ~ ., bos_test)[, -1]
y_bos_test <- bos_test$crim
-Best Subset
regfit.full <- regsubsets(crim ~ ., data = bos_train, nvmax = 12)
regfit.summary <- summary(regfit_full)
par(mfrow=c(2,2))
par(mfrow=c(2,2 ))
plot(regfit.summary$rss,xlab ="Number of Variables", ylab = "RSS", type = "l")
plot(regfit.summary$adjr2,xlab ="Number of Variables", ylab = "adjr2", type = "l")
which.max(regfit.summary$adjr2)
[1] 8
points(11,regfit.summary$adjr2[11],col='red', cex=2,pch=20)
plot(regfit.summary$cp,xlab ="Number of Variables", ylab = "cp", type = "l")
which.min(regfit.summary$cp)
[1] 6
points(10,regfit.summary$cp[10],col='red', cex=2,pch=20)
plot(regfit.summary$bic,xlab ="Number of Variables", ylab = "bic", type = "l")
which.min(regfit.summary$bic)
[1] 2
points(6,regfit.summary$bic[6],col='red', cex=2,pch=20)

test_mat <- model.matrix(crim ~ ., data = bos_test)
best_size <- 11
best_coef <- coef(regfit.full, id = best_size)
best_pred <- test_mat[, names(best_coef)] %*% best_coef
best_subset_mse <- mean((bos_test$crim - best_pred)^2)
best_subset_mse
[1] 50.2209
-Lasso
# Lasso
grid <- 10^seq(10, -2, length = 100)
lasso_mod <- glmnet(x_bos_train, y_bos_train, alpha = 1, lambda = grid)
set.seed(1)
cv_lasso_bos <- cv.glmnet(x_bos_train, y_bos_train, alpha = 1)
best_lam_boslasso <- cv_lasso_bos$lambda.min
lasso_pred_bos <- predict(lasso_mod, s = best_lam_boslasso, newx = x_bos_test)
lasso_mse_bos <- mean((lasso_pred_bos - y_bos_test)^2)
lasso_coef_bos <- predict(lasso_mod, s = cv_lasso_bos$lambda.min, type = "coefficients")
nonzero_bos <- sum(lasso_coef_bos != 0) -1
best_lam_boslasso
[1] 0.0422181
lasso_mse_bos
[1] 50.5437
lasso_coef_bos
13 x 1 sparse Matrix of class "dgCMatrix"
s=0.0422181
(Intercept) 9.15341877
zn 0.03465035
indus -0.08413468
chas -0.74979794
nox -5.49801258
rm 0.17307922
age .
dis -0.65772034
rad 0.52416009
tax .
ptratio -0.29138583
lstat 0.23187008
medv -0.13506184
nonzero_bos
[1] 10
-PCR
# PCR
set.seed(1)
pcr_bos <- pcr(crim ~ ., data = bos_train, scale = TRUE, validation = "CV")
validationplot(pcr_bos, val.type = "MSEP")

cv_errs_bos <- MSEP(pcr_bos)$val[1, 1, ]
best_M_bos <- which.min(cv_errs_bos[-1])
pcr_pred_bos <- predict(pcr_bos, bos_test, ncomp = best_M_bos)
pcr_mse_bos <- mean((pcr_pred_bos - bos_test$crim)^2)
cat("Best M (PCR):", best_M_bos, "\n")
Best M (PCR): 12
cat("PCR Test MSE:", pcr_mse_bos, "\n")
PCR Test MSE: 50.22142
- The three methods produced similar test MSE values on the data,
meaning they performed similarly when predicting crime rate. Both the
subset and lasso reduced the number of predictors in the model to come
up with there better predictions. PCR used combinations of the original
predictors instead of selecting individual variables.
(b) Propose a model (or set of models) that seem to perform
well on this data set, and justify your answer. Make sure that you are
evaluating model performance using validation set error,
cross-validation, or some other reasonable alternative, as opposed to
using training error.
comparison <- data.frame(
Method = c("Best Subset", "Lasso", "PCR"),
Test_MSE = c(best_subset_mse, lasso_mse_bos, pcr_mse_bos)
)
comparison
- Based on the test results, I would choose the PCR model as the best
approach because it has the lowest MSE. However, the differences between
the models were super small, all three methods performed similarly when
predicting new data. Best subset selection and lasso produced simpler
models that are easier to interpret, while PCR provided slightly better
prediction performance. Overall, PCR would be the preferred model for
prediction, while lasso or best subset could be useful if interpret
ability is more important.
(c) Does your chosen model involve all of the features in the
data set? Why or why not?
- No. The PCR model does not use the original features. It combines
the features into a smaller number of principal components that capture
the most important patterns in the data. This allows the model to use
the information from many variables while reducing unnecessary
complexity. PCR was chosen because it provided the lowest test MSE,
meaning it performed slightly better at predicting crime rate on new
data.
LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQ1Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMjIFByb2JsZW0gMg0KDQpfX0ZvciBwYXJ0cyAoYSkgdGhyb3VnaCAoYyksIGluZGljYXRlIHdoaWNoIG9mIGkuIHRocm91Z2ggaXYuIGlzIGNvcnJlY3QuIEp1c3RpZnkgeW91ciBhbnN3ZXIuX18NCg0KX18oYSkgVGhlIGxhc3NvLCByZWxhdGl2ZSB0byBsZWFzdCBzcXVhcmVzLCBpczpfXw0KDQogIF9faS4gTW9yZSBmbGV4aWJsZSBhbmQgaGVuY2Ugd2lsbCBnaXZlIGltcHJvdmVkIHByZWRpY3Rpb24gYWNjdXJhY3kgd2hlbiBpdHMgaW5jcmVhc2UgaW4gYmlhcyBpcyBsZXNzIHRoYW4gaXRzIGRlY3JlYXNlIGluIHZhcmlhbmNlLl9fDQoNCiAgX19paS4gTW9yZSBmbGV4aWJsZSBhbmQgaGVuY2Ugd2lsbCBnaXZlIGltcHJvdmVkIHByZWRpY3Rpb24gYWNjdXJhY3kgd2hlbiBpdHMgaW5jcmVhc2UgaW4gdmFyaWFuY2UgaXMgbGVzcyB0aGFuIGl0cyBkZWNyZWFzZSBpbiBiaWFzLl9fDQoNCiAgX19paWkuIExlc3MgZmxleGlibGUgYW5kIGhlbmNlIHdpbGwgZ2l2ZSBpbXByb3ZlZCBwcmVkaWN0aW9uIGFjY3VyYWN5IHdoZW4gaXRzIGluY3JlYXNlIGluIGJpYXMgaXMgbGVzcyB0aGFuIGl0cyBkZWNyZWFzZSBpbiB2YXJpYW5jZS5fXw0KDQogIF9faXYuIExlc3MgZmxleGlibGUgYW5kIGhlbmNlIHdpbGwgZ2l2ZSBpbXByb3ZlZCBwcmVkaWN0aW9uIGFjY3VyYWN5IHdoZW4gaXRzIGluY3JlYXNlIGluIHZhcmlhbmNlIGlzIGxlc3MgdGhhbiBpdHMgZGVjcmVhc2UgaW4gYmlhcy5fXw0KDQogIC0gKippaWkgaXMgY29ycmVjdC4qKiBDb21wYXJlZCB0byBsZWFzdCBTcXVhcmVzLCBUaGUgKipMYXNzbyoqIGFkZHMgYSBwZW5hbHR5IHRvIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50cywgc2hyaW5raW5nIHNvbWUgdG93YXJkIHplcm8gYW5kIGV2ZW4gc2V0dGluZyBzb21lIGV4YWN0bHkgdG8gemVyby4gVGhhdCBtYWtlcyB0aGUgbW9kZWwgbGVzcyBmbGV4aWJsZSwgaGlnaGVyIGJpYXMgYmVjYXVzZSBvZiB0aGUgY29uc3RyYWluZWQgY29lZmZpY2llbnRzIGFuZCBsb3dlciB2YXJpYW5jZSBiZWNhdXNlIGl0J3MgbGVzcyBzZW5zaXRpdmUgdG8gdHJhaW5pbmcgZGF0YS4NCg0KX18oYikgUmVwZWF0IChhKSBmb3IgcmlkZ2UgcmVncmVzc2lvbiByZWxhdGl2ZSB0byBsZWFzdCBzcXVhcmVzLl9fDQoNCiAgLSAqKmlpaSBpcyBjb3JyZWN0LioqIFJpZGdlIHJlZ3Jlc3Npb24gd29ya3MgdGhlIHNhbWUgd2F5IGFzIHRoZSBsYXNzbyBpbiB0aGlzIHJlZ2FyZC4gSXQgc2hyaW5rcyBjb2VmZmljaWVudHMgdG93YXJkIHplcm8gYnV0IG5ldmVyIGFjdHVhbGx5IHplcm8sIG1ha2luZyBpdCBsZXNzIGZsZXhpYmxlIHRoYW4gbGVhc3Qgc3F1YXJlcy5XaXRoIHRoZSBzYW1lIGhpZ2ggYmlhcyBhbmQgbG93IHZhcmlhbmNlIHRyYWRlIG9mZi4NCg0KX18oYykgUmVwZWF0IChhKSBmb3Igbm9uLWxpbmVhciBtZXRob2RzIHJlbGF0aXZlIHRvIGxlYXN0IHNxdWFyZXMuX18NCg0KICAtICoqaWkgaXMgY29ycmVjdC4qKiBOb24tbGluZWFyIG1ldGhvZHMgYXJlIGRpZmZlcmVudCB0aG91Z2gsIHRoZXkgYXJlIG1vcmUgZmxleGlibGUgdGhhbiBsZWFzdCBzcXVhcmVzLiBXaXRoIHRoZSBpbmNyZWFzZSBpbiBmbGV4aWJpbGl0eSBpdCB3aWxsIG1ha2UgdGhlIGJpYXMgZGVjcmVhc2UgYW5kIHRoZSB2YXJpYW5jZSBpbmNyZWFzZS4gVGhleSB3b3JrIGJldHRlciB3aGVuIHRoZSBkZWNyZWFzZSBpbiBiaWFzIGlzIGxhcmdlciB0aGVuIHRoZSBpbmNyZWFzZSBpbiB2YXJpYW5jZSwgZXNwZWNpYWxseSB3aGVuIHRoZSByZWxhdGlvbnNoaXAgaW4gbm90IGxpbmVhci4gDQogIA0KLS0tDQoNCiMjIyBQcm9ibGVtIDkNCg0KX19JbiB0aGlzIGV4ZXJjaXNlLCB3ZSB3aWxsIHByZWRpY3QgdGhlIG51bWJlciBvZiBhcHBsaWNhdGlvbnMgcmVjZWl2ZWQgdXNpbmcgdGhlIG90aGVyIHZhcmlhYmxlcyBpbiB0aGUgQ29sbGVnZSBkYXRhIHNldC5fXw0KDQpfXyhhKSBTcGxpdCB0aGUgZGF0YSBzZXQgaW50byBhIHRyYWluaW5nIHNldCBhbmQgYSB0ZXN0IHNldC5fXw0KYGBge3J9DQpsaWJyYXJ5KElTTFIyKQ0KbGlicmFyeShnbG1uZXQpDQpsaWJyYXJ5KHBscykNCg0Kc2V0LnNlZWQoMSkNCm4gPC0gbnJvdyhDb2xsZWdlKQ0KdHJhaW5faWR4IDwtIHNhbXBsZSgxOm4sIHNpemUgPSBmbG9vcigwLjYwICogbikpDQpjb2xsZWdlX3RyYWluIDwtIENvbGxlZ2VbdHJhaW5faWR4LCBdDQpjb2xsZWdlX3Rlc3QgIDwtIENvbGxlZ2VbLXRyYWluX2lkeCwgXQ0KYGBgDQoNCl9fKGIpIEZpdCBhIGxpbmVhciBtb2RlbCB1c2luZyBsZWFzdCBzcXVhcmVzIG9uIHRoZSB0cmFpbmluZyBzZXQsIGFuZCByZXBvcnQgdGhlIHRlc3QgZXJyb3Igb2J0YWluZWQuX18NCmBgYHtyfQ0KbG1fZml0ICA8LSBsbShBcHBzIH4gLiwgZGF0YSA9IGNvbGxlZ2VfdHJhaW4pDQpsbV9wcmVkIDwtIHByZWRpY3QobG1fZml0LCBjb2xsZWdlX3Rlc3QpDQptZWFuKChsbV9wcmVkIC0gY29sbGVnZV90ZXN0JEFwcHMpXjIpDQoNCmBgYA0KDQoNCl9fKGMpIEZpdCBhIHJpZGdlIHJlZ3Jlc3Npb24gbW9kZWwgb24gdGhlIHRyYWluaW5nIHNldCwgd2l0aCDOuyBjaG9zZW4gYnkgY3Jvc3MtdmFsaWRhdGlvbi4gUmVwb3J0IHRoZSB0ZXN0IGVycm9yIG9idGFpbmVkLl9fDQpgYGB7cn0NCnhfdHJhaW4gPC0gbW9kZWwubWF0cml4KEFwcHMgfiAuLCBjb2xsZWdlX3RyYWluKVssIC0xXQ0KeV90cmFpbiA8LSBjb2xsZWdlX3RyYWluJEFwcHMNCnhfdGVzdCAgPC0gbW9kZWwubWF0cml4KEFwcHMgfiAuLCBjb2xsZWdlX3Rlc3QpWywgLTFdDQp5X3Rlc3QgIDwtIGNvbGxlZ2VfdGVzdCRBcHBzDQoNCnNldC5zZWVkKDEpDQpjdl9yaWRnZSAgIDwtIGN2LmdsbW5ldCh4X3RyYWluLCB5X3RyYWluLCBhbHBoYSA9IDApDQpiZXN0X2xhbSA8LSBjdl9yaWRnZSRsYW1iZGEubWluDQoNCnJpZGdlX3ByZWQgPC0gcHJlZGljdChjdl9yaWRnZSwgcyA9IGJlc3RfbGFtLCBuZXd4ID0geF90ZXN0KQ0KcmlkZ2VfbXNlICA8LSBtZWFuKChyaWRnZV9wcmVkIC0geV90ZXN0KV4yKQ0KDQpjYXQoIkJlc3QgTGFtOiIsIGJlc3RfbGFtLCAiXG4iKQ0KY2F0KCJSaWRnZSB0ZXN0IE1TRToiLCByaWRnZV9tc2UsICJcbiIpDQoNCmBgYA0KDQoNCl9fKGQpIEZpdCBhIGxhc3NvIG1vZGVsIG9uIHRoZSB0cmFpbmluZyBzZXQsIHdpdGggzrsgY2hvc2VuIGJ5IGNyb3NzLXZhbGlkYXRpb24uIFJlcG9ydCB0aGUgdGVzdCBlcnJvciBvYnRhaW5lZCwgYWxvbmcgd2l0aCB0aGUgbnVtYmVyIG9mIG5vbi16ZXJvIGNvZWZmaWNpZW50IGVzdGltYXRlcy5fXw0KYGBge3J9DQpzZXQuc2VlZCgxKQ0KY3ZfbGFzc28gICA8LSBjdi5nbG1uZXQoeF90cmFpbiwgeV90cmFpbiwgYWxwaGEgPSAxKQ0KYmVzdF9sYW1fbGFzc28gPC0gY3ZfbGFzc28kbGFtYmRhLm1pbg0KDQpsYXNzb19wcmVkIDwtIHByZWRpY3QoY3ZfbGFzc28sIHMgPSBiZXN0X2xhbV9sYXNzbywgbmV3eCA9IHhfdGVzdCkNCmxhc3NvX21zZSAgPC0gbWVhbigobGFzc29fcHJlZCAtIHlfdGVzdCleMikNCg0KbGFzc29fY29lZiA8LSBwcmVkaWN0KGN2X2xhc3NvLHR5cGUgPSAiY29lZmZpY2llbnRzIiwgcyA9IGJlc3RfbGFtX2xhc3NvKQ0Kbm9uemVybyAgICA8LSBzdW0obGFzc29fY29lZiAhPSAwKSAtIDEgDQoNCmNhdCgiQmVzdCBMYW06IiwgYmVzdF9sYW1fbGFzc28sICJcbiIpDQpjYXQoIkxhc3NvIHRlc3QgTVNFOiIsIGxhc3NvX21zZSwgIlxuIikNCmNhdCgiTnVtYmVyIGZvIG5vbi16ZXJvIGNvZWY6Iiwgbm9uemVybywgIlxuIikNCmBgYA0KDQoNCl9fKGUpIEZpdCBhIFBDUiBtb2RlbCBvbiB0aGUgdHJhaW5pbmcgc2V0LCB3aXRoIE0gY2hvc2VuIGJ5IGNyb3NzLXZhbGlkYXRpb24uIFJlcG9ydCB0aGUgdGVzdCBlcnJvciBvYnRhaW5lZCwgYWxvbmcgd2l0aCB0aGUgdmFsdWUgb2YgTSBzZWxlY3RlZCBieSBjcm9zcy12YWxpZGF0aW9uLl9fDQpgYGB7cn0NCnNldC5zZWVkKDEpDQpwY3JfZml0IDwtIHBjcihBcHBzIH4gLiwgZGF0YSA9IGNvbGxlZ2VfdHJhaW4sIHNjYWxlID0gVFJVRSwgdmFsaWRhdGlvbiA9ICJDViIpDQp2YWxpZGF0aW9ucGxvdChwY3JfZml0LCB2YWwudHlwZSA9ICJNU0VQIikNCnN1bW1hcnkocGNyX2ZpdCkNCmBgYA0KDQpgYGB7cn0NCiMgU2VsZWN0IE0gd2l0aCBsb3dlc3QgQ1YgZXJyb3INCmN2X2VycnMgPC0gTVNFUChwY3JfZml0KSR2YWxbMSwgMSwgXQ0KYmVzdF9NICA8LSB3aGljaC5taW4oY3ZfZXJyc1stMV0pICAjIGV4Y2x1ZGUgaW50ZXJjZXB0LW9ubHkNCg0KcGNyX3ByZWQgPC0gcHJlZGljdChwY3JfZml0LCBjb2xsZWdlX3Rlc3QsIG5jb21wID0gYmVzdF9NKQ0KcGNyX21zZSAgPC0gbWVhbigocGNyX3ByZWQgLSBjb2xsZWdlX3Rlc3QkQXBwcyleMikNCg0KY2F0KCJCZXN0IE0gKFBDUik6IiwgYmVzdF9NLCAiXG4iKQ0KY2F0KCJQQ1IgVGVzdCBNU0U6IiwgcGNyX21zZSwgIlxuIikNCmBgYA0KDQoNCl9fKGYpIEZpdCBhIFBMUyBtb2RlbCBvbiB0aGUgdHJhaW5pbmcgc2V0LCB3aXRoIE0gY2hvc2VuIGJ5IGNyb3NzLXZhbGlkYXRpb24uIFJlcG9ydCB0aGUgdGVzdCBlcnJvciBvYnRhaW5lZCwgYWxvbmcgd2l0aCB0aGUgdmFsdWUgb2YgTSBzZWxlY3RlZCBieSBjcm9zcy12YWxpZGF0aW9uLl9fDQpgYGB7cn0NCnNldC5zZWVkKDEpDQpwbHNfZml0IDwtIHBsc3IoQXBwcyB+IC4sIGRhdGEgPSBjb2xsZWdlX3RyYWluLCBzY2FsZSA9IFRSVUUsIHZhbGlkYXRpb24gPSAiQ1YiKQ0KdmFsaWRhdGlvbnBsb3QocGxzX2ZpdCwgdmFsLnR5cGUgPSAiTVNFUCIpDQpzdW1tYXJ5KHBsc19maXQpDQpgYGANCg0KYGBge3J9DQpjdl9lcnJzX3BscyA8LSBNU0VQKHBsc19maXQpJHZhbFsxLCAxLCBdDQpiZXN0X01fcGxzICA8LSB3aGljaC5taW4oY3ZfZXJyc19wbHNbLTFdKQ0KDQpwbHNfcHJlZCA8LSBwcmVkaWN0KHBsc19maXQsIGNvbGxlZ2VfdGVzdCwgbmNvbXAgPSBiZXN0X01fcGxzKQ0KcGxzX21zZSAgPC0gbWVhbigocGxzX3ByZWQgLSBjb2xsZWdlX3Rlc3QkQXBwcyleMikNCg0KY2F0KCJCZXN0IE0gKFBMUyk6IiwgYmVzdF9NX3BscywgIlxuIikNCmNhdCgiUExTIFRlc3QgTVNFOiIsIHBsc19tc2UsICJcbiIpDQpgYGANCg0KDQpfXyhnKSBDb21tZW50IG9uIHRoZSByZXN1bHRzIG9idGFpbmVkLiBIb3cgYWNjdXJhdGVseSBjYW4gd2UgcHJlZGljdCB0aGUgbnVtYmVyIG9mIGNvbGxlZ2UgYXBwbGljYXRpb25zIHJlY2VpdmVkPyBJcyB0aGVyZSBtdWNoIGRpZmZlcmVuY2UgYW1vbmcgdGhlIHRlc3QgZXJyb3JzIHJlc3VsdGluZyBmcm9tIHRoZXNlIGZpdmUgYXBwcm9hY2hlcz9fXw0KDQogIC0gVGhlIGRpZmZlcmVudCBtZXRob2RzIHByb2R1Y2VkIHNpbWlsYXIgdGVzdCBNU0UgdmFsdWVzLCBhbGwgcGVyZm9ybWVkIHNpbWlsYXJseSB3aGVuIHByZWRpY3RpbmcgdGhlIG51bWJlciBvZiBjb2xsZWdlIGFwcGxpY2F0aW9ucyByZWNlaXZlZC4gUmlkZ2UgcmVncmVzc2lvbiBoYWQgdGhlIGxvd2VzdCB0ZXN0IE1TRSAoMTAzMjkyMSksIGZvbGxvd2VkIGJ5IGxhc3NvICgxMDc2ODIwKSwgd2hpbGUgUENSIGFuZCBQTFMgaGFkIHNsaWdodGx5IGhpZ2hlciBlcnJvcnMgKGFyb3VuZCAxMTI0MDAwKS4gT3ZlcmFsbCwgdGhlIG1vZGVscyB3ZXJlIGFibGUgdG8gcHJlZGljdCBhcHBsaWNhdGlvbnMgcmVhc29uYWJseSB3ZWxsLCBidXQgbm8gc2luZ2xlIG1ldGhvZCBwcm92aWRlZCBhIG1ham9yIGltcHJvdmVtZW50IG92ZXIgdGhlIG90aGVycy4gDQogIA0KLS0tDQoNCiMjIyBQcm9ibGVtIDExDQoNCg0KX18oYSkgVHJ5IG91dCBzb21lIG9mIHRoZSByZWdyZXNzaW9uIG1ldGhvZHMgZXhwbG9yZWQgaW4gdGhpcyBjaGFwdGVyLCBzdWNoIGFzIGJlc3Qgc3Vic2V0IHNlbGVjdGlvbiwgdGhlIGxhc3NvLCByaWRnZSByZWdyZXNzaW9uLCBhbmQgUENSLiBQcmVzZW50IGFuZCBkaXNjdXNzIHJlc3VsdHMgZm9yIHRoZSBhcHByb2FjaGVzIHRoYXQgeW91IGNvbnNpZGVyLl9fDQpgYGB7cn0NCmxpYnJhcnkobGVhcHMpDQoNCnNldC5zZWVkKDEpDQpuX2JvcyA8LSBucm93KEJvc3RvbikNCmJvc190cmFpbl9pZHggPC0gc2FtcGxlKDE6bl9ib3MsIHNpemUgPSBmbG9vcigwLjY1ICogbl9ib3MpKQ0KYm9zX3RyYWluIDwtIEJvc3Rvbltib3NfdHJhaW5faWR4LCBdDQpib3NfdGVzdCAgPC0gQm9zdG9uWy1ib3NfdHJhaW5faWR4LCBdDQoNCnhfYm9zX3RyYWluIDwtIG1vZGVsLm1hdHJpeChjcmltIH4gLiwgYm9zX3RyYWluKVssIC0xXQ0KeV9ib3NfdHJhaW4gPC0gYm9zX3RyYWluJGNyaW0NCnhfYm9zX3Rlc3QgIDwtIG1vZGVsLm1hdHJpeChjcmltIH4gLiwgYm9zX3Rlc3QpWywgLTFdDQp5X2Jvc190ZXN0ICA8LSBib3NfdGVzdCRjcmltDQpgYGANCg0KICAtKipCZXN0IFN1YnNldCoqDQoNCmBgYHtyfQ0KcmVnZml0LmZ1bGwgPC0gcmVnc3Vic2V0cyhjcmltIH4gLiwgZGF0YSA9IGJvc190cmFpbiwgbnZtYXggPSAxMikgDQpyZWdmaXQuc3VtbWFyeSA8LSBzdW1tYXJ5KHJlZ2ZpdF9mdWxsKSANCnBhcihtZnJvdz1jKDIsMikpDQoNCnBhcihtZnJvdz1jKDIsMiApKQ0KcGxvdChyZWdmaXQuc3VtbWFyeSRyc3MseGxhYiA9Ik51bWJlciBvZiBWYXJpYWJsZXMiLCB5bGFiID0gIlJTUyIsIHR5cGUgPSAibCIpDQpwbG90KHJlZ2ZpdC5zdW1tYXJ5JGFkanIyLHhsYWIgPSJOdW1iZXIgb2YgVmFyaWFibGVzIiwgeWxhYiA9ICJhZGpyMiIsIHR5cGUgPSAibCIpDQp3aGljaC5tYXgocmVnZml0LnN1bW1hcnkkYWRqcjIpDQpwb2ludHMoMTEscmVnZml0LnN1bW1hcnkkYWRqcjJbMTFdLGNvbD0ncmVkJywgY2V4PTIscGNoPTIwKQ0KcGxvdChyZWdmaXQuc3VtbWFyeSRjcCx4bGFiID0iTnVtYmVyIG9mIFZhcmlhYmxlcyIsIHlsYWIgPSAiY3AiLCB0eXBlID0gImwiKQ0Kd2hpY2gubWluKHJlZ2ZpdC5zdW1tYXJ5JGNwKQ0KcG9pbnRzKDEwLHJlZ2ZpdC5zdW1tYXJ5JGNwWzEwXSxjb2w9J3JlZCcsIGNleD0yLHBjaD0yMCkNCnBsb3QocmVnZml0LnN1bW1hcnkkYmljLHhsYWIgPSJOdW1iZXIgb2YgVmFyaWFibGVzIiwgeWxhYiA9ICJiaWMiLCB0eXBlID0gImwiKQ0Kd2hpY2gubWluKHJlZ2ZpdC5zdW1tYXJ5JGJpYykNCnBvaW50cyg2LHJlZ2ZpdC5zdW1tYXJ5JGJpY1s2XSxjb2w9J3JlZCcsIGNleD0yLHBjaD0yMCkNCg0KdGVzdF9tYXQgPC0gbW9kZWwubWF0cml4KGNyaW0gfiAuLCBkYXRhID0gYm9zX3Rlc3QpDQpiZXN0X3NpemUgPC0gMTEgIA0KYmVzdF9jb2VmIDwtIGNvZWYocmVnZml0LmZ1bGwsIGlkID0gYmVzdF9zaXplKQ0KYmVzdF9wcmVkIDwtIHRlc3RfbWF0WywgbmFtZXMoYmVzdF9jb2VmKV0gJSolIGJlc3RfY29lZg0KYmVzdF9zdWJzZXRfbXNlIDwtIG1lYW4oKGJvc190ZXN0JGNyaW0gLSBiZXN0X3ByZWQpXjIpDQpiZXN0X3N1YnNldF9tc2UNCg0KYGBgDQoNCg0KICAtKipMYXNzbyoqDQoNCmBgYHtyfQ0KIyBMYXNzbw0KZ3JpZCA8LSAxMF5zZXEoMTAsIC0yLCBsZW5ndGggPSAxMDApDQpsYXNzb19tb2QgPC0gZ2xtbmV0KHhfYm9zX3RyYWluLCB5X2Jvc190cmFpbiwgYWxwaGEgPSAxLCBsYW1iZGEgPSBncmlkKQ0KDQpzZXQuc2VlZCgxKQ0KY3ZfbGFzc29fYm9zIDwtIGN2LmdsbW5ldCh4X2Jvc190cmFpbiwgeV9ib3NfdHJhaW4sIGFscGhhID0gMSkNCg0KYmVzdF9sYW1fYm9zbGFzc28gPC0gY3ZfbGFzc29fYm9zJGxhbWJkYS5taW4NCmxhc3NvX3ByZWRfYm9zIDwtIHByZWRpY3QobGFzc29fbW9kLCBzID0gYmVzdF9sYW1fYm9zbGFzc28sIG5ld3ggPSB4X2Jvc190ZXN0KQ0KbGFzc29fbXNlX2JvcyA8LSBtZWFuKChsYXNzb19wcmVkX2JvcyAtIHlfYm9zX3Rlc3QpXjIpDQpsYXNzb19jb2VmX2JvcyA8LSBwcmVkaWN0KGxhc3NvX21vZCwgcyA9IGN2X2xhc3NvX2JvcyRsYW1iZGEubWluLCB0eXBlID0gImNvZWZmaWNpZW50cyIpDQpub256ZXJvX2JvcyA8LSBzdW0obGFzc29fY29lZl9ib3MgIT0gMCkgLTENCg0KYmVzdF9sYW1fYm9zbGFzc28gDQpsYXNzb19tc2VfYm9zIA0KbGFzc29fY29lZl9ib3MgDQpub256ZXJvX2JvcyANCmBgYA0KICAtKipQQ1IqKg0KDQpgYGB7cn0NCiMgUENSDQpzZXQuc2VlZCgxKQ0KcGNyX2JvcyA8LSBwY3IoY3JpbSB+IC4sIGRhdGEgPSBib3NfdHJhaW4sIHNjYWxlID0gVFJVRSwgdmFsaWRhdGlvbiA9ICJDViIpDQp2YWxpZGF0aW9ucGxvdChwY3JfYm9zLCB2YWwudHlwZSA9ICJNU0VQIikNCg0KY3ZfZXJyc19ib3MgPC0gTVNFUChwY3JfYm9zKSR2YWxbMSwgMSwgXQ0KYmVzdF9NX2JvcyAgPC0gd2hpY2gubWluKGN2X2VycnNfYm9zWy0xXSkNCg0KcGNyX3ByZWRfYm9zIDwtIHByZWRpY3QocGNyX2JvcywgYm9zX3Rlc3QsIG5jb21wID0gYmVzdF9NX2JvcykNCnBjcl9tc2VfYm9zICA8LSBtZWFuKChwY3JfcHJlZF9ib3MgLSBib3NfdGVzdCRjcmltKV4yKQ0KDQpjYXQoIkJlc3QgTSAoUENSKToiLCBiZXN0X01fYm9zLCAiXG4iKQ0KY2F0KCJQQ1IgVGVzdCBNU0U6IiwgcGNyX21zZV9ib3MsICJcbiIpDQpgYGANCg0KICAtIFRoZSB0aHJlZSBtZXRob2RzIHByb2R1Y2VkIHNpbWlsYXIgdGVzdCBNU0UgdmFsdWVzIG9uIHRoZSBkYXRhLCBtZWFuaW5nIHRoZXkgcGVyZm9ybWVkIHNpbWlsYXJseSB3aGVuIHByZWRpY3RpbmcgY3JpbWUgcmF0ZS4gQm90aCB0aGUgc3Vic2V0IGFuZCBsYXNzbyByZWR1Y2VkIHRoZSBudW1iZXIgb2YgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwgdG8gY29tZSB1cCB3aXRoIHRoZXJlIGJldHRlciBwcmVkaWN0aW9ucy4gUENSIHVzZWQgY29tYmluYXRpb25zIG9mIHRoZSBvcmlnaW5hbCBwcmVkaWN0b3JzIGluc3RlYWQgb2Ygc2VsZWN0aW5nIGluZGl2aWR1YWwgdmFyaWFibGVzLg0KDQoNCl9fKGIpIFByb3Bvc2UgYSBtb2RlbCAob3Igc2V0IG9mIG1vZGVscykgdGhhdCBzZWVtIHRvIHBlcmZvcm0gd2VsbCBvbiB0aGlzIGRhdGEgc2V0LCBhbmQganVzdGlmeSB5b3VyIGFuc3dlci4gTWFrZSBzdXJlIHRoYXQgeW91IGFyZSBldmFsdWF0aW5nIG1vZGVsIHBlcmZvcm1hbmNlIHVzaW5nIHZhbGlkYXRpb24gc2V0IGVycm9yLCBjcm9zcy12YWxpZGF0aW9uLCBvciBzb21lIG90aGVyIHJlYXNvbmFibGUgYWx0ZXJuYXRpdmUsIGFzIG9wcG9zZWQgdG8gdXNpbmcgdHJhaW5pbmcgZXJyb3IuX18NCmBgYHtyfQ0KY29tcGFyaXNvbiA8LSBkYXRhLmZyYW1lKA0KICBNZXRob2QgICA9IGMoIkJlc3QgU3Vic2V0IiwgIkxhc3NvIiwgIlBDUiIpLA0KICBUZXN0X01TRSA9IGMoYmVzdF9zdWJzZXRfbXNlLCBsYXNzb19tc2VfYm9zLCBwY3JfbXNlX2JvcykNCikNCmNvbXBhcmlzb24NCmBgYA0KDQogIC0gQmFzZWQgb24gdGhlIHRlc3QgcmVzdWx0cywgSSB3b3VsZCBjaG9vc2UgdGhlIFBDUiBtb2RlbCBhcyB0aGUgYmVzdCBhcHByb2FjaCBiZWNhdXNlIGl0IGhhcyB0aGUgbG93ZXN0IE1TRS4gSG93ZXZlciwgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIG1vZGVscyB3ZXJlIHN1cGVyIHNtYWxsLCBhbGwgdGhyZWUgbWV0aG9kcyBwZXJmb3JtZWQgc2ltaWxhcmx5IHdoZW4gcHJlZGljdGluZyBuZXcgZGF0YS4gQmVzdCBzdWJzZXQgc2VsZWN0aW9uIGFuZCBsYXNzbyBwcm9kdWNlZCBzaW1wbGVyIG1vZGVscyB0aGF0IGFyZSBlYXNpZXIgdG8gaW50ZXJwcmV0LCB3aGlsZSBQQ1IgcHJvdmlkZWQgc2xpZ2h0bHkgYmV0dGVyIHByZWRpY3Rpb24gcGVyZm9ybWFuY2UuIE92ZXJhbGwsIFBDUiB3b3VsZCBiZSB0aGUgcHJlZmVycmVkIG1vZGVsIGZvciBwcmVkaWN0aW9uLCB3aGlsZSBsYXNzbyBvciBiZXN0IHN1YnNldCBjb3VsZCBiZSB1c2VmdWwgaWYgaW50ZXJwcmV0IGFiaWxpdHkgaXMgbW9yZSBpbXBvcnRhbnQuDQoNCl9fKGMpIERvZXMgeW91ciBjaG9zZW4gbW9kZWwgaW52b2x2ZSBhbGwgb2YgdGhlIGZlYXR1cmVzIGluIHRoZSBkYXRhIHNldD8gV2h5IG9yIHdoeSBub3Q/X18NCg0KICAtIE5vLiBUaGUgUENSIG1vZGVsIGRvZXMgbm90IHVzZSB0aGUgb3JpZ2luYWwgZmVhdHVyZXMuIEl0IGNvbWJpbmVzIHRoZSBmZWF0dXJlcyBpbnRvIGEgc21hbGxlciBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgdGhhdCBjYXB0dXJlIHRoZSBtb3N0IGltcG9ydGFudCBwYXR0ZXJucyBpbiB0aGUgZGF0YS4gVGhpcyBhbGxvd3MgdGhlIG1vZGVsIHRvIHVzZSB0aGUgaW5mb3JtYXRpb24gZnJvbSBtYW55IHZhcmlhYmxlcyB3aGlsZSByZWR1Y2luZyB1bm5lY2Vzc2FyeSBjb21wbGV4aXR5LiBQQ1Igd2FzIGNob3NlbiBiZWNhdXNlIGl0IHByb3ZpZGVkIHRoZSBsb3dlc3QgdGVzdCBNU0UsIG1lYW5pbmcgaXQgcGVyZm9ybWVkIHNsaWdodGx5IGJldHRlciBhdCBwcmVkaWN0aW5nIGNyaW1lIHJhdGUgb24gbmV3IGRhdGEuDQo=