Question 1
fir <- read.csv("HW6data.csv")
a.
counts <- fir %>% group_by(y) %>% summarise(n = n(), proportion = n() / 659)
counts
# A tibble: 2 × 3
y n proportion
<chr> <int> <dbl>
1 No 426 0.646
2 Yes 233 0.354
fir$y <- as.factor(fir$y)
b.
set.seed(1)
kGrid <- expand.grid(k = seq(1, 30, by = 2))
fitControl <- trainControl(method = "cv", number = 10)
model.knn <- train(y ~.,
data = fir,
method = "knn",
trControl = fitControl,
tuneGrid = kGrid)
model.knn
k-Nearest Neighbors
659 samples
2 predictor
2 classes: 'No', 'Yes'
No pre-processing
Resampling: Cross-Validated (10 fold)
Summary of sample sizes: 594, 592, 594, 593, 592, 594, ...
Resampling results across tuning parameters:
k Accuracy Kappa
1 0.7449097 0.4448469
3 0.7934920 0.5383872
5 0.7816456 0.5109847
7 0.7937682 0.5351687
9 0.8090603 0.5703620
11 0.8013913 0.5521750
13 0.8028146 0.5538941
15 0.8012994 0.5502945
17 0.8012768 0.5496301
19 0.7996924 0.5499072
21 0.7846533 0.5185537
23 0.7800838 0.5109016
25 0.7740452 0.5024982
27 0.7709682 0.4944898
29 0.7770522 0.5091332
Accuracy was used to select the optimal model using the largest value.
The final value used for the model was k = 9.
Highest accuracy (0.8090603) when k = 9. When k = 9, the model
correctly predicted whether the tree survived or died 80.91% of the
time.
c.
The kappa statistic is lower than the accuracy due to slight class
imbalance. The kappa statistic takes into account the accuracy that
would be generated simply by chance. Since there is two options, no or
yes, the model could simply guess and get 50% accuracy. Since there are
more trees that survived (no) than died (yes), the model could choose no
for every tree and get 65% accuracy. The kappa statistic takes all of
this into account.
d.
predict(model.knn, fir[1, ])
[1] No
Levels: No Yes
d <- as.matrix(dist(fir[ , -3]))
e.
fir$y[order(d[1,])[2:10]]
[1] No No No No No No Yes No No
Levels: No Yes
8 no’s and 1 yes
f.
set.seed(1)
model.knn.s <- train(y ~.,
data = fir,
method = "knn",
preProc = c("center", "scale"),
trControl = fitControl,
tuneGrid = kGrid)
model.knn.s
k-Nearest Neighbors
659 samples
2 predictor
2 classes: 'No', 'Yes'
Pre-processing: centered (2), scaled (2)
Resampling: Cross-Validated (10 fold)
Summary of sample sizes: 594, 592, 594, 593, 592, 594, ...
Resampling results across tuning parameters:
k Accuracy Kappa
1 0.7524629 0.4543978
3 0.7874095 0.5238633
5 0.7997843 0.5474779
7 0.7982232 0.5468836
9 0.8074526 0.5656214
11 0.8150983 0.5812651
13 0.8089225 0.5649740
15 0.8196218 0.5887324
17 0.8226295 0.5948393
19 0.8181293 0.5860307
21 0.8181978 0.5858372
23 0.8272223 0.6048862
25 0.8257297 0.6012081
27 0.8271764 0.6021629
29 0.8240994 0.5961436
Accuracy was used to select the optimal model using the largest value.
The final value used for the model was k = 23.
The new best test accuracy (0.8272223) is when k = 23. D was measured
in cm and S was measured in units, so both were on completely different
scales. Centering the data turns it into distances from the average and
then scaling turns those distances into the same unit. This puts D and S
on the same scale. Now a value 1 std dev above the mean for D and for S
will be labeled as a 1.
g.
set.seed(1)
model.logit <- train(data = fir,
y ~ .,
method = "glm",
family = "binomial",
trControl = fitControl)
model.logit
Generalized Linear Model
659 samples
2 predictor
2 classes: 'No', 'Yes'
No pre-processing
Resampling: Cross-Validated (10 fold)
Summary of sample sizes: 594, 592, 594, 593, 592, 594, ...
Resampling results:
Accuracy Kappa
0.8134015 0.5736139
The new test accuracy is 0.8134015.
summary(model.logit)
Call:
NULL
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -5.2238 0.3902 -13.387 <2e-16 ***
D 0.2850 0.0290 9.828 <2e-16 ***
S 4.4242 0.5037 8.784 <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: 856.21 on 658 degrees of freedom
Residual deviance: 582.66 on 656 degrees of freedom
AIC: 588.66
Number of Fisher Scoring iterations: 5
The coefficient for D is 0.2850. When all other variables are held
constant, a 1 unit increase in D increases the log-odds of the outcome
by 0.2850.
h.
predict(model.logit, newdata = data.frame(D = 10, S = 0.40), type = "prob")
No Yes
1 0.6466098 0.3533902
The probability this tree will die is 0.353390. The odds the tree
dies is 0.3533902/0.6466098 = 0.547. For every 1 tree that survives,
about 0.547 trees die.
i.
predict(model.logit, newdata = data.frame(D = 11, S = 0.40), type = "prob")
No Yes
1 0.5791239 0.4208761
In part (g), we stated “When all other variables are held constant, a
1 unit increase in D increases the log-odds of the outcome by 0.2850.
Since S was held constant and D increased by 1 unit, we would expect the
log-odds to increase by 0.2850. The math below proves this is the
case.
d10 <- log(0.3533902/0.6466098)
d11 <- log(0.4208761/0.5791239)
d11 - d10
[1] 0.2849922
j.
set.seed(1)
grid <- expand.grid(
usekernel = FALSE, # Use Normal instead of KDE
fL = 0, # Laplace correction
adjust = 1 # Bandwidth adjustment factor
)
model.nb <- train(data = fir,
y ~ .,
method = "nb",
trControl = fitControl,
tuneGrid = grid)
model.nb
Naive Bayes
659 samples
2 predictor
2 classes: 'No', 'Yes'
No pre-processing
Resampling: Cross-Validated (10 fold)
Summary of sample sizes: 594, 592, 594, 593, 592, 594, ...
Resampling results:
Accuracy Kappa
0.8013235 0.5422791
Tuning parameter 'fL' was held constant at a value of 0
Tuning
parameter 'usekernel' was held constant at a value of FALSE
Tuning
parameter 'adjust' was held constant at a value of 1
The test accuracy was 0.8013235.
k.
table <- fir %>% group_by(y) %>% summarise(meanD = mean(D), stdD = sd(D), meanS = mean(S), stdS = sd(S))
table
# A tibble: 2 × 5
y meanD stdD meanS stdS
<fct> <dbl> <dbl> <dbl> <dbl>
1 No 8.01 3.31 0.313 0.189
2 Yes 12.8 4.89 0.520 0.216
fir[1,]
D S y
1 9 0.024212 No
Probabilities of getting obs1 if no were true
dnorm(9, mean = 8.005869, sd = 3.311916)
[1] 0.1151504
dnorm(0.024212, mean = 0.3128129, sd = 0.1891409)
[1] 0.6585027
Probabilities of getting obs1 if yes were true
dnorm(9, mean = 12.798283, sd = 4.889300)
[1] 0.06034118
dnorm(0.024212, mean = 0.5195392, sd = 0.2162452)
[1] 0.1338578
Probability of being in No vs Yes
pNo <- mean(fir$y == "No") * 0.1151504 * 0.6585027
pNo
[1] 0.04901705
pYes <- mean(fir$y == "Yes") * 0.06034118 * 0.1338578
pYes
[1] 0.002855801
The probability of being in class No when D = 9 and S = 0.024212 is
higher than the probability of being in class Yes. So the tree
survived.
l
KNN estimates probability based on nearby points by looking at the k
closest observations and taking the proportion of those that fall into
each class. Logistic regression models the probability directly by
plugging the predictors into a linear equation and passing it through a
function to keep it between 0 and 1. Naive Bayes calculates the
probability by checking how likely the feature values are under each
class using distributions, then combining those and comparing across
classes, assuming the features are independent.
LS0tCnRpdGxlOiAiSG9tZXdvcmsgNiIKYXV0aG9yOiAiQ2hhcmxpZSBNb3JnYW4iCmRhdGU6ICIgRHVlOiAwNC8yNi8yNiIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRvY19jb2xsYXBzZWQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIHNtb290aF9zY3JvbGw6IHllcwogICAgdGhlbWU6IGx1bWVuCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBmaWdfd2lkdGg6IDMKICAgIGZpZ19oZWlnaHQ6IDMKICB3b3JkX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGtlZXBfbWQ6IHllcwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0KI1RPQzo6YmVmb3JlIHsKICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtc2l6ZTogMS4yZW07CiAgZGlzcGxheTogYmxvY2s7CiAgY29sb3I6IG5hdnk7CiAgbWFyZ2luLWJvdHRvbTogMTBweDsKfQoKCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47CiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7CiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOwogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOwp9CgpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLwogIGZvbnQtc2l6ZTogMjJweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwp9CgpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMTVweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBuYXZ5OwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDIwcHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTZweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTRweDsKICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsKICBjb250ZW50OiAiLiI7Cgpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQoKLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0KCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9Cgp9CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCmlmICghcmVxdWlyZSgia25pdHIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpCiAgIGxpYnJhcnkoa25pdHIpCn0KaWYgKCFyZXF1aXJlKCJmYWN0b2V4dHJhIikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJmYWN0b2V4dHJhIikKICBsaWJyYXJ5KGZhY3RvZXh0cmEpCn0KCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQogIGxpYnJhcnkodGlkeXZlcnNlKQp9CgppZiAoIXJlcXVpcmUoIkZhY3RvTWluZVIiKSkgewogIGluc3RhbGwucGFja2FnZXMoIkZhY3RvTWluZVIiKQogIGxpYnJhcnkoRmFjdG9NaW5lUikKfQoKaWYgKCFyZXF1aXJlKCJjb3JycGxvdCIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiY29ycnBsb3QiKQogIGxpYnJhcnkoY29ycnBsb3QpCn0KCmlmICghcmVxdWlyZSgibWljZSIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygibWljZSIpCiAgbGlicmFyeShtaWNlKQp9CgppZiAoIXJlcXVpcmUoImthYmxlRXh0cmEiKSkgewogIGluc3RhbGwucGFja2FnZXMoImthYmxlRXh0cmEiKQogIGxpYnJhcnkoa2FibGVFeHRyYSkKfQoKaWYgKCFyZXF1aXJlKCJjbHVzdGVyIikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJjbHVzdGVyIikKICBsaWJyYXJ5KGNsdXN0ZXIpCn0KCmlmICghcmVxdWlyZSgibWNsdXN0IikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJtY2x1c3QiKQogIGxpYnJhcnkobWNsdXN0KQp9CgppZiAoIXJlcXVpcmUoImRic2NhbiIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiZGJzY2FuIikKICBsaWJyYXJ5KGRic2NhbikKfQoKaWYgKCFyZXF1aXJlKCJjYXJldCIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQogIGxpYnJhcnkoY2FyZXQpCn0KIyMjIwprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgICMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgKSAgCgpgYGAKCiMgUXVlc3Rpb24gMQpgYGB7cn0KZmlyIDwtIHJlYWQuY3N2KCJIVzZkYXRhLmNzdiIpCmBgYAoKIyMgYS4KYGBge3J9CmNvdW50cyA8LSBmaXIgJT4lIGdyb3VwX2J5KHkpICU+JSBzdW1tYXJpc2UobiA9IG4oKSwgcHJvcG9ydGlvbiA9IG4oKSAvIDY1OSkKY291bnRzCmZpciR5IDwtIGFzLmZhY3RvcihmaXIkeSkKYGBgCgojIyBiLgpgYGB7cn0Kc2V0LnNlZWQoMSkKa0dyaWQgPC0gZXhwYW5kLmdyaWQoayA9IHNlcSgxLCAzMCwgYnkgPSAyKSkKZml0Q29udHJvbCA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyID0gMTApCgptb2RlbC5rbm4gPC0gdHJhaW4oeSB+LiwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGZpciwKICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImtubiIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IGZpdENvbnRyb2wsCiAgICAgICAgICAgICAgICAgICAgICAgIHR1bmVHcmlkID0ga0dyaWQpCm1vZGVsLmtubgpgYGAKSGlnaGVzdCBhY2N1cmFjeSAoMC44MDkwNjAzKSB3aGVuIGsgPSA5LiBXaGVuIGsgPSA5LCB0aGUgbW9kZWwgY29ycmVjdGx5IHByZWRpY3RlZCB3aGV0aGVyIHRoZSB0cmVlIHN1cnZpdmVkIG9yIGRpZWQgODAuOTElIG9mIHRoZSB0aW1lLgoKIyMgYy4KVGhlIGthcHBhIHN0YXRpc3RpYyBpcyBsb3dlciB0aGFuIHRoZSBhY2N1cmFjeSBkdWUgdG8gc2xpZ2h0IGNsYXNzIGltYmFsYW5jZS4gVGhlIGthcHBhIHN0YXRpc3RpYyB0YWtlcyBpbnRvIGFjY291bnQgdGhlIGFjY3VyYWN5IHRoYXQgd291bGQgYmUgZ2VuZXJhdGVkIHNpbXBseSBieSBjaGFuY2UuIFNpbmNlIHRoZXJlIGlzIHR3byBvcHRpb25zLCBubyBvciB5ZXMsIHRoZSBtb2RlbCBjb3VsZCBzaW1wbHkgZ3Vlc3MgYW5kIGdldCA1MCUgYWNjdXJhY3kuIFNpbmNlIHRoZXJlIGFyZSBtb3JlIHRyZWVzIHRoYXQgc3Vydml2ZWQgKG5vKSB0aGFuIGRpZWQgKHllcyksIHRoZSBtb2RlbCBjb3VsZCBjaG9vc2Ugbm8gZm9yIGV2ZXJ5IHRyZWUgYW5kIGdldCA2NSUgYWNjdXJhY3kuIFRoZSBrYXBwYSBzdGF0aXN0aWMgdGFrZXMgYWxsIG9mIHRoaXMgaW50byBhY2NvdW50LgoKIyMgZC4KYGBge3J9CnByZWRpY3QobW9kZWwua25uLCBmaXJbMSwgXSkKZCA8LSBhcy5tYXRyaXgoZGlzdChmaXJbICwgLTNdKSkKYGBgCgojIyBlLgpgYGB7cn0KZmlyJHlbb3JkZXIoZFsxLF0pWzI6MTBdXQpgYGAKOCBubydzIGFuZCAxIHllcwoKIyMgZi4KYGBge3J9CnNldC5zZWVkKDEpCm1vZGVsLmtubi5zIDwtIHRyYWluKHkgfi4sCiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBmaXIsCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJrbm4iLAogICAgICAgICAgICAgICAgICAgICAgICBwcmVQcm9jID0gYygiY2VudGVyIiwgInNjYWxlIiksCiAgICAgICAgICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IGZpdENvbnRyb2wsCiAgICAgICAgICAgICAgICAgICAgICAgIHR1bmVHcmlkID0ga0dyaWQpCm1vZGVsLmtubi5zCmBgYApUaGUgbmV3IGJlc3QgdGVzdCBhY2N1cmFjeSAoMC44MjcyMjIzKSBpcyB3aGVuIGsgPSAyMy4gRCB3YXMgbWVhc3VyZWQgaW4gY20gYW5kIFMgd2FzIG1lYXN1cmVkIGluIHVuaXRzLCBzbyBib3RoIHdlcmUgb24gY29tcGxldGVseSBkaWZmZXJlbnQgc2NhbGVzLiBDZW50ZXJpbmcgdGhlIGRhdGEgdHVybnMgaXQgaW50byBkaXN0YW5jZXMgZnJvbSB0aGUgYXZlcmFnZSBhbmQgdGhlbiBzY2FsaW5nIHR1cm5zIHRob3NlIGRpc3RhbmNlcyBpbnRvIHRoZSBzYW1lIHVuaXQuIFRoaXMgcHV0cyBEIGFuZCBTIG9uIHRoZSBzYW1lIHNjYWxlLiBOb3cgYSB2YWx1ZSAxIHN0ZCBkZXYgYWJvdmUgdGhlIG1lYW4gZm9yIEQgYW5kIGZvciBTIHdpbGwgYmUgbGFiZWxlZCBhcyBhIDEuCgojIyBnLgpgYGB7cn0Kc2V0LnNlZWQoMSkKbW9kZWwubG9naXQgPC0gdHJhaW4oZGF0YSA9IGZpciwKICAgICAgICAgICAgICAgICAgICAgeSB+IC4sCiAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG0iLAogICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLAogICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBmaXRDb250cm9sKQptb2RlbC5sb2dpdApgYGAKVGhlIG5ldyB0ZXN0IGFjY3VyYWN5IGlzIDAuODEzNDAxNS4gCgpgYGB7cn0Kc3VtbWFyeShtb2RlbC5sb2dpdCkKYGBgClRoZSBjb2VmZmljaWVudCBmb3IgRCBpcyAwLjI4NTAuIFdoZW4gYWxsIG90aGVyIHZhcmlhYmxlcyBhcmUgaGVsZCBjb25zdGFudCwgYSAxIHVuaXQgaW5jcmVhc2UgaW4gRCBpbmNyZWFzZXMgdGhlIGxvZy1vZGRzIG9mIHRoZSBvdXRjb21lIGJ5IDAuMjg1MC4KCiMjIGguCmBgYHtyfQpwcmVkaWN0KG1vZGVsLmxvZ2l0LCBuZXdkYXRhID0gZGF0YS5mcmFtZShEID0gMTAsIFMgPSAwLjQwKSwgdHlwZSA9ICJwcm9iIikKYGBgClRoZSBwcm9iYWJpbGl0eSB0aGlzIHRyZWUgd2lsbCBkaWUgaXMgMC4zNTMzOTAuIFRoZSBvZGRzIHRoZSB0cmVlIGRpZXMgaXMgMC4zNTMzOTAyLzAuNjQ2NjA5OCA9IDAuNTQ3LiBGb3IgZXZlcnkgMSB0cmVlIHRoYXQgc3Vydml2ZXMsIGFib3V0IDAuNTQ3IHRyZWVzIGRpZS4KCiMjIGkuCmBgYHtyfQpwcmVkaWN0KG1vZGVsLmxvZ2l0LCBuZXdkYXRhID0gZGF0YS5mcmFtZShEID0gMTEsIFMgPSAwLjQwKSwgdHlwZSA9ICJwcm9iIikKYGBgCkluIHBhcnQgKGcpLCB3ZSBzdGF0ZWQgIldoZW4gYWxsIG90aGVyIHZhcmlhYmxlcyBhcmUgaGVsZCBjb25zdGFudCwgYSAxIHVuaXQgaW5jcmVhc2UgaW4gRCBpbmNyZWFzZXMgdGhlIGxvZy1vZGRzIG9mIHRoZSBvdXRjb21lIGJ5IDAuMjg1MC4gU2luY2UgUyB3YXMgaGVsZCBjb25zdGFudCBhbmQgRCBpbmNyZWFzZWQgYnkgMSB1bml0LCB3ZSB3b3VsZCBleHBlY3QgdGhlIGxvZy1vZGRzIHRvIGluY3JlYXNlIGJ5IDAuMjg1MC4gVGhlIG1hdGggYmVsb3cgcHJvdmVzIHRoaXMgaXMgdGhlIGNhc2UuCmBgYHtyfQpkMTAgPC0gbG9nKDAuMzUzMzkwMi8wLjY0NjYwOTgpCmQxMSA8LSBsb2coMC40MjA4NzYxLzAuNTc5MTIzOSkKZDExIC0gZDEwCmBgYAoKIyMgai4KYGBge3J9CnNldC5zZWVkKDEpCgpncmlkIDwtIGV4cGFuZC5ncmlkKAogIHVzZWtlcm5lbCA9IEZBTFNFLCAjIFVzZSBOb3JtYWwgaW5zdGVhZCBvZiBLREUKICBmTCA9IDAsICMgTGFwbGFjZSBjb3JyZWN0aW9uCiAgYWRqdXN0ID0gMSAjIEJhbmR3aWR0aCBhZGp1c3RtZW50IGZhY3RvcgopCgptb2RlbC5uYiA8LSB0cmFpbihkYXRhID0gZmlyLAogICAgICAgICAgICAgICAgICB5IH4gLiwKICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIm5iIiwKICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gZml0Q29udHJvbCwKICAgICAgICAgICAgICAgICAgdHVuZUdyaWQgPSBncmlkKQptb2RlbC5uYgpgYGAKVGhlIHRlc3QgYWNjdXJhY3kgd2FzIDAuODAxMzIzNS4KCiMjIGsuCmBgYHtyfQp0YWJsZSA8LSBmaXIgJT4lIGdyb3VwX2J5KHkpICU+JSBzdW1tYXJpc2UobWVhbkQgPSBtZWFuKEQpLCBzdGREID0gc2QoRCksIG1lYW5TID0gbWVhbihTKSwgc3RkUyA9IHNkKFMpKQp0YWJsZQpgYGAKYGBge3J9CmZpclsxLF0KYGBgClByb2JhYmlsaXRpZXMgb2YgZ2V0dGluZyBvYnMxIGlmIG5vIHdlcmUgdHJ1ZQpgYGB7cn0KZG5vcm0oOSwgbWVhbiA9IDguMDA1ODY5LCBzZCA9IDMuMzExOTE2KQpkbm9ybSgwLjAyNDIxMiwgbWVhbiA9IDAuMzEyODEyOSwgc2QgPSAwLjE4OTE0MDkpCmBgYApQcm9iYWJpbGl0aWVzIG9mIGdldHRpbmcgb2JzMSBpZiB5ZXMgd2VyZSB0cnVlCmBgYHtyfQpkbm9ybSg5LCBtZWFuID0gMTIuNzk4MjgzLCBzZCA9IDQuODg5MzAwKQpkbm9ybSgwLjAyNDIxMiwgbWVhbiA9IDAuNTE5NTM5Miwgc2QgPSAwLjIxNjI0NTIpCmBgYApQcm9iYWJpbGl0eSBvZiBiZWluZyBpbiBObyB2cyBZZXMKYGBge3J9CnBObyA8LSBtZWFuKGZpciR5ID09ICJObyIpICogMC4xMTUxNTA0ICogMC42NTg1MDI3CnBObwpwWWVzIDwtIG1lYW4oZmlyJHkgPT0gIlllcyIpICogMC4wNjAzNDExOCAqIDAuMTMzODU3OApwWWVzCmBgYApUaGUgcHJvYmFiaWxpdHkgb2YgYmVpbmcgaW4gY2xhc3MgTm8gd2hlbiBEID0gOSBhbmQgUyA9IDAuMDI0MjEyIGlzIGhpZ2hlciB0aGFuIHRoZSBwcm9iYWJpbGl0eSBvZiBiZWluZyBpbiBjbGFzcyBZZXMuIFNvIHRoZSB0cmVlIHN1cnZpdmVkLgoKIyMgbApLTk4gZXN0aW1hdGVzIHByb2JhYmlsaXR5IGJhc2VkIG9uIG5lYXJieSBwb2ludHMgYnkgbG9va2luZyBhdCB0aGUgayBjbG9zZXN0IG9ic2VydmF0aW9ucyBhbmQgdGFraW5nIHRoZSBwcm9wb3J0aW9uIG9mIHRob3NlIHRoYXQgZmFsbCBpbnRvIGVhY2ggY2xhc3MuIExvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxzIHRoZSBwcm9iYWJpbGl0eSBkaXJlY3RseSBieSBwbHVnZ2luZyB0aGUgcHJlZGljdG9ycyBpbnRvIGEgbGluZWFyIGVxdWF0aW9uIGFuZCBwYXNzaW5nIGl0IHRocm91Z2ggYSBmdW5jdGlvbiB0byBrZWVwIGl0IGJldHdlZW4gMCBhbmQgMS4gTmFpdmUgQmF5ZXMgY2FsY3VsYXRlcyB0aGUgcHJvYmFiaWxpdHkgYnkgY2hlY2tpbmcgaG93IGxpa2VseSB0aGUgZmVhdHVyZSB2YWx1ZXMgYXJlIHVuZGVyIGVhY2ggY2xhc3MgdXNpbmcgZGlzdHJpYnV0aW9ucywgdGhlbiBjb21iaW5pbmcgdGhvc2UgYW5kIGNvbXBhcmluZyBhY3Jvc3MgY2xhc3NlcywgYXNzdW1pbmcgdGhlIGZlYXR1cmVzIGFyZSBpbmRlcGVuZGVudC4=