Question 1
titanic <- read.csv("ExamData.csv")
a.
Age has 177 missing values. Cabin has 687 empty strings. Embarked has
2 empty strings.
kable(colSums(is.na(titanic)))
| PassengerId |
0 |
| Survived |
0 |
| Pclass |
0 |
| Name |
0 |
| Sex |
0 |
| Age |
177 |
| SibSp |
0 |
| Parch |
0 |
| Ticket |
0 |
| Fare |
0 |
| Cabin |
0 |
| Embarked |
0 |
kable(colSums(titanic == ""))
| PassengerId |
0 |
| Survived |
0 |
| Pclass |
0 |
| Name |
0 |
| Sex |
0 |
| Age |
NA |
| SibSp |
0 |
| Parch |
0 |
| Ticket |
0 |
| Fare |
0 |
| Cabin |
687 |
| Embarked |
2 |
titanic$Cabin <- na_if(titanic$Cabin, "")
titanic$Embarked<- na_if(titanic$Embarked, "")
b.
There was much more avaliable information about the first class
passengers than the second and third class passengers. If class refers
to wealth/status this makes sense.
titanic %>% mutate(has_na = if_any(everything(), is.na)) %>% group_by(Pclass) %>% summarise(prop_missing = mean(has_na))
# A tibble: 3 × 2
Pclass prop_missing
<int> <dbl>
1 1 0.269
2 2 0.918
3 3 0.980
c.
titanic <- mutate(titanic, Deck = substr(Cabin, 1, 1))
d.
titanic <- titanic %>% select(-PassengerId, -Name, -Cabin, -Ticket)
titanic <- titanic %>% mutate(Survived = as.factor(Survived), Pclass = as.factor(Pclass), Sex = as.factor(Sex), Embarked = as.factor(Embarked), Deck = as.factor(Deck))
e.
mice_impute <- mice(titanic, seed = 123)
titanic1 <- complete(mice_impute, 1)
f.Â
Parch and SibSp have the strongest positive pairwise correlation.
SibSp and Age have the strongest negative correlation.
data_num <- titanic1 %>% select(where(is.numeric))
cor_ma <- cor(data_num)
kable(round(cor_ma, 2), format = "html") %>%
kable_styling(full_width = F, font_size = 10)
|
|
Age
|
SibSp
|
Parch
|
Fare
|
|
Age
|
1.00
|
-0.35
|
-0.22
|
0.09
|
|
SibSp
|
-0.35
|
1.00
|
0.41
|
0.16
|
|
Parch
|
-0.22
|
0.41
|
1.00
|
0.22
|
|
Fare
|
0.09
|
0.16
|
0.22
|
1.00
|
g.
0.9201 of the original variation is explained by PC1. 0.99940 of the
original variation is explained by PC1 and PC2 together.
pca <- prcomp(data_num)
summary(pca)
Importance of components:
PC1 PC2 PC3 PC4
Standard deviation 49.7128 14.59946 1.07082 0.67926
Proportion of Variance 0.9201 0.07935 0.00043 0.00017
Cumulative Proportion 0.9201 0.99940 0.99983 1.00000
h.
The summary does say PC1 -> PC4 explains 1.0000 of the original
variation. We can check this by taking the variation of the original
data vs PCs. They are the same.
sum(apply(data_num, 2, var))
[1] 2686.118
sum(apply(pca$x, 2, var))
[1] 2686.118
cor_mat <- cor(pca$x)
kable(round(cor_mat, 2), format = "html") %>%
kable_styling(full_width = F, font_size = 10)
|
|
PC1
|
PC2
|
PC3
|
PC4
|
|
PC1
|
1
|
0
|
0
|
0
|
|
PC2
|
0
|
1
|
0
|
0
|
|
PC3
|
0
|
0
|
1
|
0
|
|
PC4
|
0
|
0
|
0
|
1
|
i.
Fare is the most important in PC1 and Age is the most important in
PC2. SibSp and Parch have smaller scales than Age and Fare, so they have
smaller variances and variables with larger variances contribute more
strongly to the first components. This can be fixed with scaling.
pca$rotation[ , 1:2]
PC1 PC2
Age 0.028757803 -0.99912343
SibSp 0.003475807 0.02752000
Parch 0.003474588 0.01330037
Fare 0.999574327 0.02860290
j.
After scaling, the first two PCs now explain 0.7012 of the original
variation.
pca2 <- prcomp(data_num, scale = TRUE)
summary(pca2)
Importance of components:
PC1 PC2 PC3 PC4
Standard deviation 1.3065 1.0478 0.8034 0.7414
Proportion of Variance 0.4267 0.2745 0.1614 0.1374
Cumulative Proportion 0.4267 0.7012 0.8626 1.0000
The biplot reflects what we found in question (f). Parch and SibSp
point in the same direction. SibSp and Age point in opposite directions.
Fare and Parch point in similar directions. Fare and SibSp, plus Fare
and Age, have very little correlation reflected by their near 90 degree
angles on the biplot.
fviz_pca_var(pca2, col.var = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)

k.
Deck_D, Deck_E, and female are the most positively correlated
variables with Survived_1. Variables Deck_T, male, and Pclass_3 are the
most negatively correlated with Survived_1. Deck G A C and B, all
Embarked variables, and Pclass_1 are hardly correlated with
Survived_1.
data_cat <- titanic1 %>% select(where(is.factor))
he_ca <- MCA(data_cat, graph = FALSE)
fviz_mca_var(he_ca, col.var = "cos2",
geom.var = c("arrow", "text"),
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"))

l.
Sex, Embarked, Fare, and Pclass seem to be the most associated with
Survived.
dat_famd <- FAMD(titanic1, graph = FALSE, ncp = 10)
fviz_famd_var(dat_famd, col.var = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)

m.
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"))

n.Â
I would keep 7 dimensions because the first 7 components all have
eigenvalues greater than 1. Dimensions with eigenvalues above 1 are
typically retained since they explain more variance than a single
original standardized variable. After the 7th component, the eigenvalues
drop below 1, so those dimensions contribute less individual
information.
dat_famd$eig
eigenvalue percentage of variance cumulative percentage of variance
comp 1 2.8483875 16.755221 16.75522
comp 2 2.3249385 13.676109 30.43133
comp 3 1.6170617 9.512128 39.94346
comp 4 1.2736722 7.492189 47.43565
comp 5 1.1718818 6.893422 54.32907
comp 6 1.0944684 6.438050 60.76712
comp 7 1.0131719 5.959835 66.72695
comp 8 0.9894587 5.820345 72.54730
comp 9 0.8480019 4.988247 77.53554
comp 10 0.7381362 4.341977 81.87752
o.
dat_famd_n <- dat_famd$ind$coord[,1:7]
p.Â
Observation 1’s nearest neighbor was observation 443 with a euclidean
distance of 0.1233653. Observation 2’s nearest neighbor was observation
850 with a euclidean distance of 0.5523195.
dist_mat <- as.matrix(dist(dat_famd_n))
n1 <- which.min(dist_mat[1, -1]) + 1 #had to look this code up
d1 <- min(dist_mat[1, -1])
n2 <- which.min(dist_mat[2, -2]) + 1
d2 <- min(dist_mat[2, -2])
n1
443
443
d1
[1] 0.1233653
n2
850
850
d2
[1] 0.5523195
The observations are nearly identical. Observation 1 and 443 have a
shorter distance than observation 2 and 850 because their Fare and Age
values are closer.
kable(titanic1[c(1, 443), ])
| 1 |
0 |
3 |
male |
22 |
1 |
0 |
7.250 |
S |
F |
| 443 |
0 |
3 |
male |
25 |
1 |
0 |
7.775 |
S |
F |
kable(titanic1[c(2, 850), ])
| 2 |
1 |
1 |
female |
38 |
1 |
0 |
71.2833 |
C |
C |
| 850 |
1 |
1 |
female |
25 |
1 |
0 |
89.1042 |
C |
C |
q.
The average silhouette score peaks at 7 clusters. Since silhouette
scores measure how well and observation fits inside its cluster compared
to other clusters, 7 clusters is optimal.
fviz_nbclust(dat_famd_n, kmeans, method = "silhouette") +
labs(subtitle = "Elbow Method")

r.
Cluster 1 has 331 observations, cluster 2 has 75 observations,
cluster 3 has 42 observations, cluster 4 has 95 observations, cluster 5
has 98 observations, cluster 6 has 66 observations, and cluster 7 has
184 observations.
set.seed(123)
km <- kmeans(dat_famd_n, centers = 7, nstart = 20)
kable(table(km$cluster))
| 1 |
331 |
| 2 |
75 |
| 3 |
42 |
| 4 |
95 |
| 5 |
98 |
| 6 |
66 |
| 7 |
184 |
s.
Dimension 1 is highly driven by Fare and Pclass. This suggests that
Dimension 1 reflects differences related to passenger status or wealth.
Dimension 2 is primarily influenced by Age, Sex, SibSp, Parch, and Deck
G, so this dimension captures differences more related to gender and
family structure rather than social class. Looking at the cluster
centers, clusters with positive values on Dimension 1 represent
passengers with higher status (wealth), while clusters with negative
values represent lower status passengers. Clusters with large positive
values on Dimension 2 likely correspond to passengers traveling with
family or particular gender groupings, while clusters with negative
values represent passengers traveling alone or with different
demographic characteristics. Cluster 1 likely consists of lower status
passengers traveling alone. Cluster 2 likely consists of wealthier
passengers traviling with family or alone.
km$centers
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5 Dim.6
1 -1.2354444 -0.746043890 0.2042022 0.4293120 0.03721878 -0.2848594
2 2.6697002 -0.100977627 1.2756206 0.2387800 1.65426806 -0.6341549
3 0.6395448 -1.543079232 1.2256454 -0.6648678 -2.31807260 2.3088748
4 -0.8414501 0.264443391 -0.4700905 -2.1122662 0.06177521 -0.8428592
5 -1.0706037 3.222036273 0.7714037 0.2665500 0.04532345 0.7600625
6 2.9494175 -0.006510214 0.9580438 -0.1710747 -1.02497425 -0.9433299
7 0.9349950 -0.114830572 -1.6788557 0.2921088 0.09949721 0.6126227
Dim.7
1 0.22222162
2 -1.46984995
3 -1.70774293
4 -0.32609953
5 0.01917922
6 2.10649283
7 -0.00826109
dat_famd$quanti.var$contrib
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5 Dim.6
Age 3.8319377 13.140730 1.2344929 0.6218446 6.937460352 10.1265362
SibSp 0.2308333 23.455453 2.6700077 3.3486761 0.020888435 0.1364451
Parch 0.2574612 22.358643 0.1766317 3.8400644 0.008368628 2.4162196
Fare 18.6054948 1.967104 4.1447774 1.3601240 1.033096747 4.0627168
Dim.7 Dim.8 Dim.9 Dim.10
Age 0.01226043 0.001022794 20.6136111 4.39266305
SibSp 0.95868881 0.002832248 0.4960558 1.11151132
Parch 0.50583804 0.305892423 0.4396809 1.39951123
Fare 0.28158397 0.002863466 1.3254382 0.00954473
dat_famd$quali.var$contrib
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
0 4.3834091 0.648395299 7.65225642 1.956584632 0.02353650
1 7.0365251 1.040845084 12.28388531 3.140833224 0.03778228
1 18.9123021 0.433783992 3.48675779 0.059298285 0.62490410
2 0.2082099 0.492316978 18.52713720 16.474958454 0.05424638
3 6.7864836 0.750592813 1.95006365 7.002635542 0.44474759
female 2.9872200 6.713946838 9.02451118 3.315337189 0.08392846
male 1.6256275 3.653690307 4.91108581 1.804186962 0.04567338
C 6.7327787 0.114849039 0.68671546 1.336569985 23.82347812
Q 1.1233996 0.091834086 0.03787727 32.839376861 2.17603013
S 0.9254043 0.004728778 0.12740437 6.613993484 3.95509951
A 0.2376377 2.076467286 2.70799649 1.284478614 18.44412495
B 7.7219589 0.002110787 2.73170229 0.129845680 5.67637045
C 6.7590757 0.027236324 5.18657941 0.035842583 18.49375740
D 1.7848341 0.053311880 9.87182214 7.238742325 6.00926187
E 0.5414346 0.341010996 8.05729660 6.853051100 9.46689115
F 6.6421595 2.071173424 0.46032200 0.614694062 0.38131185
G 2.2867329 19.357708399 2.68753996 0.127113562 0.12163299
T 0.3790797 1.204067876 1.38313690 0.001748341 2.13740874
Dim.6 Dim.7 Dim.8 Dim.9 Dim.10
0 0.005258125 0.006535272 1.752960e-03 2.622525843 0.22422425
1 0.008440675 0.010490832 2.813963e-03 4.209844116 0.35993893
1 0.023865061 0.182870395 1.332688e-01 0.414461142 0.09926839
2 0.495615961 0.028574913 9.292527e-06 0.208429265 8.80552037
3 0.107912734 0.149857792 5.953458e-02 0.021762810 2.58427903
female 0.018323778 0.022769740 4.474536e-01 0.002803039 6.96060302
male 0.009971692 0.012391158 2.435016e-01 0.001525397 3.78791915
C 0.134378450 0.085540414 1.309119e+00 1.493320597 10.43038961
Q 3.912120787 1.556119809 8.444520e+00 10.189847109 4.97976865
S 0.758703692 0.337234686 2.527193e+00 0.227925296 0.77814948
A 20.978087315 13.392150512 3.294228e+00 5.084483705 19.52049030
B 5.474063129 33.071928881 3.638573e+00 6.039545833 3.38576538
C 3.315000727 19.953836790 2.469010e+00 4.382518419 0.10749412
D 1.928575329 2.695435537 2.207356e+01 14.457201742 10.05035704
E 12.165846643 2.460513044 1.674581e+01 0.511390540 18.36125692
F 19.622388016 0.120984663 1.048925e+00 1.306805786 0.95501712
G 5.917572434 0.002323440 6.324857e-02 6.093210334 0.37379283
T 8.381957765 24.152070871 3.718486e+01 19.857613035 1.32253509
LS0tCnRpdGxlOiAiRXhhbSAxIgphdXRob3I6ICJDaGFybGllIE1vcmdhbiIKZGF0ZTogIiBEdWU6IDAzLzE1LzI2IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICB0b2NfZmxvYXQ6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgdG9jX2NvbGxhcHNlZDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgc21vb3RoX3Njcm9sbDogeWVzCiAgICB0aGVtZTogbHVtZW4KICBwZGZfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIGZpZ193aWR0aDogMwogICAgZmlnX2hlaWdodDogMwogIHdvcmRfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAga2VlcF9tZDogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge2NzcywgZWNobyA9IEZBTFNFfQojVE9DOjpiZWZvcmUgewogIGNvbnRlbnQ6ICJUYWJsZSBvZiBDb250ZW50cyI7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1zaXplOiAxLjJlbTsKICBkaXNwbGF5OiBibG9jazsKICBjb2xvcjogbmF2eTsKICBtYXJnaW4tYm90dG9tOiAxMHB4Owp9CgoKZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLwogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsKICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsKICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7CiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7Cn0KCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovCiAgZm9udC1zaXplOiAyMnB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7Cn0KCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxNXB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7CiAgY29sb3I6IG5hdnk7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwogIGNvbG9yOiBEYXJrQmx1ZTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNnB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9CgouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQoKcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCn0KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikKICAgbGlicmFyeShrbml0cikKfQppZiAoIXJlcXVpcmUoImZhY3RvZXh0cmEiKSkgewogIGluc3RhbGwucGFja2FnZXMoImZhY3RvZXh0cmEiKQogIGxpYnJhcnkoZmFjdG9leHRyYSkKfQoKaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgewogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpCiAgbGlicmFyeSh0aWR5dmVyc2UpCn0KCmlmICghcmVxdWlyZSgiRmFjdG9NaW5lUiIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiRmFjdG9NaW5lUiIpCiAgbGlicmFyeShGYWN0b01pbmVSKQp9CgppZiAoIXJlcXVpcmUoImNvcnJwbG90IikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJjb3JycGxvdCIpCiAgbGlicmFyeShjb3JycGxvdCkKfQoKaWYgKCFyZXF1aXJlKCJtaWNlIikpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJtaWNlIikKICBsaWJyYXJ5KG1pY2UpCn0KCmlmICghcmVxdWlyZSgia2FibGVFeHRyYSIpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygia2FibGVFeHRyYSIpCiAgbGlicmFyeShrYWJsZUV4dHJhKQp9CgppZiAoIXJlcXVpcmUoImNsdXN0ZXIiKSkgewogIGluc3RhbGwucGFja2FnZXMoImNsdXN0ZXIiKQogIGxpYnJhcnkoY2x1c3RlcikKfQoKaWYgKCFyZXF1aXJlKCJkYnNjYW4iKSkgewogIGluc3RhbGwucGFja2FnZXMoImRic2NhbiIpCiAgbGlicmFyeShkYnNjYW4pCn0KIyMjIwprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgICMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgKSAgCgpgYGAKCiMgUXVlc3Rpb24gMQpgYGB7cn0KdGl0YW5pYyA8LSByZWFkLmNzdigiRXhhbURhdGEuY3N2IikKYGBgCgojIyBhLgpBZ2UgaGFzIDE3NyBtaXNzaW5nIHZhbHVlcy4gQ2FiaW4gaGFzIDY4NyBlbXB0eSBzdHJpbmdzLiBFbWJhcmtlZCBoYXMgMiBlbXB0eSBzdHJpbmdzLgpgYGB7cn0Ka2FibGUoY29sU3Vtcyhpcy5uYSh0aXRhbmljKSkpCmthYmxlKGNvbFN1bXModGl0YW5pYyA9PSAiIikpCgp0aXRhbmljJENhYmluIDwtIG5hX2lmKHRpdGFuaWMkQ2FiaW4sICIiKQp0aXRhbmljJEVtYmFya2VkPC0gbmFfaWYodGl0YW5pYyRFbWJhcmtlZCwgIiIpCmBgYAojIyBiLiAKVGhlcmUgd2FzIG11Y2ggbW9yZSBhdmFsaWFibGUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGZpcnN0IGNsYXNzIHBhc3NlbmdlcnMgdGhhbiB0aGUgc2Vjb25kIGFuZCB0aGlyZCBjbGFzcyBwYXNzZW5nZXJzLiBJZiBjbGFzcyByZWZlcnMgdG8gd2VhbHRoL3N0YXR1cyB0aGlzIG1ha2VzIHNlbnNlLiAKYGBge3J9CnRpdGFuaWMgJT4lIG11dGF0ZShoYXNfbmEgPSBpZl9hbnkoZXZlcnl0aGluZygpLCBpcy5uYSkpICU+JSBncm91cF9ieShQY2xhc3MpICU+JSBzdW1tYXJpc2UocHJvcF9taXNzaW5nID0gbWVhbihoYXNfbmEpKQpgYGAKIyMgYy4KYGBge3J9CnRpdGFuaWMgPC0gbXV0YXRlKHRpdGFuaWMsIERlY2sgPSBzdWJzdHIoQ2FiaW4sIDEsIDEpKQpgYGAKIyMgZC4KYGBge3J9CnRpdGFuaWMgPC0gdGl0YW5pYyAlPiUgc2VsZWN0KC1QYXNzZW5nZXJJZCwgLU5hbWUsIC1DYWJpbiwgLVRpY2tldCkKdGl0YW5pYyA8LSB0aXRhbmljICU+JSBtdXRhdGUoU3Vydml2ZWQgPSBhcy5mYWN0b3IoU3Vydml2ZWQpLCBQY2xhc3MgPSBhcy5mYWN0b3IoUGNsYXNzKSwgU2V4ID0gYXMuZmFjdG9yKFNleCksIEVtYmFya2VkID0gYXMuZmFjdG9yKEVtYmFya2VkKSwgRGVjayA9IGFzLmZhY3RvcihEZWNrKSkKYGBgCiMjIGUuCmBgYHtyLCByZXN1bHRzID0gJ2hpZGUnfQptaWNlX2ltcHV0ZSA8LSBtaWNlKHRpdGFuaWMsIHNlZWQgPSAxMjMpCnRpdGFuaWMxIDwtIGNvbXBsZXRlKG1pY2VfaW1wdXRlLCAxKQpgYGAKIyMgZi4gClBhcmNoIGFuZCBTaWJTcCBoYXZlIHRoZSBzdHJvbmdlc3QgcG9zaXRpdmUgcGFpcndpc2UgY29ycmVsYXRpb24uIFNpYlNwIGFuZCBBZ2UgaGF2ZSB0aGUgc3Ryb25nZXN0IG5lZ2F0aXZlIGNvcnJlbGF0aW9uLgpgYGB7cn0KZGF0YV9udW0gPC0gdGl0YW5pYzEgJT4lIHNlbGVjdCh3aGVyZShpcy5udW1lcmljKSkKY29yX21hIDwtIGNvcihkYXRhX251bSkKa2FibGUocm91bmQoY29yX21hLCAyKSwgZm9ybWF0ID0gImh0bWwiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGLCBmb250X3NpemUgPSAxMCkKYGBgCgojIyBnLgowLjkyMDEgb2YgdGhlIG9yaWdpbmFsIHZhcmlhdGlvbiBpcyBleHBsYWluZWQgYnkgUEMxLiAwLjk5OTQwIG9mIHRoZSBvcmlnaW5hbCB2YXJpYXRpb24gaXMgZXhwbGFpbmVkIGJ5IFBDMSBhbmQgUEMyIHRvZ2V0aGVyLgpgYGB7cn0KcGNhIDwtIHByY29tcChkYXRhX251bSkKICBzdW1tYXJ5KHBjYSkKYGBgCiMjIGguIApUaGUgc3VtbWFyeSBkb2VzIHNheSBQQzEgLT4gUEM0IGV4cGxhaW5zIDEuMDAwMCBvZiB0aGUgb3JpZ2luYWwgdmFyaWF0aW9uLiBXZSBjYW4gY2hlY2sgdGhpcyBieSB0YWtpbmcgdGhlIHZhcmlhdGlvbiBvZiB0aGUgb3JpZ2luYWwgZGF0YSB2cyBQQ3MuIFRoZXkgYXJlIHRoZSBzYW1lLiAKYGBge3J9CnN1bShhcHBseShkYXRhX251bSwgMiwgdmFyKSkKc3VtKGFwcGx5KHBjYSR4LCAyLCB2YXIpKQoKY29yX21hdCA8LSBjb3IocGNhJHgpCmthYmxlKHJvdW5kKGNvcl9tYXQsIDIpLCBmb3JtYXQgPSAiaHRtbCIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYsIGZvbnRfc2l6ZSA9IDEwKQpgYGAKCiMjIGkuIApGYXJlIGlzIHRoZSBtb3N0IGltcG9ydGFudCBpbiBQQzEgYW5kIEFnZSBpcyB0aGUgbW9zdCBpbXBvcnRhbnQgaW4gUEMyLiBTaWJTcCBhbmQgUGFyY2ggaGF2ZSBzbWFsbGVyIHNjYWxlcyB0aGFuIEFnZSBhbmQgRmFyZSwgc28gdGhleSBoYXZlIHNtYWxsZXIgdmFyaWFuY2VzIGFuZCB2YXJpYWJsZXMgd2l0aCBsYXJnZXIgdmFyaWFuY2VzIGNvbnRyaWJ1dGUgbW9yZSBzdHJvbmdseSB0byB0aGUgZmlyc3QgY29tcG9uZW50cy4gVGhpcyBjYW4gYmUgZml4ZWQgd2l0aCBzY2FsaW5nLgpgYGB7cn0KcGNhJHJvdGF0aW9uWyAsIDE6Ml0KYGBgCiMjIGouCkFmdGVyIHNjYWxpbmcsIHRoZSBmaXJzdCB0d28gUENzIG5vdyBleHBsYWluIDAuNzAxMiBvZiB0aGUgb3JpZ2luYWwgdmFyaWF0aW9uLgpgYGB7cn0KcGNhMiA8LSBwcmNvbXAoZGF0YV9udW0sIHNjYWxlID0gVFJVRSkKICBzdW1tYXJ5KHBjYTIpCmBgYApUaGUgYmlwbG90IHJlZmxlY3RzIHdoYXQgd2UgZm91bmQgaW4gcXVlc3Rpb24gKGYpLiBQYXJjaCBhbmQgU2liU3AgcG9pbnQgaW4gdGhlIHNhbWUgZGlyZWN0aW9uLiBTaWJTcCBhbmQgQWdlIHBvaW50IGluIG9wcG9zaXRlIGRpcmVjdGlvbnMuIEZhcmUgYW5kIFBhcmNoIHBvaW50IGluIHNpbWlsYXIgZGlyZWN0aW9ucy4gRmFyZSBhbmQgU2liU3AsIHBsdXMgRmFyZSBhbmQgQWdlLCBoYXZlIHZlcnkgbGl0dGxlIGNvcnJlbGF0aW9uIHJlZmxlY3RlZCBieSB0aGVpciBuZWFyIDkwIGRlZ3JlZSBhbmdsZXMgb24gdGhlIGJpcGxvdC4KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KZnZpel9wY2FfdmFyKHBjYTIsIGNvbC52YXIgPSAiY29zMiIsCiAgICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpLCAKICAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFKQpgYGAKCiMjIGsuIApEZWNrX0QsIERlY2tfRSwgYW5kIGZlbWFsZSBhcmUgdGhlIG1vc3QgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHZhcmlhYmxlcyB3aXRoIFN1cnZpdmVkXzEuIFZhcmlhYmxlcyBEZWNrX1QsIG1hbGUsIGFuZCBQY2xhc3NfMyBhcmUgdGhlIG1vc3QgbmVnYXRpdmVseSBjb3JyZWxhdGVkIHdpdGggU3Vydml2ZWRfMS4gRGVjayBHIEEgQyBhbmQgQiwgYWxsIEVtYmFya2VkIHZhcmlhYmxlcywgYW5kIFBjbGFzc18xIGFyZSBoYXJkbHkgY29ycmVsYXRlZCB3aXRoIFN1cnZpdmVkXzEuCmBgYHtyfQpkYXRhX2NhdCA8LSB0aXRhbmljMSAlPiUgc2VsZWN0KHdoZXJlKGlzLmZhY3RvcikpCmhlX2NhIDwtIE1DQShkYXRhX2NhdCwgZ3JhcGggPSBGQUxTRSkgCmZ2aXpfbWNhX3ZhcihoZV9jYSwgY29sLnZhciA9ICJjb3MyIiwKICAgICAgICAgICAgIGdlb20udmFyID0gYygiYXJyb3ciLCAidGV4dCIpLAogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IikpCmBgYAoKIyMgbC4KU2V4LCBFbWJhcmtlZCwgRmFyZSwgYW5kIFBjbGFzcyBzZWVtIHRvIGJlIHRoZSBtb3N0IGFzc29jaWF0ZWQgd2l0aCBTdXJ2aXZlZC4KYGBge3J9CmRhdF9mYW1kIDwtIEZBTUQodGl0YW5pYzEsIGdyYXBoID0gRkFMU0UsIG5jcCA9IDEwKQpmdml6X2ZhbWRfdmFyKGRhdF9mYW1kLCBjb2wudmFyID0gImNvczIiLAogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksCiAgICAgICAgICAgICByZXBlbCA9IFRSVUUpCmBgYAoKIyMgbS4KVGhlIHJlYWxseSByZWQgcG9pbnRzIGFyZSBvYnNlcnZhdGlvbnMgd2l0aCBsYXJnZSBwb3NpdGl2ZSBzY29yZXMgb24gdGhlIHRoaXJkIGRpbWVuc2lvbiwgbWVhbmluZyB0aGV5IGFsaWduIHN0cm9uZ2x5IHdpdGggdGhlIHZhcmlhYmxlcyB0aGF0IGxvYWQgcG9zaXRpdmVseSBvbiBEaW0zLiBUaGUgcmVhbGx5IGJsdWUgcG9pbnRzIGhhdmUgbGFyZ2UgbmVnYXRpdmUgRGltMyBzY29yZXMsIG1lYW5pbmcgdGhleSBhbGlnbiB3aXRoIHRoZSBvcHBvc2l0ZSBwYXR0ZXJuICh2YXJpYWJsZXMgd2l0aCBuZWdhdGl2ZSBsb2FkaW5ncyBvbiBEaW0zKS4KYGBge3J9CmZ2aXpfcGNhX2luZChkYXRfZmFtZCwgY29sLmluZCA9IGRhdF9mYW1kJGluZCRjb29yZFssM10sIGdyYWRpZW50LmNvbHMgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpKQpgYGAKCiMjIG4uIApJIHdvdWxkIGtlZXAgNyBkaW1lbnNpb25zIGJlY2F1c2UgdGhlIGZpcnN0IDcgY29tcG9uZW50cyBhbGwgaGF2ZSBlaWdlbnZhbHVlcyBncmVhdGVyIHRoYW4gMS4gRGltZW5zaW9ucyB3aXRoIGVpZ2VudmFsdWVzIGFib3ZlIDEgYXJlIHR5cGljYWxseSByZXRhaW5lZCBzaW5jZSB0aGV5IGV4cGxhaW4gbW9yZSB2YXJpYW5jZSB0aGFuIGEgc2luZ2xlIG9yaWdpbmFsIHN0YW5kYXJkaXplZCB2YXJpYWJsZS4gQWZ0ZXIgdGhlIDd0aCBjb21wb25lbnQsIHRoZSBlaWdlbnZhbHVlcyBkcm9wIGJlbG93IDEsIHNvIHRob3NlIGRpbWVuc2lvbnMgY29udHJpYnV0ZSBsZXNzIGluZGl2aWR1YWwgaW5mb3JtYXRpb24uCmBgYHtyfQpkYXRfZmFtZCRlaWcKYGBgCiMjIG8uCmBgYHtyfQpkYXRfZmFtZF9uIDwtICBkYXRfZmFtZCRpbmQkY29vcmRbLDE6N10KYGBgCiMjIHAuIApPYnNlcnZhdGlvbiAxJ3MgbmVhcmVzdCBuZWlnaGJvciB3YXMgb2JzZXJ2YXRpb24gNDQzIHdpdGggYSBldWNsaWRlYW4gZGlzdGFuY2Ugb2YgMC4xMjMzNjUzLiBPYnNlcnZhdGlvbiAyJ3MgbmVhcmVzdCBuZWlnaGJvciB3YXMgb2JzZXJ2YXRpb24gODUwIHdpdGggYSBldWNsaWRlYW4gZGlzdGFuY2Ugb2YgMC41NTIzMTk1LgpgYGB7cn0KZGlzdF9tYXQgPC0gYXMubWF0cml4KGRpc3QoZGF0X2ZhbWRfbikpCgpuMSA8LSB3aGljaC5taW4oZGlzdF9tYXRbMSwgLTFdKSArIDEgI2hhZCB0byBsb29rIHRoaXMgY29kZSB1cApkMSA8LSBtaW4oZGlzdF9tYXRbMSwgLTFdKQoKbjIgPC0gd2hpY2gubWluKGRpc3RfbWF0WzIsIC0yXSkgKyAxCmQyIDwtIG1pbihkaXN0X21hdFsyLCAtMl0pCgpuMQpkMQpuMgpkMgpgYGAKVGhlIG9ic2VydmF0aW9ucyBhcmUgbmVhcmx5IGlkZW50aWNhbC4gT2JzZXJ2YXRpb24gMSBhbmQgNDQzIGhhdmUgYSBzaG9ydGVyIGRpc3RhbmNlIHRoYW4gb2JzZXJ2YXRpb24gMiBhbmQgODUwIGJlY2F1c2UgdGhlaXIgRmFyZSBhbmQgQWdlIHZhbHVlcyBhcmUgY2xvc2VyLgpgYGB7cn0Ka2FibGUodGl0YW5pYzFbYygxLCA0NDMpLCBdKQprYWJsZSh0aXRhbmljMVtjKDIsIDg1MCksIF0pCmBgYAoKIyMgcS4gClRoZSBhdmVyYWdlIHNpbGhvdWV0dGUgc2NvcmUgcGVha3MgYXQgNyBjbHVzdGVycy4gU2luY2Ugc2lsaG91ZXR0ZSBzY29yZXMgbWVhc3VyZSBob3cgd2VsbCBhbmQgb2JzZXJ2YXRpb24gZml0cyBpbnNpZGUgaXRzIGNsdXN0ZXIgY29tcGFyZWQgdG8gb3RoZXIgY2x1c3RlcnMsIDcgY2x1c3RlcnMgaXMgb3B0aW1hbC4KYGBge3J9CmZ2aXpfbmJjbHVzdChkYXRfZmFtZF9uLCBrbWVhbnMsIG1ldGhvZCA9ICJzaWxob3VldHRlIikgKwogIGxhYnMoc3VidGl0bGUgPSAiRWxib3cgTWV0aG9kIikKYGBgCgojIyByLiAKQ2x1c3RlciAxIGhhcyAzMzEgb2JzZXJ2YXRpb25zLCBjbHVzdGVyIDIgaGFzIDc1IG9ic2VydmF0aW9ucywgY2x1c3RlciAzIGhhcyA0MiBvYnNlcnZhdGlvbnMsIGNsdXN0ZXIgNCBoYXMgOTUgb2JzZXJ2YXRpb25zLCBjbHVzdGVyIDUgaGFzIDk4IG9ic2VydmF0aW9ucywgY2x1c3RlciA2IGhhcyA2NiBvYnNlcnZhdGlvbnMsIGFuZCBjbHVzdGVyIDcgaGFzIDE4NCBvYnNlcnZhdGlvbnMuCmBgYHtyfQpzZXQuc2VlZCgxMjMpCmttIDwtIGttZWFucyhkYXRfZmFtZF9uLCBjZW50ZXJzID0gNywgbnN0YXJ0ID0gMjApIAprYWJsZSh0YWJsZShrbSRjbHVzdGVyKSkKYGBgCiMjIHMuCkRpbWVuc2lvbiAxIGlzIGhpZ2hseSBkcml2ZW4gYnkgRmFyZSBhbmQgUGNsYXNzLiBUaGlzIHN1Z2dlc3RzIHRoYXQgRGltZW5zaW9uIDEgcmVmbGVjdHMgZGlmZmVyZW5jZXMgcmVsYXRlZCB0byBwYXNzZW5nZXIgc3RhdHVzIG9yIHdlYWx0aC4gRGltZW5zaW9uIDIgaXMgcHJpbWFyaWx5IGluZmx1ZW5jZWQgYnkgQWdlLCBTZXgsIFNpYlNwLCBQYXJjaCwgYW5kIERlY2sgRywgc28gdGhpcyBkaW1lbnNpb24gY2FwdHVyZXMgZGlmZmVyZW5jZXMgbW9yZSByZWxhdGVkIHRvIGdlbmRlciBhbmQgZmFtaWx5IHN0cnVjdHVyZSByYXRoZXIgdGhhbiBzb2NpYWwgY2xhc3MuIExvb2tpbmcgYXQgdGhlIGNsdXN0ZXIgY2VudGVycywgY2x1c3RlcnMgd2l0aCBwb3NpdGl2ZSB2YWx1ZXMgb24gRGltZW5zaW9uIDEgcmVwcmVzZW50IHBhc3NlbmdlcnMgd2l0aCBoaWdoZXIgc3RhdHVzICh3ZWFsdGgpLCB3aGlsZSBjbHVzdGVycyB3aXRoIG5lZ2F0aXZlIHZhbHVlcyByZXByZXNlbnQgbG93ZXIgc3RhdHVzIHBhc3NlbmdlcnMuIENsdXN0ZXJzIHdpdGggbGFyZ2UgcG9zaXRpdmUgdmFsdWVzIG9uIERpbWVuc2lvbiAyIGxpa2VseSBjb3JyZXNwb25kIHRvIHBhc3NlbmdlcnMgdHJhdmVsaW5nIHdpdGggZmFtaWx5IG9yIHBhcnRpY3VsYXIgZ2VuZGVyIGdyb3VwaW5ncywgd2hpbGUgY2x1c3RlcnMgd2l0aCBuZWdhdGl2ZSB2YWx1ZXMgcmVwcmVzZW50IHBhc3NlbmdlcnMgdHJhdmVsaW5nIGFsb25lIG9yIHdpdGggZGlmZmVyZW50IGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcy4gQ2x1c3RlciAxIGxpa2VseSBjb25zaXN0cyBvZiBsb3dlciBzdGF0dXMgcGFzc2VuZ2VycyB0cmF2ZWxpbmcgYWxvbmUuIENsdXN0ZXIgMiBsaWtlbHkgY29uc2lzdHMgb2Ygd2VhbHRoaWVyIHBhc3NlbmdlcnMgdHJhdmlsaW5nIHdpdGggZmFtaWx5IG9yIGFsb25lLgpgYGB7cn0Ka20kY2VudGVycwpgYGAKYGBge3J9CmRhdF9mYW1kJHF1YW50aS52YXIkY29udHJpYgpkYXRfZmFtZCRxdWFsaS52YXIkY29udHJpYgpgYGA=