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=