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/

Get the data

A German sample in young, married, heterosexual couples in the late 1970s, see more https://www.tandfonline.com/doi/abs/10.1207/S15327906MBR3403_4

library(factoextra)
head(housetasks)

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:

  1. Give a two-sentence summary of your CA on the collected data.
  2. 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?
  3. What behavioral/sociological conclusion could you make based on the analysis?
  4. 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):

  1. happy-scale by sociodemographics (age, marital status, and income);
  2. widespread sources of happiness by sociodemographics; and
  3. 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==