dat <- read.csv("Week2Data.csv")

Questions

a.

dat_new <- dat %>%
filter(dataset == "Cleveland") %>%
select(-id, -dataset) %>%
mutate(num = ifelse(num == 0, "No", "Yes"))

b.

colSums(is.na(dat_new))
     age      sex       cp trestbps     chol      fbs  restecg   thalch 
       0        0        0        0        0        0        0        0 
   exang  oldpeak    slope       ca     thal      num 
       0        0        0        5        0        0 

c.

colSums(is.na(dat_new) | dat_new == "")
     age      sex       cp trestbps     chol      fbs  restecg   thalch 
       0        0        0        0        0        0        0        0 
   exang  oldpeak    slope       ca     thal      num 
       0        0        1        5        3        0 
dat_new$slope <- na_if(dat_new$slope, "")
dat_new$thal <- na_if(dat_new$thal, "")

d.

dat_new <- dat_new %>%
mutate(
across(where(is.character), as.factor),
across(where(is.logical), as.factor)
)

e.

mice_impute <- mice(dat_new, seed = 123)
dat_imp <- complete(mice_impute, 1)

f. 

Age and ca have the strongest positive correlation (0.37), and ca and oldpeak have the second strongest (0.30). age and thalch have the strongest negative correlation (-.40), and thalch and oldpeak have the second strongest (-0.35).

data_numeric <- dat_imp %>%
  select(where(is.numeric))
cor_mat <- cor(data_numeric)
kable(round(cor_mat, 2), format = "html") %>%
  kable_styling(full_width = F, font_size = 10)
age trestbps chol thalch oldpeak ca
age 1.00 0.28 0.23 -0.40 0.21 0.37
trestbps 0.28 1.00 0.13 -0.05 0.19 0.10
chol 0.23 0.13 1.00 -0.01 0.05 0.13
thalch -0.40 -0.05 -0.01 1.00 -0.35 -0.27
oldpeak 0.21 0.19 0.05 -0.35 1.00 0.30
ca 0.37 0.10 0.13 -0.27 0.30 1.00

g.

The first PC alone explains 74.98% of the variation in the original data set. The first and second PC explain 89.92% of the variation in the original data set.

pca <- prcomp(data_numeric)
  names(pca)
[1] "sdev"     "rotation" "center"   "scale"    "x"       
  summary(pca)
Importance of components:
                           PC1     PC2      PC3     PC4     PC5     PC6
Standard deviation     52.2102 23.3079 17.48752 7.66560 1.10732 0.80797
Proportion of Variance  0.7498  0.1494  0.08412 0.01616 0.00034 0.00018
Cumulative Proportion   0.7498  0.8992  0.98332 0.99948 0.99982 1.00000

h.

Chol dominated PC1, thalch dominated PC2, and trestbps dominated PC3. Due to their larger scales, these three variables had the highest variance, resulting in them carrying more weight in PCA. You should also scale variables before running PCA.

pca$rotation[ , 1:3]
                  PC1         PC2          PC3
age      -0.041751366 -0.18400118 -0.126715579
trestbps -0.049911822 -0.10117012 -0.982293036
chol     -0.997827582  0.02252561  0.053193289
thalch    0.009920235  0.97721420 -0.126981652
oldpeak  -0.001303992 -0.01794537 -0.008982926
ca       -0.002374603 -0.01145152 -0.002999127
apply(data_numeric, 2, var)
         age     trestbps         chol       thalch      oldpeak           ca 
  83.7271908  308.7382317 2715.2728852  525.6593712    1.3472012    0.8716237 

i.

sum(apply(data_numeric, 2, var))
[1] 3635.617
sum(apply(pca$x, 2, var))
[1] 3635.617

j.

cor_mat <- cor(pca$x)
kable(round(cor_mat, 2), format = "html") %>%
  kable_styling(full_width = F, font_size = 10)
PC1 PC2 PC3 PC4 PC5 PC6
PC1 1 0 0 0 0 0
PC2 0 1 0 0 0 0
PC3 0 0 1 0 0 0
PC4 0 0 0 1 0 0
PC5 0 0 0 0 1 0
PC6 0 0 0 0 0 1

k.

The first PC explains 34.94% of the variation in the original data set. The first and second PC explain 53.11% of the variation in the original data set. There is a large difference after scaling because the variation of the original features are now more equal, meaning a couple features can no longer have significantly larger variances than the others.

pca_sc <- prcomp(data_numeric, scale = TRUE)
  summary(pca_sc)
Importance of components:
                          PC1    PC2    PC3    PC4    PC5     PC6
Standard deviation     1.4479 1.0442 0.9492 0.8716 0.8427 0.66528
Proportion of Variance 0.3494 0.1817 0.1502 0.1266 0.1184 0.07377
Cumulative Proportion  0.3494 0.5311 0.6813 0.8079 0.9262 1.00000

l.

The angle between age and ca, and the angle between ca and oldpeak are both small due to the larger positive correlation between the variables. The angle between thalch and age, and thalch and oldpeak are closer to 180 degrees due to the larger negative correlation between the variables.The angle between thalch and chol is almost 90 degrees because the variables share no correlation.

fviz_pca_var(pca_sc, col.var = "cos2",
               gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), 
               repel = TRUE)

m.

set.seed(23)
fviz_pca_ind(pca_sc, col.ind = pca_sc$x[,3], 
             select.ind = list(name = sample(1:nrow(dat_imp), 50)), 
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"))

n. 

Yes, they are close to each other.

scale(data_numeric)[c(51, 241), ]
           age  trestbps       chol    thalch    oldpeak         ca
[1,] -1.459191 -1.518655 -0.9272190 0.7971434 -0.8927312  0.3629102
[2,] -1.459191 -1.234094 -0.2171591 0.1429004 -0.8927312 -0.7082033

o.

Observation 3 and 51 have very different age, thalch, and oldpeak scores, and since PC1 or dim1 is heavily influenced by those variables, the observations are very far apart in dim1 of the biplot. Observation 3 is on the negative side of dim1, since its scores are the opposite sign of the weights for those variables (positive/neg score for a negative/pos weight). Observation 51 is on the positive side since its signs are the same (negative/pos score for a negative/pos weight). Observation 3 and 51 have similar chol and trestbps scores, and since PC2 or dim2 is heavily influenced by those variables, the observations aren’t super far apart in dim2 of the biplot. They’re both on the positive side since signs match.

scale(data_numeric)[c(3, 51), ]
           age   trestbps      chol     thalch    oldpeak        ca
[1,]  1.382259 -0.6649732 -0.332304 -0.9038883  1.3473157 1.4340237
[2,] -1.459191 -1.5186551 -0.927219  0.7971434 -0.8927312 0.3629102
pca_sc$rotation
                PC1        PC2        PC3         PC4         PC5        PC6
age      -0.5201885 -0.1508345 -0.1061464 -0.52689267  0.08619213  0.6405785
trestbps -0.2931992 -0.4929706  0.7427019 -0.09308449  0.09143817 -0.3199725
chol     -0.2211667 -0.6739897 -0.5153347  0.28452697 -0.36110251 -0.1410768
thalch    0.4519486 -0.4287149  0.1060637  0.35833169  0.45216554  0.5175338
oldpeak  -0.4284800  0.2840087  0.2906678  0.66220769 -0.29817699  0.3518915
ca       -0.4546105  0.1245371 -0.2753536  0.25659925  0.74863326 -0.2751458

p.

Observation 51 and 174 are on the opposite side of both dims in the biplot. This is due to them having very different scores across all variables, with the exception of thalch. Observation 51 is on the positive side in both dims, and 174 is on the negative, due to the same logic I used in question o.

scale(data_numeric)[c(51, 174), ]
            age   trestbps      chol    thalch    oldpeak         ca
[1,] -1.4591912 -1.5186551 -0.927219 0.7971434 -0.8927312  0.3629102
[2,]  0.8358265  0.4732692  2.834179 0.3173652  0.1411366 -0.7082033

q.

data_cat <- dat_imp %>%
  select(where(is.factor))

he_cont <- xtabs( ~ thal + num, data = data_cat)   
kable(he_cont)
No Yes
fixed defect 6 12
normal 131 37
reversable defect 28 90

r.

Reversable defect has the strongest positive relationship with having heart disease, and normal has the strongest negative relationship. Normal has the strongest positive relationship with no getting heart disease, and reversable defect has the strongest negative relationship.

chi_test <- chisq.test(he_cont)
  chi_test$residuals
                   num
thal                       No       Yes
  fixed defect      -1.206062  1.314027
  normal             4.169611 -4.542868
  reversable defect -4.504136  4.907339

s.

The angle between normal and no is extremely small since they have a strong positive relationship, the same can be said for yes and reversable defect. The angle between the opposites (normal and yes, reversable and no) are near 180 degress since those relationships are strong and negative.

he_ca <- MCA(data_cat[ , 7:8], graph = FALSE) 
fviz_mca_var(he_ca, col.var = "cos2",
             geom.var = c("arrow", "text"),
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"))

t.

Fixed defect is closer to reversable defect since its also positively associated with yes, and negatively associated with no, however the association isn’t as strong.

u.

The variables oldpeak and thalch seem the most associated with num. There also could be some association with ca, slope, exang, cp, and thal.

dat_famd <- FAMD(dat_imp, graph = FALSE)
fviz_famd_var(dat_famd, col.var = "cos2",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE)

v.

The really red points are observations with large positive scores on the third dimension, meaning they align strongly with the variables that load positively on Dim3. The really blue points have large negative Dim3 scores, meaning they align with the opposite pattern (variables with negative loadings on Dim3).

fviz_pca_ind(dat_famd, col.ind = dat_famd$ind$coord[,3],
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"))

LS0tCnRpdGxlOiAiSG9tZXdvcmsgMiIKYXV0aG9yOiAiQ2hhcmxpZSBNb3JnYW4iCmRhdGU6ICIgRHVlOiAwMy8wMS8yNiIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRvY19jb2xsYXBzZWQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIHNtb290aF9zY3JvbGw6IHllcwogICAgdGhlbWU6IGx1bWVuCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBmaWdfd2lkdGg6IDMKICAgIGZpZ19oZWlnaHQ6IDMKICB3b3JkX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGtlZXBfbWQ6IHllcwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0KI1RPQzo6YmVmb3JlIHsKICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtc2l6ZTogMS4yZW07CiAgZGlzcGxheTogYmxvY2s7CiAgY29sb3I6IG5hdnk7CiAgbWFyZ2luLWJvdHRvbTogMTBweDsKfQoKCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47CiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7CiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOwogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOwp9CgpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLwogIGZvbnQtc2l6ZTogMjJweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwp9CgpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMTVweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBuYXZ5OwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDIwcHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTZweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTRweDsKICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsKICBjb250ZW50OiAiLiI7Cgpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQoKLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0KCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9Cgp9CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCmlmICghcmVxdWlyZSgia25pdHIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpCiAgIGxpYnJhcnkoa25pdHIpCn0KaWYgKCFyZXF1aXJlKCJmYWN0b2V4dHJhIikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJmYWN0b2V4dHJhIikKICBsaWJyYXJ5KGZhY3RvZXh0cmEpCn0KCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQogIGxpYnJhcnkodGlkeXZlcnNlKQp9CgppZiAoIXJlcXVpcmUoIkZhY3RvTWluZVIiKSkgewogIGluc3RhbGwucGFja2FnZXMoIkZhY3RvTWluZVIiKQogIGxpYnJhcnkoRmFjdG9NaW5lUikKfQoKaWYgKCFyZXF1aXJlKCJjb3JycGxvdCIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiY29ycnBsb3QiKQogIGxpYnJhcnkoY29ycnBsb3QpCn0KCmlmICghcmVxdWlyZSgibWljZSIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygibWljZSIpCiAgbGlicmFyeShtaWNlKQp9CgppZiAoIXJlcXVpcmUoImthYmxlRXh0cmEiKSkgewogIGluc3RhbGwucGFja2FnZXMoImthYmxlRXh0cmEiKQogIGxpYnJhcnkoa2FibGVFeHRyYSkKfQojIyMjCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIAogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLgogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BCiAgICAgICAgICAgICAgICAgICAgICApICAKCmBgYAoKYGBge3J9CmRhdCA8LSByZWFkLmNzdigiV2VlazJEYXRhLmNzdiIpCmBgYAoKIyBRdWVzdGlvbnMKIyMgYS4KYGBge3J9CmRhdF9uZXcgPC0gZGF0ICU+JQpmaWx0ZXIoZGF0YXNldCA9PSAiQ2xldmVsYW5kIikgJT4lCnNlbGVjdCgtaWQsIC1kYXRhc2V0KSAlPiUKbXV0YXRlKG51bSA9IGlmZWxzZShudW0gPT0gMCwgIk5vIiwgIlllcyIpKQpgYGAKCiMjIGIuCmBgYHtyfQpjb2xTdW1zKGlzLm5hKGRhdF9uZXcpKQpgYGAKCiMjIGMuCmBgYHtyfQpjb2xTdW1zKGlzLm5hKGRhdF9uZXcpIHwgZGF0X25ldyA9PSAiIikKZGF0X25ldyRzbG9wZSA8LSBuYV9pZihkYXRfbmV3JHNsb3BlLCAiIikKZGF0X25ldyR0aGFsIDwtIG5hX2lmKGRhdF9uZXckdGhhbCwgIiIpCmBgYAoKIyMgZC4KYGBge3J9CmRhdF9uZXcgPC0gZGF0X25ldyAlPiUKbXV0YXRlKAphY3Jvc3Mod2hlcmUoaXMuY2hhcmFjdGVyKSwgYXMuZmFjdG9yKSwKYWNyb3NzKHdoZXJlKGlzLmxvZ2ljYWwpLCBhcy5mYWN0b3IpCikKYGBgCgojIyBlLgpgYGB7ciwgcmVzdWx0cyA9ICdoaWRlJ30KbWljZV9pbXB1dGUgPC0gbWljZShkYXRfbmV3LCBzZWVkID0gMTIzKQpkYXRfaW1wIDwtIGNvbXBsZXRlKG1pY2VfaW1wdXRlLCAxKQpgYGAKCiMjIGYuIApBZ2UgYW5kIGNhIGhhdmUgdGhlIHN0cm9uZ2VzdCBwb3NpdGl2ZSBjb3JyZWxhdGlvbiAoMC4zNyksIGFuZCBjYSBhbmQgb2xkcGVhayBoYXZlIHRoZSBzZWNvbmQgc3Ryb25nZXN0ICgwLjMwKS4gYWdlIGFuZCB0aGFsY2ggaGF2ZSB0aGUgc3Ryb25nZXN0IG5lZ2F0aXZlIGNvcnJlbGF0aW9uICgtLjQwKSwgYW5kIHRoYWxjaCBhbmQgb2xkcGVhayBoYXZlIHRoZSBzZWNvbmQgc3Ryb25nZXN0ICgtMC4zNSkuCmBgYHtyfQpkYXRhX251bWVyaWMgPC0gZGF0X2ltcCAlPiUKICBzZWxlY3Qod2hlcmUoaXMubnVtZXJpYykpCmNvcl9tYXQgPC0gY29yKGRhdGFfbnVtZXJpYykKa2FibGUocm91bmQoY29yX21hdCwgMiksIGZvcm1hdCA9ICJodG1sIikgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRiwgZm9udF9zaXplID0gMTApCmBgYAoKIyMgZy4gClRoZSBmaXJzdCBQQyBhbG9uZSBleHBsYWlucyA3NC45OCUgIG9mIHRoZSB2YXJpYXRpb24gaW4gdGhlIG9yaWdpbmFsIGRhdGEgc2V0LiBUaGUgZmlyc3QgYW5kIHNlY29uZCBQQyBleHBsYWluIDg5LjkyJSBvZiB0aGUgdmFyaWF0aW9uIGluIHRoZSBvcmlnaW5hbCBkYXRhIHNldC4KYGBge3J9CnBjYSA8LSBwcmNvbXAoZGF0YV9udW1lcmljKQogIG5hbWVzKHBjYSkKICBzdW1tYXJ5KHBjYSkKYGBgCgojIyBoLiAKQ2hvbCBkb21pbmF0ZWQgUEMxLCB0aGFsY2ggZG9taW5hdGVkIFBDMiwgYW5kIHRyZXN0YnBzIGRvbWluYXRlZCBQQzMuIER1ZSB0byB0aGVpciBsYXJnZXIgc2NhbGVzLCB0aGVzZSB0aHJlZSB2YXJpYWJsZXMgaGFkIHRoZSBoaWdoZXN0IHZhcmlhbmNlLCByZXN1bHRpbmcgaW4gdGhlbSBjYXJyeWluZyBtb3JlIHdlaWdodCBpbiBQQ0EuIFlvdSBzaG91bGQgYWxzbyBzY2FsZSB2YXJpYWJsZXMgYmVmb3JlIHJ1bm5pbmcgUENBLgpgYGB7cn0KcGNhJHJvdGF0aW9uWyAsIDE6M10KYGBgCgpgYGB7cn0KYXBwbHkoZGF0YV9udW1lcmljLCAyLCB2YXIpCmBgYAoKIyMgaS4KYGBge3J9CnN1bShhcHBseShkYXRhX251bWVyaWMsIDIsIHZhcikpCnN1bShhcHBseShwY2EkeCwgMiwgdmFyKSkKYGBgCgojIyBqLgpgYGB7cn0KY29yX21hdCA8LSBjb3IocGNhJHgpCmthYmxlKHJvdW5kKGNvcl9tYXQsIDIpLCBmb3JtYXQgPSAiaHRtbCIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYsIGZvbnRfc2l6ZSA9IDEwKQpgYGAKCiMjIGsuIApUaGUgZmlyc3QgUEMgZXhwbGFpbnMgMzQuOTQlIG9mIHRoZSB2YXJpYXRpb24gaW4gdGhlIG9yaWdpbmFsIGRhdGEgc2V0LiBUaGUgZmlyc3QgYW5kIHNlY29uZCBQQyBleHBsYWluIDUzLjExJSBvZiB0aGUgdmFyaWF0aW9uIGluIHRoZSBvcmlnaW5hbCBkYXRhIHNldC4gVGhlcmUgaXMgYSBsYXJnZSBkaWZmZXJlbmNlIGFmdGVyIHNjYWxpbmcgYmVjYXVzZSB0aGUgdmFyaWF0aW9uIG9mIHRoZSBvcmlnaW5hbCBmZWF0dXJlcyBhcmUgbm93IG1vcmUgZXF1YWwsIG1lYW5pbmcgYSBjb3VwbGUgZmVhdHVyZXMgY2FuIG5vIGxvbmdlciBoYXZlIHNpZ25pZmljYW50bHkgbGFyZ2VyIHZhcmlhbmNlcyB0aGFuIHRoZSBvdGhlcnMuCmBgYHtyfQpwY2Ffc2MgPC0gcHJjb21wKGRhdGFfbnVtZXJpYywgc2NhbGUgPSBUUlVFKQogIHN1bW1hcnkocGNhX3NjKQpgYGAKCiMjIGwuIApUaGUgYW5nbGUgYmV0d2VlbiBhZ2UgYW5kIGNhLCBhbmQgdGhlIGFuZ2xlIGJldHdlZW4gY2EgYW5kIG9sZHBlYWsgYXJlIGJvdGggc21hbGwgZHVlIHRvIHRoZSBsYXJnZXIgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgdmFyaWFibGVzLiBUaGUgYW5nbGUgYmV0d2VlbiB0aGFsY2ggYW5kIGFnZSwgYW5kIHRoYWxjaCBhbmQgb2xkcGVhayBhcmUgY2xvc2VyIHRvIDE4MCBkZWdyZWVzIGR1ZSB0byB0aGUgbGFyZ2VyIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHZhcmlhYmxlcy5UaGUgYW5nbGUgYmV0d2VlbiB0aGFsY2ggYW5kIGNob2wgaXMgYWxtb3N0IDkwIGRlZ3JlZXMgYmVjYXVzZSB0aGUgdmFyaWFibGVzIHNoYXJlIG5vIGNvcnJlbGF0aW9uLgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQpmdml6X3BjYV92YXIocGNhX3NjLCBjb2wudmFyID0gImNvczIiLAogICAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwgCiAgICAgICAgICAgICAgIHJlcGVsID0gVFJVRSkKYGBgCgojIyBtLgpgYGB7cn0Kc2V0LnNlZWQoMjMpCmZ2aXpfcGNhX2luZChwY2Ffc2MsIGNvbC5pbmQgPSBwY2Ffc2MkeFssM10sIAogICAgICAgICAgICAgc2VsZWN0LmluZCA9IGxpc3QobmFtZSA9IHNhbXBsZSgxOm5yb3coZGF0X2ltcCksIDUwKSksIAogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IikpCmBgYAoKIyMgbi4gClllcywgdGhleSBhcmUgY2xvc2UgdG8gZWFjaCBvdGhlci4KYGBge3J9CnNjYWxlKGRhdGFfbnVtZXJpYylbYyg1MSwgMjQxKSwgXQpgYGAKCiMjIG8uIApPYnNlcnZhdGlvbiAzIGFuZCA1MSBoYXZlIHZlcnkgZGlmZmVyZW50IGFnZSwgdGhhbGNoLCBhbmQgb2xkcGVhayBzY29yZXMsIGFuZCBzaW5jZSBQQzEgb3IgZGltMSBpcyBoZWF2aWx5IGluZmx1ZW5jZWQgYnkgdGhvc2UgdmFyaWFibGVzLCB0aGUgb2JzZXJ2YXRpb25zIGFyZSB2ZXJ5IGZhciBhcGFydCBpbiBkaW0xIG9mIHRoZSBiaXBsb3QuIE9ic2VydmF0aW9uIDMgaXMgb24gdGhlIG5lZ2F0aXZlIHNpZGUgb2YgZGltMSwgc2luY2UgaXRzIHNjb3JlcyBhcmUgdGhlIG9wcG9zaXRlIHNpZ24gb2YgdGhlIHdlaWdodHMgZm9yIHRob3NlIHZhcmlhYmxlcyAocG9zaXRpdmUvbmVnIHNjb3JlIGZvciBhIG5lZ2F0aXZlL3BvcyB3ZWlnaHQpLiBPYnNlcnZhdGlvbiA1MSBpcyBvbiB0aGUgcG9zaXRpdmUgc2lkZSBzaW5jZSBpdHMgc2lnbnMgYXJlIHRoZSBzYW1lIChuZWdhdGl2ZS9wb3Mgc2NvcmUgZm9yIGEgbmVnYXRpdmUvcG9zIHdlaWdodCkuIE9ic2VydmF0aW9uIDMgYW5kIDUxIGhhdmUgc2ltaWxhciBjaG9sIGFuZCB0cmVzdGJwcyBzY29yZXMsIGFuZCBzaW5jZSBQQzIgb3IgZGltMiBpcyBoZWF2aWx5IGluZmx1ZW5jZWQgYnkgdGhvc2UgdmFyaWFibGVzLCB0aGUgb2JzZXJ2YXRpb25zIGFyZW4ndCBzdXBlciBmYXIgYXBhcnQgaW4gZGltMiBvZiB0aGUgYmlwbG90LiBUaGV5J3JlIGJvdGggb24gdGhlIHBvc2l0aXZlIHNpZGUgc2luY2Ugc2lnbnMgbWF0Y2guCmBgYHtyfQpzY2FsZShkYXRhX251bWVyaWMpW2MoMywgNTEpLCBdCnBjYV9zYyRyb3RhdGlvbgpgYGAKCiMjIHAuCk9ic2VydmF0aW9uIDUxIGFuZCAxNzQgYXJlIG9uIHRoZSBvcHBvc2l0ZSBzaWRlIG9mIGJvdGggZGltcyBpbiB0aGUgYmlwbG90LiBUaGlzIGlzIGR1ZSB0byB0aGVtIGhhdmluZyB2ZXJ5IGRpZmZlcmVudCBzY29yZXMgYWNyb3NzIGFsbCB2YXJpYWJsZXMsIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiB0aGFsY2guIE9ic2VydmF0aW9uIDUxIGlzIG9uIHRoZSBwb3NpdGl2ZSBzaWRlIGluIGJvdGggZGltcywgYW5kIDE3NCBpcyBvbiB0aGUgbmVnYXRpdmUsIGR1ZSB0byB0aGUgc2FtZSBsb2dpYyBJIHVzZWQgaW4gcXVlc3Rpb24gby4KYGBge3J9CnNjYWxlKGRhdGFfbnVtZXJpYylbYyg1MSwgMTc0KSwgXQpgYGAKCiMjIHEuCmBgYHtyfQpkYXRhX2NhdCA8LSBkYXRfaW1wICU+JQogIHNlbGVjdCh3aGVyZShpcy5mYWN0b3IpKQoKaGVfY29udCA8LSB4dGFicyggfiB0aGFsICsgbnVtLCBkYXRhID0gZGF0YV9jYXQpICAgCmthYmxlKGhlX2NvbnQpCmBgYAoKIyMgci4KUmV2ZXJzYWJsZSBkZWZlY3QgaGFzIHRoZSBzdHJvbmdlc3QgcG9zaXRpdmUgcmVsYXRpb25zaGlwIHdpdGggaGF2aW5nIGhlYXJ0IGRpc2Vhc2UsIGFuZCBub3JtYWwgaGFzIHRoZSBzdHJvbmdlc3QgbmVnYXRpdmUgcmVsYXRpb25zaGlwLiBOb3JtYWwgaGFzIHRoZSBzdHJvbmdlc3QgcG9zaXRpdmUgcmVsYXRpb25zaGlwIHdpdGggbm8gZ2V0dGluZyBoZWFydCBkaXNlYXNlLCBhbmQgcmV2ZXJzYWJsZSBkZWZlY3QgaGFzIHRoZSBzdHJvbmdlc3QgbmVnYXRpdmUgcmVsYXRpb25zaGlwLgpgYGB7cn0KY2hpX3Rlc3QgPC0gY2hpc3EudGVzdChoZV9jb250KQogIGNoaV90ZXN0JHJlc2lkdWFscwpgYGAKCiMjIHMuIApUaGUgYW5nbGUgYmV0d2VlbiBub3JtYWwgYW5kIG5vIGlzIGV4dHJlbWVseSBzbWFsbCBzaW5jZSB0aGV5IGhhdmUgYSBzdHJvbmcgcG9zaXRpdmUgcmVsYXRpb25zaGlwLCB0aGUgc2FtZSBjYW4gYmUgc2FpZCBmb3IgeWVzIGFuZCByZXZlcnNhYmxlIGRlZmVjdC4gVGhlIGFuZ2xlIGJldHdlZW4gdGhlIG9wcG9zaXRlcyAobm9ybWFsIGFuZCB5ZXMsIHJldmVyc2FibGUgYW5kIG5vKSBhcmUgbmVhciAxODAgZGVncmVzcyBzaW5jZSB0aG9zZSByZWxhdGlvbnNoaXBzIGFyZSBzdHJvbmcgYW5kIG5lZ2F0aXZlLgpgYGB7cn0KaGVfY2EgPC0gTUNBKGRhdGFfY2F0WyAsIDc6OF0sIGdyYXBoID0gRkFMU0UpIApmdml6X21jYV92YXIoaGVfY2EsIGNvbC52YXIgPSAiY29zMiIsCiAgICAgICAgICAgICBnZW9tLnZhciA9IGMoImFycm93IiwgInRleHQiKSwKICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpKQpgYGAKCiMjIHQuIApGaXhlZCBkZWZlY3QgaXMgY2xvc2VyIHRvIHJldmVyc2FibGUgZGVmZWN0IHNpbmNlIGl0cyBhbHNvIHBvc2l0aXZlbHkgYXNzb2NpYXRlZCB3aXRoIHllcywgYW5kIG5lZ2F0aXZlbHkgYXNzb2NpYXRlZCB3aXRoIG5vLCBob3dldmVyIHRoZSBhc3NvY2lhdGlvbiBpc24ndCBhcyBzdHJvbmcuCgojIyB1LiAKVGhlIHZhcmlhYmxlcyBvbGRwZWFrIGFuZCB0aGFsY2ggc2VlbSB0aGUgbW9zdCBhc3NvY2lhdGVkIHdpdGggbnVtLiBUaGVyZSBhbHNvIGNvdWxkIGJlIHNvbWUgYXNzb2NpYXRpb24gd2l0aCBjYSwgc2xvcGUsIGV4YW5nLCBjcCwgYW5kIHRoYWwuCmBgYHtyfQpkYXRfZmFtZCA8LSBGQU1EKGRhdF9pbXAsIGdyYXBoID0gRkFMU0UpCmZ2aXpfZmFtZF92YXIoZGF0X2ZhbWQsIGNvbC52YXIgPSAiY29zMiIsCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwKICAgICAgICAgICAgIHJlcGVsID0gVFJVRSkKYGBgCgojIyB2LgpUaGUgcmVhbGx5IHJlZCBwb2ludHMgYXJlIG9ic2VydmF0aW9ucyB3aXRoIGxhcmdlIHBvc2l0aXZlIHNjb3JlcyBvbiB0aGUgdGhpcmQgZGltZW5zaW9uLCBtZWFuaW5nIHRoZXkgYWxpZ24gc3Ryb25nbHkgd2l0aCB0aGUgdmFyaWFibGVzIHRoYXQgbG9hZCBwb3NpdGl2ZWx5IG9uIERpbTMuIFRoZSByZWFsbHkgYmx1ZSBwb2ludHMgaGF2ZSBsYXJnZSBuZWdhdGl2ZSBEaW0zIHNjb3JlcywgbWVhbmluZyB0aGV5IGFsaWduIHdpdGggdGhlIG9wcG9zaXRlIHBhdHRlcm4gKHZhcmlhYmxlcyB3aXRoIG5lZ2F0aXZlIGxvYWRpbmdzIG9uIERpbTMpLgpgYGB7cn0KZnZpel9wY2FfaW5kKGRhdF9mYW1kLCBjb2wuaW5kID0gZGF0X2ZhbWQkaW5kJGNvb3JkWywzXSwKZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IikpCmBgYA==