Replicate the correspondence analysis (CA) on household chores.
Source: http://www.sthda.com/english/articles/31-principal-component-methods-in-r-practical-guide/113-ca-correspondence-analysis-in-r-essentials/
Graph contingency tables and run a chi-square test
library(gplots)
dt <- as.table(as.matrix(housetasks))
balloonplot(
t(dt),
main = "housetasks",
xlab = "",
ylab = "",
label = F,
show.margins = FALSE
)
chisq.test(housetasks)
chisq.test(housetasks)$stdres
Compute CA
library(FactoMineR)
res.ca <- CA(housetasks, graph = FALSE) # argument ncp: number of dimensions kept in the final results
print(res.ca)
Eigenvalues / Inertia
“Our data contains 13 rows and 4 columns.
If the data were random, the expected value of the eigenvalue for
each axis would be 1/(nrow(housetasks)-1) = 1/12 = 8.33% in terms of
rows.
Likewise, the average axis should account for 1/(ncol(housetasks)-1)
= 1/3 = 33.33% in terms of the 4 columns.”
res.ca$eig
fviz_screeplot(res.ca) +
geom_hline(yintercept = 33.33, linetype = 2, color = "red")
Biplot
“Symmetric plot represents the row and column profiles simultaneously
in a common space. In this case, only the distance between row points or
the distance between column points can be really interpreted.
The distance between any row and column items is not meaningful! You
can only make a general statements about the observed pattern.
In order to interpret the distance between column and row points, the
column profiles must be presented in row space or vice versa. This type
of map is called asymmetric biplot.”
fviz_ca_biplot(res.ca, repel = TRUE)
Graph of row variables
“If a row item is well represented by two dimensions, the sum of the
cos2 is closed to one. For some of the row items, more than 2 dimensions
are required to perfectly represent the data.”
fviz_ca_row(res.ca, repel = TRUE)
fviz_ca_row(res.ca, alpha.row = "cos2", repel = TRUE)
library(corrplot)
corrplot(res.ca$row$cos2, is.corr = FALSE)
Contributions of rows to the dimensions
“Rows that contribute the most to Dim.1 and Dim.2 are the most
important in explaining the variability in the data set.”
“It’s possible to use the function `corrplot()’ to highlight the most
contributing row points for each dimension:”
corrplot(res.ca$row$contrib, is.corr = FALSE)
fviz_contrib(res.ca, choice = "row", axes = 1, top = 10)
fviz_contrib(res.ca, choice = "row", axes = 2, top = 10)
fviz_contrib(res.ca, choice = "row", axes = 1:2, top = 10)
fviz_ca_row(res.ca, col.row = "contrib",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)
Graph of column variables
fviz_ca_col(res.ca, col.col = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)
fviz_ca_col(res.ca, col.col = "contrib",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)
Quality of column representation
“A cos2 closed to 1 corresponds to a column/row variables that are
well represented on the factor map.”
fviz_cos2(res.ca, choice = "col", axes = 1:2)
Asymmetric biplot
“If the angle between two arrows is acute, then their is a strong
association between the corresponding row and column.
To interpret the distance between rows and and a column you should
perpendicularly project row points on the column arrow.”
fviz_ca_biplot(res.ca,
map ="rowprincipal", arrow = c(TRUE, TRUE),
repel = TRUE)
fviz_ca_biplot(res.ca,
map ="colprincipal", arrow = c(TRUE, TRUE),
repel = TRUE)
Export the results
biplot.ca <- fviz_ca_biplot(res.ca, repel = T)
scree.plot <- fviz_eig(res.ca)
library(ggpubr)
ggexport(plotlist = list(scree.plot, biplot.ca),
filename = "CA.pdf")
write.infile(res.ca, "ca.csv", sep = ";")
Run a similar analysis on the data you collected.
Sample: student-driven sample of heterosexual
couples in their 40s (n = 31), St.Petersburg, Russia (2023)
Get the data
simple_coa <- read.csv(choose.files(), encoding = "UTF-8") # pick the csv
names(simple_coa)
table(
simple_coa$Laundry,
simple_coa$Breakfast) # you can crosstab the pairs of columns
sum_total <- (table(t(simple_coa[,2:14])))
sum_total # calculate sum totals for a summary
rownames <-
c(
"Laundry",
"Main_meal",
"Dinner",
"Breakfast",
"Tidying",
"Dishes",
"Shopping",
"Official",
"Driving",
"Finances",
"Insurance",
"Repairs",
"Holidays"
)
colnames <- c("Wife", "Alternating", "Husband", "Jointly", "NA")
hc <- matrix(c(21,7,0,3,0,
13,9,5,4,0,
11,12,3,5,0,
12,8,3,6,2,
11,7,3,10,0,
5,14,4,6,2,
7,9,5,10,0,
7,3,10,6,5,
1,5,14,5,6,
3,3,7,13,5,
1,4,8,10,8,
3,0,16,10,0,
9,2,2,15,3
) ,
nrow = 13,
byrow = T)
rownames(hc) <- rownames
colnames(hc) <- colnames
head(hc)
Graph contingency tables and run a chi-square test
Pick the way to proceed further: without NAs (option 1)–better for
comparability, with NAs (option 2, columns 1-4)–more observations and
true to the data collected.
dt2 <- as.table(as.matrix(hc[ , 1:4]))
balloonplot(
t(dt2),
main = "housetasks",
xlab = "",
ylab = "",
label = FALSE,
show.margins = FALSE
)
dt2 <- as.table(as.matrix(hc))
balloonplot(
t(dt2),
main = "housetasks",
xlab = "",
ylab = "",
label = FALSE,
show.margins = FALSE
)
(Further analysis is done on full data.)
chisq.test(hc)
chisq.test(hc)$stdres
chisq.test(hc)$exp # share of expected counts below 5 should not exceed 20% of all counts! I recommend excluding NAs.
Compute CA
res2.ca <- CA(hc, graph = T)
summary(res2.ca)
res3.ca <- CA(hc, graph = T, col.sup = 5, row.sup = 7)
Eigenvalues / Inertia
res2.ca$eig
fviz_screeplot(res2.ca) +
geom_hline(yintercept = 25.0, linetype = 2, color = "red")
Biplot
fviz_ca_biplot(res2.ca, repel = TRUE, axes = 1:2)
Graph of row variables
fviz_ca_row(res2.ca, repel = TRUE)
fviz_ca_row(res2.ca, alpha.row = "cos2", repel = T)
corrplot(res2.ca$row$cos2, is.corr = FALSE)
Contributions of rows to the dimensions
corrplot(res2.ca$row$contrib, is.corr = FALSE)
fviz_contrib(res2.ca, choice = "row", axes = 1, top = 10)
fviz_contrib(res2.ca, choice = "row", axes = 2, top = 10)
fviz_contrib(res2.ca, choice = "row", axes = 1:2, top = 10)
fviz_ca_row(res2.ca, col.row = "contrib",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)
Graph of column variables
fviz_ca_col(res2.ca, col.col = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)
fviz_ca_row(res2.ca, col.row = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)
Quality of column representation
fviz_cos2(res2.ca, choice = "col", axes = 1:2)
Asymmetric biplots
fviz_ca_biplot(res2.ca,
map ="rowprincipal", arrow = c(TRUE, TRUE),
repel = TRUE)
fviz_ca_biplot(res2.ca,
map ="colprincipal", arrow = c(TRUE, TRUE),
repel = TRUE)
Export the results
biplot2.ca <- fviz_ca_biplot(res2.ca)
scree2.plot <- fviz_eig(res2.ca)
ggexport(plotlist = list(scree2.plot,
biplot2.ca),
filename = "CA2.pdf")
write.infile(res2.ca, "ca2.csv", sep = ";")
Self-check questions:
- Give a two-sentence summary of your CA on the collected data.
- Compare the example with the collected data analysis: Which CA keep
more information in? What are the most differentiating household tasks
in the two cases? Can you summarize the difference in 1-2
sentences?
- What behavioral/sociological conclusion could you make based on the
analysis?
- What recommendation could you give to businesses targeting these or
similar household?
Next time:
A new turn on crosstabs: Multiple Correspondence
Analysis
Browsing through the press release https://www.levada.ru/en/2018/10/12/happiness/, you
stumble upon the following cross-tabulation: https://www.levada.ru/cp/wp-content/uploads/2018/09/Schaste_tab..pdf
Follow the routine shown in https://rpubs.com/shirokaner/coa to create a cross-tab
out of vectors of numbers and then run multiple correspondence analyses
on the data.
Task:
Examine the original cross tabulation and make sure to leave only
relevant numbers in your analysis and remember that chi-square only
works properly on raw counts, not percent.
Three correspondence maps are to be done (pick any of them):
- happy-scale by sociodemographics (age, marital status, and
income);
- widespread sources of happiness by sociodemographics; and
- widespread sources of unhappiness by sociodemographics.
Some prepared numbers for the analyses can be found below:
# library(datapasta)
# vector_paste()
happy <- c(22, 28, 20, 20, 23, 19, 25, 16, 21, 30,
48, 52, 50, 41, 50, 39, 48, 34, 50, 54,
19, 13, 17, 26, 17, 26, 15, 27, 20, 10,
6, 4, 6, 7, 4, 11, 6, 13, 4, 3,
6, 4, 6, 7, 6, 6, 5, 10, 5, 3)
hp_source <- c(74, 70, 81, 70, 79, 68, 53, 72, 73, 75,
19, 23, 13, 20, 15, 23, 31, 18, 19, 19,
18, 20, 20, 14, 18, 14, 23, 13, 15, 25,
12, 12, 11, 14, 11, 17, 11, 14, 12, 12,
5, 4, 4, 7, 5, 1, 7, 3, 4, 7)
uhp_source <- c(54, 56, 57, 50, 58, 50, 42, 54, 54, 50,
17, 31, 18, 10, 19, 9, 26, 12, 19, 22,
15, 2, 9, 26, 13, 22, 9, 20, 14, 10,
11, 4, 10, 14, 6, 18, 10, 12, 9, 12,
9, 10, 8, 9, 7, 10, 13, 10, 7, 13)
coln <- c("18-34", "35-54", "55+", "Partnered", "Wid_Div", "Single", "Lower_Cl", "Middle_Cl", "Upper_Cl")
rown <- c("Def_YES", "Rather_YES", "Rather_NO", "Def_NO", "DK")
rown <- c("Family+", "Relationships+", "Work_Earnings+", "Health+", "Hobbies")
rown <- c("Work_Earnings-", "Ruling_Pwrs", "Health-", "Family-", "Intimacy")
LS0tDQp0aXRsZTogIkNvcnJlc3BvbmRlbmNlIEFuYWx5c2lzIC0gUmVwbGljYXRpb24iDQphdXRob3I6ICJBbm5hIFNoaXJva2Fub3ZhIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCBlcnJvciA9IEZBTFNFLCBldmFsID0gRkFMU0UpDQpgYGANCg0KIyMgUmVwbGljYXRlIHRoZSBjb3JyZXNwb25kZW5jZSBhbmFseXNpcyAoQ0EpIG9uIGhvdXNlaG9sZCBjaG9yZXMuDQoNClNvdXJjZTogPGh0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvYXJ0aWNsZXMvMzEtcHJpbmNpcGFsLWNvbXBvbmVudC1tZXRob2RzLWluLXItcHJhY3RpY2FsLWd1aWRlLzExMy1jYS1jb3JyZXNwb25kZW5jZS1hbmFseXNpcy1pbi1yLWVzc2VudGlhbHMvPg0KDQojIyMgR2V0IHRoZSBkYXRhDQoNCkEgR2VybWFuIHNhbXBsZSBpbiB5b3VuZywgbWFycmllZCwgaGV0ZXJvc2V4dWFsIGNvdXBsZXMgaW4gdGhlIGxhdGUgMTk3MHMsIHNlZSBtb3JlIDxodHRwczovL3d3dy50YW5kZm9ubGluZS5jb20vZG9pL2Ficy8xMC4xMjA3L1MxNTMyNzkwNk1CUjM0MDNfND4NCg0KYGBge3J9DQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpoZWFkKGhvdXNldGFza3MpDQpgYGANCg0KIyMjIEdyYXBoIGNvbnRpbmdlbmN5IHRhYmxlcyBhbmQgcnVuIGEgY2hpLXNxdWFyZSB0ZXN0IA0KDQpgYGB7cn0NCmxpYnJhcnkoZ3Bsb3RzKQ0KZHQgPC0gYXMudGFibGUoYXMubWF0cml4KGhvdXNldGFza3MpKQ0KYmFsbG9vbnBsb3QoDQogIHQoZHQpLA0KICBtYWluID0gImhvdXNldGFza3MiLA0KICB4bGFiID0gIiIsDQogIHlsYWIgPSAiIiwNCiAgbGFiZWwgPSBGLA0KICBzaG93Lm1hcmdpbnMgPSBGQUxTRQ0KKQ0KYGBgDQoNCmBgYHtyfQ0KY2hpc3EudGVzdChob3VzZXRhc2tzKQ0KY2hpc3EudGVzdChob3VzZXRhc2tzKSRzdGRyZXMNCmBgYA0KDQojIyMgQ29tcHV0ZSBDQQ0KDQpgYGB7cn0NCmxpYnJhcnkoRmFjdG9NaW5lUikNCnJlcy5jYSA8LSBDQShob3VzZXRhc2tzLCBncmFwaCA9IEZBTFNFKSAjIGFyZ3VtZW50IG5jcDogbnVtYmVyIG9mIGRpbWVuc2lvbnMga2VwdCBpbiB0aGUgZmluYWwgcmVzdWx0cw0KcHJpbnQocmVzLmNhKQ0KYGBgDQoNCiMjIyBFaWdlbnZhbHVlcyAvIEluZXJ0aWENCg0KIk91ciBkYXRhIGNvbnRhaW5zIDEzIHJvd3MgYW5kIDQgY29sdW1ucy4NCg0KSWYgdGhlIGRhdGEgd2VyZSByYW5kb20sIHRoZSBleHBlY3RlZCB2YWx1ZSBvZiB0aGUgZWlnZW52YWx1ZSBmb3IgZWFjaCBheGlzIHdvdWxkIGJlIDEvKG5yb3coaG91c2V0YXNrcyktMSkgPSAxLzEyID0gOC4zMyUgaW4gdGVybXMgb2Ygcm93cy4NCg0KTGlrZXdpc2UsIHRoZSBhdmVyYWdlIGF4aXMgc2hvdWxkIGFjY291bnQgZm9yIDEvKG5jb2woaG91c2V0YXNrcyktMSkgPSAxLzMgPSAzMy4zMyUgaW4gdGVybXMgb2YgdGhlIDQgY29sdW1ucy4iDQoNCmBgYHtyfQ0KcmVzLmNhJGVpZw0KZnZpel9zY3JlZXBsb3QocmVzLmNhKSArDQogZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMzMuMzMsIGxpbmV0eXBlID0gMiwgY29sb3IgPSAicmVkIikNCmBgYA0KDQojIyMgQmlwbG90DQoNCiJTeW1tZXRyaWMgcGxvdCByZXByZXNlbnRzIHRoZSByb3cgYW5kIGNvbHVtbiBwcm9maWxlcyBzaW11bHRhbmVvdXNseSBpbiBhIGNvbW1vbiBzcGFjZS4gSW4gdGhpcyBjYXNlLCBvbmx5IHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHJvdyBwb2ludHMgb3IgdGhlIGRpc3RhbmNlIGJldHdlZW4gY29sdW1uIHBvaW50cyBjYW4gYmUgcmVhbGx5IGludGVycHJldGVkLg0KDQpUaGUgZGlzdGFuY2UgYmV0d2VlbiBhbnkgcm93IGFuZCBjb2x1bW4gaXRlbXMgaXMgbm90IG1lYW5pbmdmdWwhIFlvdSBjYW4gb25seSBtYWtlIGEgZ2VuZXJhbCBzdGF0ZW1lbnRzIGFib3V0IHRoZSBvYnNlcnZlZCBwYXR0ZXJuLg0KDQpJbiBvcmRlciB0byBpbnRlcnByZXQgdGhlIGRpc3RhbmNlIGJldHdlZW4gY29sdW1uIGFuZCByb3cgcG9pbnRzLCB0aGUgY29sdW1uIHByb2ZpbGVzIG11c3QgYmUgcHJlc2VudGVkIGluIHJvdyBzcGFjZSBvciB2aWNlIHZlcnNhLiBUaGlzIHR5cGUgb2YgbWFwIGlzIGNhbGxlZCBhc3ltbWV0cmljIGJpcGxvdC4iDQoNCmBgYHtyfQ0KZnZpel9jYV9iaXBsb3QocmVzLmNhLCByZXBlbCA9IFRSVUUpDQpgYGANCg0KIyMjIEdyYXBoIG9mIHJvdyB2YXJpYWJsZXMNCg0KIklmIGEgcm93IGl0ZW0gaXMgd2VsbCByZXByZXNlbnRlZCBieSB0d28gZGltZW5zaW9ucywgdGhlIHN1bSBvZiB0aGUgY29zMiBpcyBjbG9zZWQgdG8gb25lLiBGb3Igc29tZSBvZiB0aGUgcm93IGl0ZW1zLCBtb3JlIHRoYW4gMiBkaW1lbnNpb25zIGFyZSByZXF1aXJlZCB0byBwZXJmZWN0bHkgcmVwcmVzZW50IHRoZSBkYXRhLiINCg0KYGBge3J9DQpmdml6X2NhX3JvdyhyZXMuY2EsIHJlcGVsID0gVFJVRSkNCmZ2aXpfY2Ffcm93KHJlcy5jYSwgYWxwaGEucm93ID0gImNvczIiLCByZXBlbCA9IFRSVUUpDQpsaWJyYXJ5KGNvcnJwbG90KQ0KY29ycnBsb3QocmVzLmNhJHJvdyRjb3MyLCBpcy5jb3JyID0gRkFMU0UpDQpgYGANCg0KIyMjIENvbnRyaWJ1dGlvbnMgb2Ygcm93cyB0byB0aGUgZGltZW5zaW9ucw0KDQoiUm93cyB0aGF0IGNvbnRyaWJ1dGUgdGhlIG1vc3QgdG8gRGltLjEgYW5kIERpbS4yIGFyZSB0aGUgbW9zdCBpbXBvcnRhbnQgaW4gZXhwbGFpbmluZyB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEgc2V0LiINCg0KIkl04oCZcyBwb3NzaWJsZSB0byB1c2UgdGhlIGZ1bmN0aW9uIGBjb3JycGxvdCgpJyB0byBoaWdobGlnaHQgdGhlIG1vc3QgY29udHJpYnV0aW5nIHJvdyBwb2ludHMgZm9yIGVhY2ggZGltZW5zaW9uOiINCg0KYGBge3J9DQpjb3JycGxvdChyZXMuY2Ekcm93JGNvbnRyaWIsIGlzLmNvcnIgPSBGQUxTRSkNCmZ2aXpfY29udHJpYihyZXMuY2EsIGNob2ljZSA9ICJyb3ciLCBheGVzID0gMSwgdG9wID0gMTApDQpmdml6X2NvbnRyaWIocmVzLmNhLCBjaG9pY2UgPSAicm93IiwgYXhlcyA9IDIsIHRvcCA9IDEwKQ0KZnZpel9jb250cmliKHJlcy5jYSwgY2hvaWNlID0gInJvdyIsIGF4ZXMgPSAxOjIsIHRvcCA9IDEwKQ0KZnZpel9jYV9yb3cocmVzLmNhLCBjb2wucm93ID0gImNvbnRyaWIiLA0KICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpLCANCiAgICAgICAgICAgICByZXBlbCA9IFRSVUUpDQpgYGANCg0KIyMjIEdyYXBoIG9mIGNvbHVtbiB2YXJpYWJsZXMNCg0KYGBge3J9DQpmdml6X2NhX2NvbChyZXMuY2EsIGNvbC5jb2wgPSAiY29zMiIsIA0KICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpLA0KICAgICAgICAgICAgIHJlcGVsID0gVFJVRSkNCmZ2aXpfY2FfY29sKHJlcy5jYSwgY29sLmNvbCA9ICJjb250cmliIiwNCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwgDQogICAgICAgICAgICAgcmVwZWwgPSBUUlVFKQ0KYGBgDQoNCiMjIyBRdWFsaXR5IG9mIGNvbHVtbiByZXByZXNlbnRhdGlvbg0KDQoiQSBjb3MyIGNsb3NlZCB0byAxIGNvcnJlc3BvbmRzIHRvIGEgY29sdW1uL3JvdyB2YXJpYWJsZXMgdGhhdCBhcmUgd2VsbCByZXByZXNlbnRlZCBvbiB0aGUgZmFjdG9yIG1hcC4iDQoNCmBgYHtyfQ0KZnZpel9jb3MyKHJlcy5jYSwgY2hvaWNlID0gImNvbCIsIGF4ZXMgPSAxOjIpDQpgYGANCg0KIyMjIEFzeW1tZXRyaWMgYmlwbG90DQoNCiJJZiB0aGUgYW5nbGUgYmV0d2VlbiB0d28gYXJyb3dzIGlzIGFjdXRlLCB0aGVuIHRoZWlyIGlzIGEgc3Ryb25nIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIGNvcnJlc3BvbmRpbmcgcm93IGFuZCBjb2x1bW4uDQoNClRvIGludGVycHJldCB0aGUgZGlzdGFuY2UgYmV0d2VlbiByb3dzIGFuZCBhbmQgYSBjb2x1bW4geW91IHNob3VsZCBwZXJwZW5kaWN1bGFybHkgcHJvamVjdCByb3cgcG9pbnRzIG9uIHRoZSBjb2x1bW4gYXJyb3cuIg0KDQpgYGB7cn0NCmZ2aXpfY2FfYmlwbG90KHJlcy5jYSwgDQogICAgICAgICAgICAgICBtYXAgPSJyb3dwcmluY2lwYWwiLCBhcnJvdyA9IGMoVFJVRSwgVFJVRSksDQogICAgICAgICAgICAgICByZXBlbCA9IFRSVUUpDQpmdml6X2NhX2JpcGxvdChyZXMuY2EsIA0KICAgICAgICAgICAgICAgbWFwID0iY29scHJpbmNpcGFsIiwgYXJyb3cgPSBjKFRSVUUsIFRSVUUpLA0KICAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFKQ0KYGBgDQoNCiMjIyBFeHBvcnQgdGhlIHJlc3VsdHMNCg0KYGBge3J9DQpiaXBsb3QuY2EgPC0gZnZpel9jYV9iaXBsb3QocmVzLmNhLCByZXBlbCA9IFQpDQpzY3JlZS5wbG90IDwtIGZ2aXpfZWlnKHJlcy5jYSkNCmxpYnJhcnkoZ2dwdWJyKQ0KZ2dleHBvcnQocGxvdGxpc3QgPSBsaXN0KHNjcmVlLnBsb3QsIGJpcGxvdC5jYSksIA0KICAgICAgICAgZmlsZW5hbWUgPSAiQ0EucGRmIikNCndyaXRlLmluZmlsZShyZXMuY2EsICJjYS5jc3YiLCBzZXAgPSAiOyIpDQpgYGANCg0KIyMgUnVuIGEgc2ltaWxhciBhbmFseXNpcyBvbiB0aGUgZGF0YSB5b3UgY29sbGVjdGVkLg0KDQoqKlNhbXBsZSoqOiBzdHVkZW50LWRyaXZlbiBzYW1wbGUgb2YgaGV0ZXJvc2V4dWFsIGNvdXBsZXMgaW4gdGhlaXIgNDBzIChuID0gMzEpLCBTdC5QZXRlcnNidXJnLCBSdXNzaWEgKDIwMjMpDQoNCiMjIyBHZXQgdGhlIGRhdGENCg0KYGBge3J9DQpzaW1wbGVfY29hIDwtIHJlYWQuY3N2KGNob29zZS5maWxlcygpLCBlbmNvZGluZyA9ICJVVEYtOCIpICMgcGljayB0aGUgY3N2DQpuYW1lcyhzaW1wbGVfY29hKQ0KdGFibGUoDQogIHNpbXBsZV9jb2EkTGF1bmRyeSwNCiAgc2ltcGxlX2NvYSRCcmVha2Zhc3QpICMgeW91IGNhbiBjcm9zc3RhYiB0aGUgcGFpcnMgb2YgY29sdW1ucw0Kc3VtX3RvdGFsIDwtICh0YWJsZSh0KHNpbXBsZV9jb2FbLDI6MTRdKSkpDQpzdW1fdG90YWwgIyBjYWxjdWxhdGUgc3VtIHRvdGFscyBmb3IgYSBzdW1tYXJ5DQpgYGANCg0KYGBge3J9DQpyb3duYW1lcyA8LQ0KICBjKA0KICAgICJMYXVuZHJ5IiwNCiAgICAiTWFpbl9tZWFsIiwNCiAgICAiRGlubmVyIiwNCiAgICAiQnJlYWtmYXN0IiwNCiAgICAiVGlkeWluZyIsDQogICAgIkRpc2hlcyIsDQogICAgIlNob3BwaW5nIiwNCiAgICAiT2ZmaWNpYWwiLA0KICAgICJEcml2aW5nIiwNCiAgICAiRmluYW5jZXMiLA0KICAgICJJbnN1cmFuY2UiLA0KICAgICJSZXBhaXJzIiwNCiAgICAiSG9saWRheXMiDQogICkNCmNvbG5hbWVzIDwtIGMoIldpZmUiLCAiQWx0ZXJuYXRpbmciLCAiSHVzYmFuZCIsICJKb2ludGx5IiwgIk5BIikNCg0KaGMgPC0gbWF0cml4KGMoMjEsNywwLDMsMCwgDQogICAgICAgICAgICAgICAxMyw5LDUsNCwwLA0KICAgICAgICAgICAgICAgMTEsMTIsMyw1LDAsDQogICAgICAgICAgICAgICAxMiw4LDMsNiwyLA0KICAgICAgICAgICAgICAgMTEsNywzLDEwLDAsDQogICAgICAgICAgICAgICA1LDE0LDQsNiwyLA0KICAgICAgICAgICAgICAgNyw5LDUsMTAsMCwNCiAgICAgICAgICAgICAgIDcsMywxMCw2LDUsDQogICAgICAgICAgICAgICAxLDUsMTQsNSw2LA0KICAgICAgICAgICAgICAgMywzLDcsMTMsNSwNCiAgICAgICAgICAgICAgIDEsNCw4LDEwLDgsDQogICAgICAgICAgICAgICAzLDAsMTYsMTAsMCwNCiAgICAgICAgICAgICAgIDksMiwyLDE1LDMNCiAgICAgICAgICAgICAgICkgLCANCiAgICAgICAgICAgICBucm93ID0gMTMsIA0KICAgICAgICAgICAgIGJ5cm93ID0gVCkNCnJvd25hbWVzKGhjKSA8LSByb3duYW1lcw0KY29sbmFtZXMoaGMpIDwtIGNvbG5hbWVzDQpoZWFkKGhjKQ0KYGBgDQoNCiMjIyBHcmFwaCBjb250aW5nZW5jeSB0YWJsZXMgYW5kIHJ1biBhIGNoaS1zcXVhcmUgdGVzdA0KDQpQaWNrIHRoZSB3YXkgdG8gcHJvY2VlZCBmdXJ0aGVyOiB3aXRob3V0IE5BcyAob3B0aW9uIDEpLS1iZXR0ZXIgZm9yIGNvbXBhcmFiaWxpdHksIHdpdGggTkFzIChvcHRpb24gMiwgY29sdW1ucyAxLTQpLS1tb3JlIG9ic2VydmF0aW9ucyBhbmQgdHJ1ZSB0byB0aGUgZGF0YSBjb2xsZWN0ZWQuDQoNCmBgYHtyfQ0KZHQyIDwtIGFzLnRhYmxlKGFzLm1hdHJpeChoY1sgLCAxOjRdKSkNCmJhbGxvb25wbG90KA0KICB0KGR0MiksDQogIG1haW4gPSAiaG91c2V0YXNrcyIsDQogIHhsYWIgPSAiIiwNCiAgeWxhYiA9ICIiLA0KICBsYWJlbCA9IEZBTFNFLA0KICBzaG93Lm1hcmdpbnMgPSBGQUxTRQ0KKQ0KZHQyIDwtIGFzLnRhYmxlKGFzLm1hdHJpeChoYykpDQpiYWxsb29ucGxvdCgNCiAgdChkdDIpLA0KICBtYWluID0gImhvdXNldGFza3MiLA0KICB4bGFiID0gIiIsDQogIHlsYWIgPSAiIiwNCiAgbGFiZWwgPSBGQUxTRSwNCiAgc2hvdy5tYXJnaW5zID0gRkFMU0UNCikNCmBgYA0KDQooRnVydGhlciBhbmFseXNpcyBpcyBkb25lIG9uIGZ1bGwgZGF0YS4pDQoNCmBgYHtyfQ0KY2hpc3EudGVzdChoYykNCmNoaXNxLnRlc3QoaGMpJHN0ZHJlcw0KY2hpc3EudGVzdChoYykkZXhwICMgc2hhcmUgb2YgZXhwZWN0ZWQgY291bnRzIGJlbG93IDUgc2hvdWxkIG5vdCBleGNlZWQgMjAlIG9mIGFsbCBjb3VudHMhIEkgcmVjb21tZW5kIGV4Y2x1ZGluZyBOQXMuDQpgYGANCg0KIyMjIENvbXB1dGUgQ0ENCg0KYGBge3J9DQpyZXMyLmNhIDwtIENBKGhjLCBncmFwaCA9IFQpDQpzdW1tYXJ5KHJlczIuY2EpDQoNCmBgYA0KDQpgYGB7cn0NCnJlczMuY2EgPC0gQ0EoaGMsIGdyYXBoID0gVCwgY29sLnN1cCA9IDUsIHJvdy5zdXAgPSA3KQ0KYGBgDQoNCg0KIyMjIEVpZ2VudmFsdWVzIC8gSW5lcnRpYQ0KDQpgYGB7cn0NCnJlczIuY2EkZWlnDQpmdml6X3NjcmVlcGxvdChyZXMyLmNhKSArDQogZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMjUuMCwgbGluZXR5cGUgPSAyLCBjb2xvciA9ICJyZWQiKQ0KYGBgDQojIyMgQmlwbG90DQoNCmBgYHtyfQ0KZnZpel9jYV9iaXBsb3QocmVzMi5jYSwgcmVwZWwgPSBUUlVFLCBheGVzID0gMToyKQ0KYGBgDQoNCiMjIyBHcmFwaCBvZiByb3cgdmFyaWFibGVzDQoNCmBgYHtyfQ0KZnZpel9jYV9yb3cocmVzMi5jYSwgcmVwZWwgPSBUUlVFKQ0KZnZpel9jYV9yb3cocmVzMi5jYSwgYWxwaGEucm93ID0gImNvczIiLCByZXBlbCA9IFQpDQpjb3JycGxvdChyZXMyLmNhJHJvdyRjb3MyLCBpcy5jb3JyID0gRkFMU0UpDQpgYGANCg0KIyMjIENvbnRyaWJ1dGlvbnMgb2Ygcm93cyB0byB0aGUgZGltZW5zaW9ucw0KDQpgYGB7cn0NCmNvcnJwbG90KHJlczIuY2Ekcm93JGNvbnRyaWIsIGlzLmNvcnIgPSBGQUxTRSkNCmZ2aXpfY29udHJpYihyZXMyLmNhLCBjaG9pY2UgPSAicm93IiwgYXhlcyA9IDEsIHRvcCA9IDEwKQ0KZnZpel9jb250cmliKHJlczIuY2EsIGNob2ljZSA9ICJyb3ciLCBheGVzID0gMiwgdG9wID0gMTApDQpmdml6X2NvbnRyaWIocmVzMi5jYSwgY2hvaWNlID0gInJvdyIsIGF4ZXMgPSAxOjIsIHRvcCA9IDEwKQ0KZnZpel9jYV9yb3cocmVzMi5jYSwgY29sLnJvdyA9ICJjb250cmliIiwNCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwgDQogICAgICAgICAgICAgcmVwZWwgPSBUUlVFKQ0KYGBgDQoNCiMjIyBHcmFwaCBvZiBjb2x1bW4gdmFyaWFibGVzDQoNCmBgYHtyfQ0KZnZpel9jYV9jb2wocmVzMi5jYSwgY29sLmNvbCA9ICJjb3MyIiwgDQogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksDQogICAgICAgICAgICAgcmVwZWwgPSBUUlVFKQ0KZnZpel9jYV9yb3cocmVzMi5jYSwgY29sLnJvdyA9ICJjb3MyIiwgDQogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksDQogICAgICAgICAgICAgcmVwZWwgPSBUUlVFKQ0KYGBgDQoNCiMjIyBRdWFsaXR5IG9mIGNvbHVtbiByZXByZXNlbnRhdGlvbg0KDQpgYGB7cn0NCmZ2aXpfY29zMihyZXMyLmNhLCBjaG9pY2UgPSAiY29sIiwgYXhlcyA9IDE6MikNCmBgYA0KDQojIyMgQXN5bW1ldHJpYyBiaXBsb3RzDQoNCmBgYHtyfQ0KZnZpel9jYV9iaXBsb3QocmVzMi5jYSwgDQogICAgICAgICAgICAgICBtYXAgPSJyb3dwcmluY2lwYWwiLCBhcnJvdyA9IGMoVFJVRSwgVFJVRSksDQogICAgICAgICAgICAgICByZXBlbCA9IFRSVUUpDQpmdml6X2NhX2JpcGxvdChyZXMyLmNhLCANCiAgICAgICAgICAgICAgIG1hcCA9ImNvbHByaW5jaXBhbCIsIGFycm93ID0gYyhUUlVFLCBUUlVFKSwNCiAgICAgICAgICAgICAgIHJlcGVsID0gVFJVRSkNCmBgYA0KIyMjIEV4cG9ydCB0aGUgcmVzdWx0cw0KDQpgYGB7cn0NCmJpcGxvdDIuY2EgPC0gZnZpel9jYV9iaXBsb3QocmVzMi5jYSkNCnNjcmVlMi5wbG90IDwtIGZ2aXpfZWlnKHJlczIuY2EpDQpnZ2V4cG9ydChwbG90bGlzdCA9IGxpc3Qoc2NyZWUyLnBsb3QsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGJpcGxvdDIuY2EpLCANCiAgICAgICAgIGZpbGVuYW1lID0gIkNBMi5wZGYiKQ0Kd3JpdGUuaW5maWxlKHJlczIuY2EsICJjYTIuY3N2Iiwgc2VwID0gIjsiKQ0KYGBgDQoNCg0KDQpTZWxmLWNoZWNrIHF1ZXN0aW9uczoNCg0KMS4gR2l2ZSBhIHR3by1zZW50ZW5jZSBzdW1tYXJ5IG9mIHlvdXIgQ0Egb24gdGhlIGNvbGxlY3RlZCBkYXRhLg0KMi4gQ29tcGFyZSB0aGUgZXhhbXBsZSB3aXRoIHRoZSBjb2xsZWN0ZWQgZGF0YSBhbmFseXNpczogV2hpY2ggQ0Ega2VlcCBtb3JlIGluZm9ybWF0aW9uIGluPyBXaGF0IGFyZSB0aGUgbW9zdCBkaWZmZXJlbnRpYXRpbmcgaG91c2Vob2xkIHRhc2tzIGluIHRoZSB0d28gY2FzZXM/IENhbiB5b3Ugc3VtbWFyaXplIHRoZSBkaWZmZXJlbmNlIGluIDEtMiBzZW50ZW5jZXM/DQozLiBXaGF0IGJlaGF2aW9yYWwvc29jaW9sb2dpY2FsIGNvbmNsdXNpb24gY291bGQgeW91IG1ha2UgYmFzZWQgb24gdGhlIGFuYWx5c2lzPw0KNC4gV2hhdCByZWNvbW1lbmRhdGlvbiBjb3VsZCB5b3UgZ2l2ZSB0byBidXNpbmVzc2VzIHRhcmdldGluZyB0aGVzZSBvciBzaW1pbGFyIGhvdXNlaG9sZD8NCg0KIyMjIE5leHQgdGltZToNCg0KKipBIG5ldyB0dXJuIG9uIGNyb3NzdGFiczogTXVsdGlwbGUgQ29ycmVzcG9uZGVuY2UgQW5hbHlzaXMqKg0KDQpCcm93c2luZyB0aHJvdWdoIHRoZSBwcmVzcyByZWxlYXNlIDxodHRwczovL3d3dy5sZXZhZGEucnUvZW4vMjAxOC8xMC8xMi9oYXBwaW5lc3MvPiwgeW91IHN0dW1ibGUgdXBvbiB0aGUgZm9sbG93aW5nIGNyb3NzLXRhYnVsYXRpb246IDxodHRwczovL3d3dy5sZXZhZGEucnUvY3Avd3AtY29udGVudC91cGxvYWRzLzIwMTgvMDkvU2NoYXN0ZV90YWIuLnBkZj4NCg0KRm9sbG93IHRoZSByb3V0aW5lIHNob3duIGluIDxodHRwczovL3JwdWJzLmNvbS9zaGlyb2thbmVyL2NvYT4gdG8gY3JlYXRlIGEgY3Jvc3MtdGFiIG91dCBvZiB2ZWN0b3JzIG9mIG51bWJlcnMgYW5kIHRoZW4gcnVuIG11bHRpcGxlIGNvcnJlc3BvbmRlbmNlIGFuYWx5c2VzIG9uIHRoZSBkYXRhLg0KDQpUYXNrOg0KDQpFeGFtaW5lIHRoZSBvcmlnaW5hbCBjcm9zcyB0YWJ1bGF0aW9uIGFuZCBtYWtlIHN1cmUgdG8gbGVhdmUgb25seSByZWxldmFudCBudW1iZXJzIGluIHlvdXIgYW5hbHlzaXMgYW5kIHJlbWVtYmVyIHRoYXQgY2hpLXNxdWFyZSBvbmx5IHdvcmtzIHByb3Blcmx5IG9uIHJhdyBjb3VudHMsIG5vdCBwZXJjZW50Lg0KDQpUaHJlZSBjb3JyZXNwb25kZW5jZSBtYXBzIGFyZSB0byBiZSBkb25lIChwaWNrIGFueSBvZiB0aGVtKToNCg0KKDEpIGhhcHB5LXNjYWxlIGJ5IHNvY2lvZGVtb2dyYXBoaWNzIChhZ2UsIG1hcml0YWwgc3RhdHVzLCBhbmQgaW5jb21lKTsNCigyKSB3aWRlc3ByZWFkIHNvdXJjZXMgb2YgaGFwcGluZXNzIGJ5IHNvY2lvZGVtb2dyYXBoaWNzOyBhbmQNCigzKSB3aWRlc3ByZWFkIHNvdXJjZXMgb2YgdW5oYXBwaW5lc3MgYnkgc29jaW9kZW1vZ3JhcGhpY3MuDQoNClNvbWUgcHJlcGFyZWQgbnVtYmVycyBmb3IgdGhlIGFuYWx5c2VzIGNhbiBiZSBmb3VuZCBiZWxvdzoNCg0KYGBge3J9DQojIGxpYnJhcnkoZGF0YXBhc3RhKQ0KIyB2ZWN0b3JfcGFzdGUoKQ0KaGFwcHkgPC0gYygyMiwgMjgsIDIwLCAyMCwgMjMsIDE5LCAyNSwgMTYsIDIxLCAzMCwNCiAgNDgsIDUyLCA1MCwgNDEsIDUwLCAzOSwgNDgsIDM0LCA1MCwgNTQsDQogIDE5LCAxMywgMTcsIDI2LCAxNywgMjYsIDE1LCAyNywgMjAsIDEwLA0KICA2LCA0LCA2LCA3LCA0LCAxMSwgNiwgMTMsIDQsIDMsDQogIDYsIDQsIDYsIDcsIDYsIDYsIDUsIDEwLCA1LCAzKQ0KDQpocF9zb3VyY2UgPC0gIGMoNzQsIDcwLCA4MSwgNzAsIDc5LCA2OCwgNTMsIDcyLCA3MywgNzUsDQogIDE5LCAyMywgMTMsIDIwLCAxNSwgMjMsIDMxLCAxOCwgMTksIDE5LA0KICAxOCwgMjAsIDIwLCAxNCwgMTgsIDE0LCAyMywgMTMsIDE1LCAyNSwNCiAgMTIsIDEyLCAxMSwgMTQsIDExLCAxNywgMTEsIDE0LCAxMiwgMTIsDQogIDUsIDQsIDQsIDcsIDUsIDEsIDcsIDMsIDQsIDcpDQoNCnVocF9zb3VyY2UgPC0gYyg1NCwgNTYsIDU3LCA1MCwgNTgsIDUwLCA0MiwgNTQsIDU0LCA1MCwNCiAgICAgICAgICAgICAgICAxNywgMzEsIDE4LCAxMCwgMTksIDksIDI2LCAxMiwgMTksIDIyLA0KICAgICAgICAgICAgICAgIDE1LCAyLCA5LCAyNiwgMTMsIDIyLCA5LCAyMCwgMTQsIDEwLA0KICAgICAgICAgICAgICAgIDExLCA0LCAxMCwgMTQsIDYsIDE4LCAxMCwgMTIsIDksIDEyLA0KICAgICAgICAgICAgICAgIDksIDEwLCA4LCA5LCA3LCAxMCwgMTMsIDEwLCA3LCAxMykNCg0KY29sbiA8LSBjKCIxOC0zNCIsICIzNS01NCIsICI1NSsiLCAiUGFydG5lcmVkIiwgIldpZF9EaXYiLCAiU2luZ2xlIiwgIkxvd2VyX0NsIiwgIk1pZGRsZV9DbCIsICJVcHBlcl9DbCIpDQoNCnJvd24gPC0gYygiRGVmX1lFUyIsICJSYXRoZXJfWUVTIiwgIlJhdGhlcl9OTyIsICJEZWZfTk8iLCAiREsiKQ0KDQpyb3duIDwtIGMoIkZhbWlseSsiLCAiUmVsYXRpb25zaGlwcysiLCAiV29ya19FYXJuaW5ncysiLCAiSGVhbHRoKyIsICJIb2JiaWVzIikNCg0Kcm93biA8LSBjKCJXb3JrX0Vhcm5pbmdzLSIsICJSdWxpbmdfUHdycyIsICJIZWFsdGgtIiwgIkZhbWlseS0iLCAiSW50aW1hY3kiKQ0KYGBgDQoNCg==