Read, Clean, Recode, Merge
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Read
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Read files
folder <- "E:/Cinetic idei noi/Cinetic elevi"
file <- "M1 de introdus anotimpuri.xlsx"
setwd(folder)
Data <- rio::import(file.path(folder, file))
## Recode NA
Data <-
Data %>% # sum(is.na(Data)) = 5873
na_if("na") # sum(is.na(Data)) = 6199
## Variable names
nume <- c("Stim", "Varsta_amin", "Ano", "Val", "Viv", "Relv")
toate <- paste(nume, rep(1:15, each = length(nume)), sep = "_")
## Check that all variable names are consistent with column headers
if(toate %in% names(Data)){
cat("All column names are consistent.")
} else {
cat("Column names are NOT consistent. \n")
cat("Missmatches: \n ")
setdiff(toate, names(Data))
}
Sample descriptives
## Number of subjects
## Number of subjects per Protocol
Season Memories and Valence
Make data frames
## Exclude P6 & P7
Data_Season <-
Data %>%
dplyr::filter(!Protocol %in% c(6, 7))
## Melt to Long
# Data_Vara <- # pivot_longer() only in development version of tidyr... dont use now
# Data_Season %>% # devtools::install_github("tidyverse/tidyr")
# tidyr::pivot_longer(
# -c(1:5),
# #cols = starts_with("Ano"),
# names_to = c(".value", "var"),
# names_sep = "_",
# values_drop_na = TRUE
# )
Data_Season_melt <-
Data_Season %>%
gather(variable, value, -c(1:5)) %>%
mutate(group = readr::parse_number(variable)) %>%
mutate(variable = gsub("\\d","",x = variable)) %>%
spread(variable, value) %>%
rename_all(~stringr::str_replace_all(., "_", "")) %>% # delete the "_" at end
mutate(Ano = factor(Ano, levels = c("Vara", "Primavara", "Toamna", "Iarna"))) %>%
mutate_at(vars("Relv", "Val", "Varstaamin", "Viv"), funs(as.numeric(as.character(.))))
## Season data frames
# Data_Vara <-
# Data_Season_melt %>%
# filter(!is.na(Ano)) %>% # delete rows were there is no Ano
# filter(Ano == "Vara")
#
# Data_Primavara <-
# Data_Season_melt %>%
# filter(!is.na(Ano)) %>% # delete rows were there is no Ano
# filter(Ano == "Primavara")
#
# Data_Toamna <-
# Data_Season_melt %>%
# filter(!is.na(Ano)) %>% # delete rows were there is no Ano
# filter(Ano == "Toamna")
#
# Data_Iarna <-
# Data_Season_melt %>%
# filter(!is.na(Ano)) %>% # delete rows were there is no Ano
# filter(Ano == "Iarna")
#
#
# ## Excel downloadable DT tables
# Data_Vara %>%
# select(-Nume) %>%
# DT::datatable(
# extensions = 'Buttons',
# options = list(pageLength = 10,
# scrollX='500px',
# dom = 'Bfrtip',
# buttons = c('excel', "csv")))
#
# Data_Primavara %>%
# select(-Nume) %>%
# DT::datatable(
# extensions = 'Buttons',
# options = list(pageLength = 10,
# scrollX='500px',
# dom = 'Bfrtip',
# buttons = c('excel', "csv")))
#
# Data_Toamna %>%
# select(-Nume) %>%
# DT::datatable(
# extensions = 'Buttons',
# options = list(pageLength = 10,
# scrollX='500px',
# dom = 'Bfrtip',
# buttons = c('excel', "csv")))
#
# Data_Iarna %>%
# select(-Nume) %>%
# DT::datatable(
# extensions = 'Buttons',
# options = list(pageLength = 10,
# scrollX='500px',
# dom = 'Bfrtip',
# buttons = c('excel', "csv")))
cat("### Melt to Long Format")
Define Function for Plots
## Function for Ano Bar Plot
my_comparisons <-
gtools::combinations(n = length(unique(Data_Season_melt_nona$Ano)), r = 2, v = as.character(Data_Season_melt_nona$Ano), repeats.allowed = FALSE) %>%
as.data.frame() %>%
mutate_if(is.factor, as.character) %>%
purrr::pmap(list) %>%
lapply(unlist)
func_plot_ano <- function(df, y_var, y_var_lab, label.y_set = 7, yticks.by_set = 1, facet = FALSE){
if(facet){
facet <- "Protocol"
}else{
facet <- NULL
}
p <-
df %>%
ggpubr::ggbarplot(x = "Ano", y = y_var,
add = "mean_se",
color = "black", fill = "lightgray",
xlab = "Anotimp", ylab = y_var_lab,
label = TRUE, lab.nb.digits = 2, lab.pos= "in",
facet.by = facet) +
stat_compare_means(method = "anova",
label.x = 0.9, label.y = label.y_set) +
stat_compare_means(comparisons = my_comparisons,
label = "p.signif", method = "t.test", paired = FALSE, na.rm = TRUE)
ggpar(p, yticks.by = yticks.by_set) # the rating scale is 1-7
}
## Dodged
func_dodged_ano <- function(df, y_var, y_var_lab, facet = FALSE){
y_var<- sym(y_var)
if(facet) {
df <-
df %>%
mutate(Protocol = paste0("Protocol ", Protocol)) %>%
group_by(Protocol)
}
p <-
df %>%
dplyr::count(Ano, !!y_var) %>% # Group by, then count number in each group
mutate(pct = prop.table(n)) %>% # Calculate percent within each var
mutate(Val_fac = as.factor(!!y_var)) %>%
ggplot(aes(x = Ano, y = pct, fill = Val_fac, label = scales::percent(pct))) +
geom_col(position = 'dodge') +
geom_text(position = position_dodge(width = .9), # move to center of bars
vjust = -0.5, # nudge above top of bar
size = 3) +
scale_y_continuous(labels = scales::percent) +
{if(facet) facet_wrap(~Protocol, scales = "free", ncol = 1, nrow = 8)} +
ggtitle(y_var_lab) +
xlab("Anotimp") + ylab("Percentage %") +
guides(fill = guide_legend(title = "Value", nrow = 1)) +
scale_fill_grey(start = 0.8, end = 0.2, na.value = "red", aesthetics = "fill") +
theme(legend.position = "bottom", legend.direction = "horizontal",
legend.justification = c(0, 1), panel.border = element_rect(fill = NA, colour = "black"))
p
}
Plots of Seasons
## Test for Val -- works well
# Data_Season_melt_nona %>%
# ggpubr::ggbarplot(x = "Ano", y = "Val",
# add = "mean_se",
# color = "black", fill = "lightgray",
# xlab = "Anotimp", ylab = "Valenta",
# label = TRUE, lab.nb.digits = 2, lab.pos= "in") +
# stat_compare_means(method = "anova",
# label.x = 0.9, label.y = 7) +
# stat_compare_means(comparisons = my_comparisons,
# label = "p.signif", method = "t.test", paired = FALSE, na.rm = TRUE)
func_plot_ano(Data_Season_melt_nona, "Val", "Valenta")
Plots of Seasons by Protocol
Plots with proportion of values
# # Stacked - Test for Val -- works well
# Data_Season_melt_nona %>%
# dplyr::count(Ano, Val) %>% # Group by, then count number in each group
# mutate(pct = n/sum(n)) %>% # Calculate percent within each var; could use prop.table(n)
# mutate(Val_fac = as.factor(Val)) %>%
# ggplot(aes(Ano, n, fill = Val_fac)) +
# geom_bar(stat = "identity") +
# geom_text(aes(label = paste0(sprintf("%1.1f", pct*100), "%"), size = scales::rescale(pct, to=c(2, 5))),
# position = position_stack(vjust=0.5), show.legend = FALSE)
#
#
# # Dodged - Test for Val -- works well
# Data_Season_melt_nona %>%
# dplyr::count(Ano, Val) %>% # Group by, then count number in each group
# mutate(pct = prop.table(n)) %>% # Calculate percent within each var
# mutate(Val_fac = as.factor(Val)) %>%
# ggplot(aes(x = Ano, y = pct, fill = Val_fac, label = scales::percent(pct))) +
# geom_col(position = 'dodge') +
# geom_text(position = position_dodge(width = .9), # move to center of bars
# vjust = -0.5, # nudge above top of bar
# size = 3) +
# scale_y_continuous(labels = scales::percent) +
# xlab("Anotimp") + ylab("Percentage %") +
# guides(fill = guide_legend(title = "Value", nrow = 1)) +
# scale_fill_grey(start = 0.8, end = 0.2, na.value = "red", aesthetics = "fill") +
# theme(legend.position = "bottom", legend.direction = "horizontal", legend.justification = c(0, 1))
func_dodged_ano(Data_Season_melt_nona, "Val", "Valenta")
Plots with proportion of values by Protocol
Likert Plots for Season
# Proportions and z-scores
Prop_val <-
Data_Season_melt_nona %>%
dplyr::select(ID, Protocol, Ano, Val) %>%
group_by(Ano) %>%
mutate(
Val = as.factor(Val),
Val = forcats::fct_collapse(Val, low = c("1", "2", "3"), neutral = "4", high = c("5", "6", "7"))
) %>%
dplyr::count(Val) %>%
mutate(total = sum(n),
perc = 100*n/total)
cat("### Proportions - compared to 0.5 probability")
Proportions - compared to 0.5 probability
Proportions - Multiple comparisons
Pairwise comparisons using Pairwise comparison of proportions
Pairwise comparisons using Pairwise comparison of proportions (Fisher exact)
Proportions - Plot of Low-Neutral-High
Likert_val <-
Data_Season_melt_nona %>%
dplyr::select(ID, Protocol, group, Ano, Val) %>%
spread(key = Ano, value = Val) %>%
mutate_at(vars("Vara", "Primavara", "Toamna", "Iarna"), ~as.factor(.))
# Plots # library(likert)
Likertobj_Val <- likert(Likert_val[, c("Vara", "Primavara", "Toamna", "Iarna")], nlevels = 7) # here are percentages
Likertobj_Val_perc <- Likertobj_Val$results
# check if same with Prop dataframe above; or prop.table(table(Likert_val$Vara))
plot(Likertobj_Val, type = "bar",
centered = TRUE, center = 4, include.center = TRUE, # "4" is neutral
wrap = 30, low.color = 'burlywood', high.color = 'maroon') +
guides(fill = guide_legend(nrow = 1))
Likert Plots for Season
Scatter plot with correlation coefficient for all Seasons
Scatter plot with correlation coefficient for each Season
ggpubr::ggscatter(Anofreq_Val, x = "Freq_Ano", y = "Mean_Val",
color = "Ano", palette = "jco",
add = "reg.line", conf.int = TRUE,
xlim = c(0, 15), ylim = c(0, 8)) +
stat_cor(aes(color = Ano), method = "pearson", label.x = 11)
Session Info
R version 3.6.1 (2019-07-05)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 8.1 x64 (build 9600)
Matrix products: default
locale:
[1] LC_COLLATE=Romanian_Romania.1250 LC_CTYPE=Romanian_Romania.1250 LC_MONETARY=Romanian_Romania.1250 LC_NUMERIC=C
[5] LC_TIME=Romanian_Romania.1250
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] likert_1.3.5 xtable_1.8-4 fmsb_0.6.3 rio_0.5.16 scales_1.0.0
[6] ggpubr_0.2 magrittr_1.5 tadaatoolbox_0.16.1 summarytools_0.8.8 rstatix_0.2.0
[11] broom_0.5.2 PerformanceAnalytics_1.5.2 xts_0.11-2 zoo_1.8-4 psych_1.8.12
[16] plyr_1.8.4 forcats_0.4.0 stringr_1.4.0 dplyr_0.8.3 purrr_0.3.2
[21] readr_1.3.1 tidyr_1.0.0 tibble_2.1.3 ggplot2_3.2.1 tidyverse_1.2.1
[26] papaja_0.1.0.9842 pacman_0.5.1
loaded via a namespace (and not attached):
[1] colorspace_1.4-1 ggsignif_0.4.0 pryr_0.1.4 ellipsis_0.3.0 rstudioapi_0.8 DT_0.5 mvtnorm_1.0-11
[8] lubridate_1.7.4 xml2_1.2.0 codetools_0.2-16 mnormt_1.5-5 knitr_1.25 zeallot_0.1.0 pixiedust_0.8.6
[15] jsonlite_1.6 shiny_1.2.0 compiler_3.6.1 httr_1.4.0 backports_1.1.4 assertthat_0.2.1 Matrix_1.2-17
[22] lazyeval_0.2.2 cli_1.1.0 later_0.7.5 htmltools_0.3.6 tools_3.6.1 gtable_0.3.0 glue_1.3.1
[29] reshape2_1.4.3 Rcpp_1.0.2 carData_3.0-2 cellranger_1.1.0 vctrs_0.2.0 nlme_3.1-140 crosstalk_1.0.0
[36] xfun_0.9 openxlsx_4.1.0 rvest_0.3.2 mime_0.7 lifecycle_0.1.0 gtools_3.8.1 MASS_7.3-51.4
[43] hms_0.5.1 promises_1.0.1 parallel_3.6.1 expm_0.999-3 pwr_1.2-2 yaml_2.2.0 curl_3.2
[50] gridExtra_2.3 pander_0.6.3 stringi_1.4.3 nortest_1.0-4 boot_1.3-22 zip_1.0.0 rlang_0.4.0
[57] pkgconfig_2.0.3 matrixStats_0.54.0 bitops_1.0-6 lattice_0.20-38 labeling_0.3 rapportools_1.0 htmlwidgets_1.3
[64] tidyselect_0.2.5 ggsci_2.9 R6_2.4.0 DescTools_0.99.29 generics_0.0.2 pillar_1.4.2 haven_2.1.1
[71] foreign_0.8-71 withr_2.1.2 abind_1.4-5 RCurl_1.95-4.11 modelr_0.1.5 crayon_1.3.4 car_3.0-2
[78] viridis_0.5.1 grid_3.6.1 readxl_1.1.0 data.table_1.11.8 digest_0.6.21 httpuv_1.4.5 munsell_0.5.0
[85] viridisLite_0.3.0 quadprog_1.5-5
A work by Claudiu Papasteri
claudiu.papasteri@gmail.com
LS0tDQp0aXRsZTogIjxicj4gQW5hbHlzZXMgZm9yIE0uMS4gKEF1dG9iaW9ncmFwaGljYWwgTWVtb3JpZXMpIiANCnN1YnRpdGxlOiAiRm9jdXMgb24gU2Vhc29ucyAtIGluZGl2aWR1YWwgc3RpbXVsaSINCmF1dGhvcjogIjxicj4gQ2xhdWRpdSBQYXBhc3RlcmkiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlbSAlWScpYCINCm91dHB1dDogDQogICAgaHRtbF9ub3RlYm9vazoNCiAgICAgICAgICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgICAgICAgICAgdG9jOiB0cnVlDQogICAgICAgICAgICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgdGhlbWU6IHNwYWNlbGFiDQogICAgICAgICAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgICAgICAgICBmb250LWZhbWlseTogQXJpYWwNCiAgICAgICAgICAgIGZpZ193aWR0aDogMTANCiAgICAgICAgICAgIGZpZ19oZWlnaHQ6IDkNCiAgICAjIHdvcmRfZG9jdW1lbnQgICAgICAgIA0KICAgICMgcGRmX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICAgICAgICAgICMgZm9udHNpemU6IDExcHQNCiAgICAgICAgICAgICMgZ2VvbWV0cnk6IG1hcmdpbj0xaW4NCiAgICAgICAgICAgICMgZmlnX3dpZHRoOiA3DQogICAgICAgICAgICAjIGZpZ19oZWlnaHQ6IDYNCiAgICAgICAgICAgICMgZmlnX2NhcHRpb246IHRydWUNCiAgICAjIGdpdGh1Yl9kb2N1bWVudDogDQogICAgICAgICAgICAjIHRvYzogdHJ1ZQ0KICAgICAgICAgICAgIyB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgaHRtbF9wcmV2aWV3OiBmYWxzZQ0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDUNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNQ0KICAgICAgICAgICAgIyBkZXY6IGpwZWcNCi0tLQ0KDQoNCjwhLS0gU2V0dXAgLS0+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGtpbnRyIG9wdGlvbnMNCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgY29tbWVudCA9ICIjIiwNCiAgY29sbGFwc2UgPSBUUlVFLA0KICBlY2hvID0gVFJVRSwgDQogIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBlcnJvciA9IEZBTFNFLA0KICBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0KIyBHZW5lcmFsIFIgb3B0aW9ucyBhbmQgaW5mbw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQoNCiMgTG9hZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY2thZ2VzIDwtIGMoDQogICJwYXBhamEiLA0KICAidGlkeXZlcnNlIiwgInBseXIiLCAgICAgIA0KICAicHN5Y2giLCAiUGVyZm9ybWFuY2VBbmFseXRpY3MiLCAgICAgICAgICANCiAgImJyb29tIiwgInJzdGF0aXgiLA0KICAic3VtbWFyeXRvb2xzIiwgInRhZGFhdG9vbGJveCIsICAgICAgICAgICANCiAgImdncGxvdDIiLCAiZ2dwdWJyIiwgInNjYWxlcyIsICAgICAgICANCiAgInJpbyIsDQogICJmbXNiIiwgImxpa2VydCINCiAgIyAsIC4uLg0KKQ0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY21hbjo6cF9sb2FkKGNoYXIgPSBwYWNrYWdlcykNCg0KIyBUaGVtZXMgZm9yIGdncGxvdDIgcGxvdGluZyAoaGVyZSB1c2VkIEFQQSBzdHlsZSkNCnRoZW1lX3NldCh0aGVtZV9hcGEoKSkNCg0KDQojIFRhYmxlcyBrbml0dGluZyB0byBXb3JkDQpkb2MudHlwZSA8LSBrbml0cjo6b3B0c19rbml0JGdldCgncm1hcmtkb3duLnBhbmRvYy50bycpICAjIHRoZW4gZm9ybWF0IHRhYmxlcyB1c2luZyBhbiBpZiBzdGF0ZW1lbnQgbGlrZToNCiMgaWYgKGRvYy50eXBlID09ICJkb2N4IikgeyBwYW5kZXI6OnBhbmRlcihkZikgfSBlbHNlIHsga25pdHI6OmthYmxlKGRmKSB9DQpgYGANCg0KDQoNCg0KDQo8IS0tIFJlcG9ydCAtLT4NCg0KDQojIFJlYWQsIENsZWFuLCBSZWNvZGUsIE1lcmdlDQoNCmBgYHtyIHJlZF9jbGVhbl9yZWNvZGVfbWVyZ2UsIHJlc3VsdHM9J2hpZGUnfQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMgUmVhZA0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCg0KIyMgUmVhZCBmaWxlcw0KZm9sZGVyIDwtICJFOi9DaW5ldGljIGlkZWkgbm9pL0NpbmV0aWMgZWxldmkiDQpmaWxlIDwtICJNMSBkZSBpbnRyb2R1cyBhbm90aW1wdXJpLnhsc3giDQoNCnNldHdkKGZvbGRlcikNCkRhdGEgPC0gcmlvOjppbXBvcnQoZmlsZS5wYXRoKGZvbGRlciwgZmlsZSkpDQoNCiMjIFJlY29kZSBOQQ0KRGF0YSA8LSANCiAgRGF0YSAlPiUgICAgICAgICAgICAgIyBzdW0oaXMubmEoRGF0YSkpID0gNTg3Mw0KICBuYV9pZigibmEiKSAgICAgICAgICAjIHN1bShpcy5uYShEYXRhKSkgPSA2MTk5DQoNCg0KIyMgVmFyaWFibGUgbmFtZXMNCm51bWUgPC0gYygiU3RpbSIsICJWYXJzdGFfYW1pbiIsICJBbm8iLCAiVmFsIiwgIlZpdiIsICJSZWx2IikNCnRvYXRlIDwtIHBhc3RlKG51bWUsIHJlcCgxOjE1LCBlYWNoID0gbGVuZ3RoKG51bWUpKSwgc2VwID0gIl8iKQ0KDQojIyBDaGVjayB0aGF0IGFsbCB2YXJpYWJsZSBuYW1lcyBhcmUgY29uc2lzdGVudCB3aXRoIGNvbHVtbiBoZWFkZXJzDQppZih0b2F0ZSAlaW4lIG5hbWVzKERhdGEpKXsNCiAgY2F0KCJBbGwgY29sdW1uIG5hbWVzIGFyZSBjb25zaXN0ZW50LiIpDQp9IGVsc2Ugew0KICBjYXQoIkNvbHVtbiBuYW1lcyBhcmUgTk9UIGNvbnNpc3RlbnQuIFxuIikNCiAgY2F0KCJNaXNzbWF0Y2hlczogXG4gIikNCiAgc2V0ZGlmZih0b2F0ZSwgbmFtZXMoRGF0YSkpDQp9DQpgYGANCg0KDQojIFNhbXBsZSBkZXNjcmlwdGl2ZXMNCg0KYGBge3Igc2FtcGxlX2Rlc2N9DQpjYXQoIiMjIE51bWJlciBvZiBzdWJqZWN0cyIpDQpEYXRhICU+JSANCiBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gZHBseXI6Om5fZGlzdGluY3QoSUQpKQ0KDQpjYXQoIiMjIE51bWJlciBvZiBzdWJqZWN0cyBwZXIgUHJvdG9jb2wiKQ0KRGF0YSAlPiUNCiBncm91cF9ieShQcm90b2NvbCkgJT4lDQogZHBseXI6OnN1bW1hcmlzZShjb3VudCA9IGRwbHlyOjpuX2Rpc3RpbmN0KElEKSkNCmBgYA0KDQoNCiMgU2Vhc29uIE1lbW9yaWVzIGFuZCBWYWxlbmNlDQoNCiMjIE1ha2UgZGF0YSBmcmFtZXMNCg0KYGBge3IgZGZfc2VhbnNvbiwgcmVzdWx0cz0nYXNpcycsIHdhcm5pbmc9RkFMU0V9DQojIyBFeGNsdWRlIFA2ICYgUDcNCkRhdGFfU2Vhc29uIDwtIA0KICBEYXRhICU+JQ0KICBkcGx5cjo6ZmlsdGVyKCFQcm90b2NvbCAlaW4lIGMoNiwgNykpDQoNCiMjIE1lbHQgdG8gTG9uZw0KDQojIERhdGFfVmFyYSA8LSAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwaXZvdF9sb25nZXIoKSBvbmx5IGluIGRldmVsb3BtZW50IHZlcnNpb24gb2YgdGlkeXIuLi4gZG9udCB1c2Ugbm93DQojICAgRGF0YV9TZWFzb24gJT4lICAgICAgICAgICAgICAgICAgICAgIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInRpZHl2ZXJzZS90aWR5ciIpDQojICAgdGlkeXI6OnBpdm90X2xvbmdlcigNCiMgICAgIC1jKDE6NSksDQojICAgICAjY29scyA9IHN0YXJ0c193aXRoKCJBbm8iKSwgDQojICAgICBuYW1lc190byA9IGMoIi52YWx1ZSIsICJ2YXIiKSwgDQojICAgICBuYW1lc19zZXAgPSAiXyIsIA0KIyAgICAgdmFsdWVzX2Ryb3BfbmEgPSBUUlVFDQojICAgKQ0KDQpEYXRhX1NlYXNvbl9tZWx0IDwtICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBEYXRhX1NlYXNvbiAlPiUNCiAgZ2F0aGVyKHZhcmlhYmxlLCB2YWx1ZSwgLWMoMTo1KSkgJT4lDQogIG11dGF0ZShncm91cCA9IHJlYWRyOjpwYXJzZV9udW1iZXIodmFyaWFibGUpKSAlPiUNCiAgbXV0YXRlKHZhcmlhYmxlID0gZ3N1YigiXFxkIiwiIix4ID0gdmFyaWFibGUpKSAlPiUNCiAgc3ByZWFkKHZhcmlhYmxlLCB2YWx1ZSkgJT4lDQogIHJlbmFtZV9hbGwofnN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCguLCAiXyIsICIiKSkgJT4lICAgICAgICAgICAjIGRlbGV0ZSB0aGUgIl8iIGF0IGVuZA0KICBtdXRhdGUoQW5vID0gZmFjdG9yKEFubywgbGV2ZWxzID0gYygiVmFyYSIsICJQcmltYXZhcmEiLCAiVG9hbW5hIiwgIklhcm5hIikpKSAlPiUNCiAgbXV0YXRlX2F0KHZhcnMoIlJlbHYiLCAiVmFsIiwgIlZhcnN0YWFtaW4iLCAiVml2IiksIGZ1bnMoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoLikpKSkNCiAgDQojIyBTZWFzb24gZGF0YSBmcmFtZXMNCiMgRGF0YV9WYXJhIDwtDQojICAgRGF0YV9TZWFzb25fbWVsdCAlPiUNCiMgICBmaWx0ZXIoIWlzLm5hKEFubykpICU+JSAgICAgICAgICAgICAgICAjIGRlbGV0ZSByb3dzIHdlcmUgdGhlcmUgaXMgbm8gQW5vDQojICAgZmlsdGVyKEFubyA9PSAiVmFyYSIpDQojIA0KIyBEYXRhX1ByaW1hdmFyYSA8LQ0KIyAgIERhdGFfU2Vhc29uX21lbHQgJT4lDQojICAgZmlsdGVyKCFpcy5uYShBbm8pKSAlPiUgICAgICAgICAgICAgICAgIyBkZWxldGUgcm93cyB3ZXJlIHRoZXJlIGlzIG5vIEFubw0KIyAgIGZpbHRlcihBbm8gPT0gIlByaW1hdmFyYSIpDQojIA0KIyBEYXRhX1RvYW1uYSA8LQ0KIyAgIERhdGFfU2Vhc29uX21lbHQgJT4lDQojICAgZmlsdGVyKCFpcy5uYShBbm8pKSAlPiUgICAgICAgICAgICAgICAgIyBkZWxldGUgcm93cyB3ZXJlIHRoZXJlIGlzIG5vIEFubw0KIyAgIGZpbHRlcihBbm8gPT0gIlRvYW1uYSIpDQojIA0KIyBEYXRhX0lhcm5hIDwtDQojICAgRGF0YV9TZWFzb25fbWVsdCAlPiUNCiMgICBmaWx0ZXIoIWlzLm5hKEFubykpICU+JSAgICAgICAgICAgICAgICAjIGRlbGV0ZSByb3dzIHdlcmUgdGhlcmUgaXMgbm8gQW5vDQojICAgZmlsdGVyKEFubyA9PSAiSWFybmEiKQ0KIyANCiMgDQojICMjIEV4Y2VsIGRvd25sb2FkYWJsZSBEVCB0YWJsZXMNCiMgRGF0YV9WYXJhICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyAgIHNlbGVjdCgtTnVtZSkgJT4lDQojICAgICBEVDo6ZGF0YXRhYmxlKCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiMgICAgICAgZXh0ZW5zaW9ucyA9ICdCdXR0b25zJywNCiMgICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLA0KIyAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxYPSc1MDBweCcsIA0KIyAgICAgICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywgDQojICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCdleGNlbCcsICJjc3YiKSkpDQojIA0KIyBEYXRhX1ByaW1hdmFyYSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiMgICBzZWxlY3QoLU51bWUpICU+JQ0KIyAgICAgRFQ6OmRhdGF0YWJsZSggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQojICAgICAgIGV4dGVuc2lvbnMgPSAnQnV0dG9ucycsDQojICAgICAgIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCwNCiMgICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWD0nNTAwcHgnLCANCiMgICAgICAgICAgICAgICAgICAgICAgZG9tID0gJ0JmcnRpcCcsIA0KIyAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygnZXhjZWwnLCAiY3N2IikpKQ0KIyANCiMgRGF0YV9Ub2FtbmEgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQojICAgc2VsZWN0KC1OdW1lKSAlPiUNCiMgICAgIERUOjpkYXRhdGFibGUoICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyAgICAgICBleHRlbnNpb25zID0gJ0J1dHRvbnMnLA0KIyAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsDQojICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFg9JzUwMHB4JywgDQojICAgICAgICAgICAgICAgICAgICAgIGRvbSA9ICdCZnJ0aXAnLCANCiMgICAgICAgICAgICAgICAgICAgICAgYnV0dG9ucyA9IGMoJ2V4Y2VsJywgImNzdiIpKSkNCiMgDQojIERhdGFfSWFybmEgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQojICAgc2VsZWN0KC1OdW1lKSAlPiUNCiMgICAgIERUOjpkYXRhdGFibGUoICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyAgICAgICBleHRlbnNpb25zID0gJ0J1dHRvbnMnLA0KIyAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsDQojICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFg9JzUwMHB4JywgDQojICAgICAgICAgICAgICAgICAgICAgIGRvbSA9ICdCZnJ0aXAnLCANCiMgICAgICAgICAgICAgICAgICAgICAgYnV0dG9ucyA9IGMoJ2V4Y2VsJywgImNzdiIpKSkNCg0KDQpjYXQoIiMjIyBNZWx0IHRvIExvbmcgRm9ybWF0IikNCkRhdGFfU2Vhc29uX21lbHQgJT4lDQogIGRwbHlyOjpzZWxlY3QoLU51bWUpICU+JQ0KICAgIERUOjpkYXRhdGFibGUoDQogICAgICBleHRlbnNpb25zID0gJ0J1dHRvbnMnLA0KICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLA0KICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWD0nNTAwcHgnLA0KICAgICAgICAgICAgICAgICAgICAgZG9tID0gJ0JmcnRpcCcsDQogICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygnZXhjZWwnLCAiY3N2IikpKQ0KDQpjYXQoIiMjIyBXaWRlIEZvcm1hdCIpDQpEYXRhX1NlYXNvbiAlPiUNCiAgZHBseXI6OnNlbGVjdCgtTnVtZSkgJT4lDQogICAgRFQ6OmRhdGF0YWJsZSgNCiAgICAgIGV4dGVuc2lvbnMgPSAnQnV0dG9ucycsDQogICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsDQogICAgICAgICAgICAgICAgICAgICBzY3JvbGxYPSc1MDBweCcsDQogICAgICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywNCiAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCdleGNlbCcsICJjc3YiKSkpDQoNCg0KIyMgRGF0YSBGcmFtZSBmb3IgUGxvdHMNCkRhdGFfU2Vhc29uX21lbHRfbm9uYSA8LQ0KICBEYXRhX1NlYXNvbl9tZWx0ICU+JQ0KICBmaWx0ZXIoIWlzLm5hKEFubykpDQoNCg0KY2F0KCIjIyMgV2lkZSBGb3JtYXQgZm9yIEFubyB+IFZhbGVuY2UiKQ0KRGF0YV9TZWFzb25fbWVsdF9ub25hICU+JQ0KICBkcGx5cjo6c2VsZWN0KElELCBBbm8sIFZhbCkgJT4lDQogIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JQ0KICBzcHJlYWQoa2V5ID0gQW5vLCB2YWx1ZSA9IFZhbCkgJT4lDQogIGFycmFuZ2UoSUQpICU+JQ0KICAgIERUOjpkYXRhdGFibGUoDQogICAgICBleHRlbnNpb25zID0gJ0J1dHRvbnMnLA0KICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLA0KICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWD0nNTAwcHgnLA0KICAgICAgICAgICAgICAgICAgICAgZG9tID0gJ0JmcnRpcCcsDQogICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygnZXhjZWwnLCAiY3N2IikpKQ0KYGBgDQoNCg0KIyMgRGVmaW5lIEZ1bmN0aW9uIGZvciBQbG90cw0KDQpgYGB7ciBkZWZfZnVuY19wbG90fQ0KIyMgRnVuY3Rpb24gZm9yIEFubyBCYXIgUGxvdA0KbXlfY29tcGFyaXNvbnMgPC0gDQogIGd0b29sczo6Y29tYmluYXRpb25zKG4gPSBsZW5ndGgodW5pcXVlKERhdGFfU2Vhc29uX21lbHRfbm9uYSRBbm8pKSwgciA9IDIsIHYgPSBhcy5jaGFyYWN0ZXIoRGF0YV9TZWFzb25fbWVsdF9ub25hJEFubyksIHJlcGVhdHMuYWxsb3dlZCA9IEZBTFNFKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpICU+JSANCiAgbXV0YXRlX2lmKGlzLmZhY3RvciwgYXMuY2hhcmFjdGVyKSAlPiUNCiAgcHVycnI6OnBtYXAobGlzdCkgJT4lIA0KICBsYXBwbHkodW5saXN0KQ0KDQpmdW5jX3Bsb3RfYW5vIDwtIGZ1bmN0aW9uKGRmLCB5X3ZhciwgeV92YXJfbGFiLCBsYWJlbC55X3NldCA9IDcsIHl0aWNrcy5ieV9zZXQgPSAxLCBmYWNldCA9IEZBTFNFKXsNCiAgaWYoZmFjZXQpew0KICAgIGZhY2V0IDwtICJQcm90b2NvbCINCiAgfWVsc2V7DQogICAgZmFjZXQgPC0gTlVMTA0KICB9DQogIHAgPC0NCiAgICBkZiAgJT4lDQogICAgZ2dwdWJyOjpnZ2JhcnBsb3QoeCA9ICJBbm8iLCB5ID0geV92YXIsIA0KICAgICAgICAgICAgICAgICAgICAgIGFkZCA9ICJtZWFuX3NlIiwNCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAibGlnaHRncmF5IiwNCiAgICAgICAgICAgICAgICAgICAgICB4bGFiID0gIkFub3RpbXAiLCB5bGFiID0geV92YXJfbGFiLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gVFJVRSwgbGFiLm5iLmRpZ2l0cyA9IDIsIGxhYi5wb3M9ICJpbiIsDQogICAgICAgICAgICAgICAgICAgICAgZmFjZXQuYnkgPSBmYWNldCkgKw0KICAgIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAiYW5vdmEiLA0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbC54ID0gMC45LCBsYWJlbC55ID0gbGFiZWwueV9zZXQpICsNCiAgICBzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucywNCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiLCBtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gRkFMU0UsIG5hLnJtID0gVFJVRSkgDQogIGdncGFyKHAsIHl0aWNrcy5ieSA9IHl0aWNrcy5ieV9zZXQpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIHJhdGluZyBzY2FsZSBpcyAxLTcNCn0NCg0KDQojIyBEb2RnZWQgDQpmdW5jX2RvZGdlZF9hbm8gPC0gZnVuY3Rpb24oZGYsIHlfdmFyLCB5X3Zhcl9sYWIsIGZhY2V0ID0gRkFMU0Upew0KICB5X3ZhcjwtIHN5bSh5X3ZhcikNCiAgDQogIGlmKGZhY2V0KSB7DQogICAgZGYgPC0gDQogICAgICBkZiAlPiUgDQogICAgICBtdXRhdGUoUHJvdG9jb2wgPSBwYXN0ZTAoIlByb3RvY29sICIsIFByb3RvY29sKSkgJT4lDQogICAgICBncm91cF9ieShQcm90b2NvbCkgIA0KICB9DQogIA0KICBwIDwtDQogICAgZGYgICU+JQ0KICAgIGRwbHlyOjpjb3VudChBbm8sICEheV92YXIpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICMgR3JvdXAgYnksIHRoZW4gY291bnQgbnVtYmVyIGluIGVhY2ggZ3JvdXANCiAgICBtdXRhdGUocGN0ID0gcHJvcC50YWJsZShuKSkgJT4lICAgICAgICAgICAgICAgICAgICAgIyBDYWxjdWxhdGUgcGVyY2VudCB3aXRoaW4gZWFjaCB2YXINCiAgICBtdXRhdGUoVmFsX2ZhYyA9IGFzLmZhY3RvcighIXlfdmFyKSkgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gQW5vLCB5ID0gcGN0LCBmaWxsID0gVmFsX2ZhYywgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQocGN0KSkpICsgDQogICAgICBnZW9tX2NvbChwb3NpdGlvbiA9ICdkb2RnZScpICsgDQogICAgICBnZW9tX3RleHQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSwgICAgIyBtb3ZlIHRvIGNlbnRlciBvZiBiYXJzDQogICAgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBudWRnZSBhYm92ZSB0b3Agb2YgYmFyDQogICAgICAgICAgICAgICAgc2l6ZSA9IDMpICsgDQogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogICAgICB7aWYoZmFjZXQpIGZhY2V0X3dyYXAoflByb3RvY29sLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSAxLCBucm93ID0gOCl9ICsNCiAgICAgIGdndGl0bGUoeV92YXJfbGFiKSArDQogICAgICB4bGFiKCJBbm90aW1wIikgKyB5bGFiKCJQZXJjZW50YWdlICUiKSArIA0KICAgICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiVmFsdWUiLCBucm93ID0gMSkpICsgDQogICAgICBzY2FsZV9maWxsX2dyZXkoc3RhcnQgPSAwLjgsIGVuZCA9IDAuMiwgbmEudmFsdWUgPSAicmVkIiwgYWVzdGhldGljcyA9ICJmaWxsIikgKw0KICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIA0KICAgICAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsIDEpLCBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBjb2xvdXIgPSAiYmxhY2siKSkNCiAgcA0KfSAgDQpgYGANCg0KDQoNCiMjIFBsb3RzIG9mIFNlYXNvbnMNCg0KYGBge3IgcGxvdF9zZWFuc29uLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD03LCBmaWcuYWxpZ249J2NlbnRlcid9DQojIyBUZXN0IGZvciBWYWwgLS0gd29ya3Mgd2VsbA0KIyBEYXRhX1NlYXNvbl9tZWx0X25vbmEgICU+JQ0KIyAgIGdncHVicjo6Z2diYXJwbG90KHggPSAiQW5vIiwgeSA9ICJWYWwiLCANCiMgICAgICAgICAgICAgICAgICAgICBhZGQgPSAibWVhbl9zZSIsDQojICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImxpZ2h0Z3JheSIsDQojICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJBbm90aW1wIiwgeWxhYiA9ICJWYWxlbnRhIiwNCiMgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IFRSVUUsIGxhYi5uYi5kaWdpdHMgPSAyLCBsYWIucG9zPSAiaW4iKSArDQojICAgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJhbm92YSIsDQojICAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnggPSAwLjksIGxhYmVsLnkgPSA3KSArDQojICAgc3RhdF9jb21wYXJlX21lYW5zKGNvbXBhcmlzb25zID0gbXlfY29tcGFyaXNvbnMsDQojICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gInAuc2lnbmlmIiwgbWV0aG9kID0gInQudGVzdCIsIHBhaXJlZCA9IEZBTFNFLCBuYS5ybSA9IFRSVUUpIA0KDQoNCmZ1bmNfcGxvdF9hbm8oRGF0YV9TZWFzb25fbWVsdF9ub25hLCAiVmFsIiwgIlZhbGVudGEiKQ0KZnVuY19wbG90X2FubyhEYXRhX1NlYXNvbl9tZWx0X25vbmEsICJSZWx2IiwgIlJlbGV2YW50YSBwZXJzb25hbGEiKQ0KZnVuY19wbG90X2FubyhEYXRhX1NlYXNvbl9tZWx0X25vbmEsICJWaXYiLCAiVml2aWQiKQ0KZnVuY19wbG90X2FubyhEYXRhX1NlYXNvbl9tZWx0X25vbmEsICJWYXJzdGFhbWluIiwgIlZhcnN0YSBhbWludGlyZSIsIGxhYmVsLnlfc2V0ID0gNTAsIHl0aWNrcy5ieV9zZXQgPSA1KQ0KYGBgDQoNCg0KIyMgUGxvdHMgb2YgU2Vhc29ucyBieSBQcm90b2NvbA0KDQpgYGB7ciBwbG90X3NlYW5zb24yLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTIsIGZpZy5hbGlnbj0nY2VudGVyJ30NCmZ1bmNfcGxvdF9hbm8oRGF0YV9TZWFzb25fbWVsdF9ub25hLCAiVmFsIiwgIlZhbGVudGEiLCBmYWNldCA9IFRSVUUpIA0KZnVuY19wbG90X2FubyhEYXRhX1NlYXNvbl9tZWx0X25vbmEsICJSZWx2IiwgIlJlbGV2YW50YSBwZXJzb25hbGEiLCBmYWNldCA9IFRSVUUpDQpmdW5jX3Bsb3RfYW5vKERhdGFfU2Vhc29uX21lbHRfbm9uYSwgIlZpdiIsICJWaXZpZCIsIGZhY2V0ID0gVFJVRSkNCmZ1bmNfcGxvdF9hbm8oRGF0YV9TZWFzb25fbWVsdF9ub25hLCAiVmFyc3RhYW1pbiIsICJWYXJzdGEgYW1pbnRpcmUiLCBsYWJlbC55X3NldCA9IDUwLCB5dGlja3MuYnlfc2V0ID0gNSwgZmFjZXQgPSBUUlVFKQ0KYGBgDQoNCg0KIyMgUGxvdHMgd2l0aCBwcm9wb3J0aW9uIG9mIHZhbHVlcw0KDQpgYGB7ciBwbG90X3NlYW5zb25fcHJvcCwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTIsIGZpZy5hbGlnbj0nY2VudGVyJ30NCiMgIyBTdGFja2VkIC0gVGVzdCBmb3IgVmFsIC0tIHdvcmtzIHdlbGwNCiMgRGF0YV9TZWFzb25fbWVsdF9ub25hICU+JSANCiMgICBkcGx5cjo6Y291bnQoQW5vLCBWYWwpICU+JSAgICAgICAgICAgICAgICAgICAjIEdyb3VwIGJ5LCB0aGVuIGNvdW50IG51bWJlciBpbiBlYWNoIGdyb3VwDQojICAgbXV0YXRlKHBjdCA9IG4vc3VtKG4pKSAlPiUgICAgICAgICAgICAgICAgICAgIyBDYWxjdWxhdGUgcGVyY2VudCB3aXRoaW4gZWFjaCB2YXI7IGNvdWxkIHVzZSBwcm9wLnRhYmxlKG4pDQojICAgbXV0YXRlKFZhbF9mYWMgPSBhcy5mYWN0b3IoVmFsKSkgJT4lDQojIGdncGxvdChhZXMoQW5vLCBuLCBmaWxsID0gVmFsX2ZhYykpICsNCiMgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAgICAgICAgICAgICAgICAgDQojICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChzcHJpbnRmKCIlMS4xZiIsIHBjdCoxMDApLCAiJSIpLCBzaXplID0gc2NhbGVzOjpyZXNjYWxlKHBjdCwgdG89YygyLCA1KSkpLCANCiMgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKQ0KIyANCiMgDQojICMgRG9kZ2VkIC0gVGVzdCBmb3IgVmFsIC0tIHdvcmtzIHdlbGwNCiMgRGF0YV9TZWFzb25fbWVsdF9ub25hICU+JSANCiMgICBkcGx5cjo6Y291bnQoQW5vLCBWYWwpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICMgR3JvdXAgYnksIHRoZW4gY291bnQgbnVtYmVyIGluIGVhY2ggZ3JvdXANCiMgICBtdXRhdGUocGN0ID0gcHJvcC50YWJsZShuKSkgJT4lICAgICAgICAgICAgICAgICAgICMgQ2FsY3VsYXRlIHBlcmNlbnQgd2l0aGluIGVhY2ggdmFyDQojICAgbXV0YXRlKFZhbF9mYWMgPSBhcy5mYWN0b3IoVmFsKSkgJT4lDQojICAgZ2dwbG90KGFlcyh4ID0gQW5vLCB5ID0gcGN0LCBmaWxsID0gVmFsX2ZhYywgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQocGN0KSkpICsgDQojICAgICBnZW9tX2NvbChwb3NpdGlvbiA9ICdkb2RnZScpICsgDQojICAgICBnZW9tX3RleHQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSwgICAgIyBtb3ZlIHRvIGNlbnRlciBvZiBiYXJzDQojICAgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBudWRnZSBhYm92ZSB0b3Agb2YgYmFyDQojICAgICAgICAgICAgICAgc2l6ZSA9IDMpICsgDQojICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQojICAgICB4bGFiKCJBbm90aW1wIikgKyB5bGFiKCJQZXJjZW50YWdlICUiKSArIA0KIyAgICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiVmFsdWUiLCBucm93ID0gMSkpICsgDQojICAgICBzY2FsZV9maWxsX2dyZXkoc3RhcnQgPSAwLjgsIGVuZCA9IDAuMiwgbmEudmFsdWUgPSAicmVkIiwgYWVzdGhldGljcyA9ICJmaWxsIikgKw0KIyAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLCAxKSkgDQogIA0KDQpmdW5jX2RvZGdlZF9hbm8oRGF0YV9TZWFzb25fbWVsdF9ub25hLCAiVmFsIiwgIlZhbGVudGEiKQ0KZnVuY19kb2RnZWRfYW5vKERhdGFfU2Vhc29uX21lbHRfbm9uYSwgIlJlbHYiLCAiUmVsZXZhbnRhIHBlcnNvbmFsYSIpDQpmdW5jX2RvZGdlZF9hbm8oRGF0YV9TZWFzb25fbWVsdF9ub25hLCAiVml2IiwgIlZpdmlkIikNCmBgYA0KDQoNCiMjIFBsb3RzIHdpdGggcHJvcG9ydGlvbiBvZiB2YWx1ZXMgYnkgUHJvdG9jb2wNCg0KYGBge3IgcGxvdF9zZWFuc29uX3Byb3AyLCBmaWcuaGVpZ2h0PTI1LCBmaWcud2lkdGg9MTAsIGZpZy5hbGlnbj0nY2VudGVyJ30NCmZ1bmNfZG9kZ2VkX2FubyhEYXRhX1NlYXNvbl9tZWx0X25vbmEsICJWYWwiLCAiVmFsZW50YSIsIGZhY2V0ID0gVFJVRSkNCmZ1bmNfZG9kZ2VkX2FubyhEYXRhX1NlYXNvbl9tZWx0X25vbmEsICJSZWx2IiwgIlJlbGV2YW50YSBwZXJzb25hbGEiLCBmYWNldCA9IFRSVUUpDQpmdW5jX2RvZGdlZF9hbm8oRGF0YV9TZWFzb25fbWVsdF9ub25hLCAiVml2IiwgIlZpdmlkIiwgZmFjZXQgPSBUUlVFKQ0KYGBgDQoNCg0KIyMgTGlrZXJ0IFBsb3RzIGZvciBTZWFzb24NCg0KYGBge3IgcGxvdF9saWtlcnQsIHJlc3VsdHM9J2FzaXMnLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04LCBmaWcuYWxpZ249J2NlbnRlcid9DQojIFByb3BvcnRpb25zIGFuZCB6LXNjb3Jlcw0KUHJvcF92YWwgPC0gDQogIERhdGFfU2Vhc29uX21lbHRfbm9uYSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElELCBQcm90b2NvbCwgQW5vLCBWYWwpICU+JQ0KICAgIGdyb3VwX2J5KEFubykgJT4lDQogICAgbXV0YXRlKA0KICAgICAgVmFsID0gYXMuZmFjdG9yKFZhbCksDQogICAgICBWYWwgPSBmb3JjYXRzOjpmY3RfY29sbGFwc2UoVmFsLCBsb3cgPSBjKCIxIiwgIjIiLCAiMyIpLCBuZXV0cmFsID0gIjQiLCBoaWdoID0gYygiNSIsICI2IiwgIjciKSkNCiAgICAgICkgJT4lDQogICAgZHBseXI6OmNvdW50KFZhbCkgJT4lIA0KICAgIG11dGF0ZSh0b3RhbCA9IHN1bShuKSwNCiAgICAgICAgICAgcGVyYyA9IDEwMCpuL3RvdGFsKQ0KDQpjYXQoIiMjIyBQcm9wb3J0aW9ucyAtIGNvbXBhcmVkIHRvIDAuNSBwcm9iYWJpbGl0eSIpDQpQcm9wX3ZhbCAlPiUNCmZpbHRlcihWYWwgPT0gImhpZ2giKSAlPiUNCiAgcm93d2lzZSAlPiUNCiAgbXV0YXRlKHRzdCA9IGxpc3QoYnJvb206OnRpZHkocHJvcC50ZXN0KG4sIHRvdGFsLCBjb25mLmxldmVsID0gMC45NSkpKSkgJT4lDQogIHRpZHlyOjp1bm5lc3QodHN0KQ0KDQpQcm9wX3ZhbCAlPiUNCmZpbHRlcihWYWwgPT0gImxvdyIpICU+JQ0KICByb3d3aXNlICU+JQ0KICBtdXRhdGUodHN0ID0gbGlzdChicm9vbTo6dGlkeShwcm9wLnRlc3QobiwgdG90YWwsIGNvbmYubGV2ZWwgPSAwLjk1KSkpKSAlPiUgDQogIHRpZHlyOjp1bm5lc3QodHN0KQ0KDQoNCmNhdCgiIyMjIFByb3BvcnRpb25zIC0gTXVsdGlwbGUgY29tcGFyaXNvbnMiKQ0KUGFpcl9Db21wX3Byb3BfaGlnaCA8LSAgICAgICAjIGNvbXBhaXJlIGFsbCBwcm9wb3J0aW9ucyBwYWlyd2lzZQ0KICBQcm9wX3ZhbCAlPiUNCiAgZmlsdGVyKFZhbCA9PSAiaGlnaCIpICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1wZXJjKSAlPiUNCiAgdW5pdGUoIkNhdGVnIiwgYygiQW5vIiwgIlZhbCIpLCBzZXAgPSAiLSIpICU+JQ0KICBjb2x1bW5fdG9fcm93bmFtZXMoIkNhdGVnIikgDQoNClBhaXJfQ29tcF9wcm9wX2hpZ2hfbWF0IDwtDQogIFBhaXJfQ29tcF9wcm9wX2hpZ2ggJT4lDQogICAgcm93bmFtZXNfdG9fY29sdW1uKCJyb3duYW1lIikgJT4lDQogICAgZHBseXI6OnJlbmFtZShzdWNjZXNzID0gbikgJT4lDQogICAgbXV0YXRlKGZhaWx1cmUgPSB0b3RhbCAtIHN1Y2Nlc3MpICU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoLXRvdGFsKSAlPiUNCiAgICBjb2x1bW5fdG9fcm93bmFtZXMoInJvd25hbWUiKSAlPiUNCiAgICBhcy5tYXRyaXgoKSANCg0KUGFpcl9Db21wX3Byb3BfbG93IDwtICAgICAgICMgY29tcGFpcmUgYWxsIHByb3BvcnRpb25zIHBhaXJ3aXNlDQogIFByb3BfdmFsICU+JQ0KICBmaWx0ZXIoVmFsID09ICJsb3ciKSAlPiUNCiAgZHBseXI6OnNlbGVjdCgtcGVyYykgJT4lDQogIHVuaXRlKCJDYXRlZyIsIGMoIkFubyIsICJWYWwiKSwgc2VwID0gIi0iKSAlPiUNCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJDYXRlZyIpIA0KDQpQYWlyX0NvbXBfcHJvcF9sb3dfbWF0IDwtDQogIFBhaXJfQ29tcF9wcm9wX2xvdyAlPiUNCiAgcm93bmFtZXNfdG9fY29sdW1uKCJyb3duYW1lIikgJT4lDQogIGRwbHlyOjpyZW5hbWUoc3VjY2VzcyA9IG4pICU+JQ0KICBtdXRhdGUoZmFpbHVyZSA9IHRvdGFsIC0gc3VjY2VzcykgJT4lDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsKSAlPiUNCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJyb3duYW1lIikgJT4lDQogIGFzLm1hdHJpeCgpDQoNCmNhdCgiIyMjIyBQYWlyd2lzZSBjb21wYXJpc29ucyB1c2luZyBQYWlyd2lzZSBjb21wYXJpc29uIG9mIHByb3BvcnRpb25zIikNCnBhaXJ3aXNlLnByb3AudGVzdCh4ID0gUGFpcl9Db21wX3Byb3BfaGlnaF9tYXQsIHAuYWRqdXN0Lm1ldGhvZCA9ICJub25lIikgJT4lIA0KICB0aWR5KCkNCnBhaXJ3aXNlLnByb3AudGVzdCh4ID0gUGFpcl9Db21wX3Byb3BfbG93X21hdCwgcC5hZGp1c3QubWV0aG9kID0gIm5vbmUiKSAlPiUgDQogIHRpZHkoKQ0KDQpjYXQoIiMjIyMgUGFpcndpc2UgY29tcGFyaXNvbnMgdXNpbmcgUGFpcndpc2UgY29tcGFyaXNvbiBvZiBwcm9wb3J0aW9ucyAoRmlzaGVyIGV4YWN0KSIpICAgICMgbGlicmFyeShmbXNiKQ0KZm1zYjo6cGFpcndpc2UuZmlzaGVyLnRlc3QoeCA9IFBhaXJfQ29tcF9wcm9wX2hpZ2hfbWF0LCBwLmFkanVzdC5tZXRob2QgPSAibm9uZSIpICU+JSANCiAgdGlkeSgpDQpmbXNiOjpwYWlyd2lzZS5maXNoZXIudGVzdCh4ID0gUGFpcl9Db21wX3Byb3BfbG93X21hdCwgcC5hZGp1c3QubWV0aG9kID0gIm5vbmUiKSAlPiUgDQogIHRpZHkoKQ0KDQoNCiMgbGlicmFyeShwYWlyY29tcHZpeikNCiMgcGFpcmNvbXB2aXo6OnBhaXJjb21wKFBhaXJfQ29tcF9wcm9wX2hpZ2gkbiwgUGFpcl9Db21wX3Byb3BfaGlnaCR0b3RhbCwgY29ycmVjdCA9IEZBTFNFLA0KIyAgICAgICAgICAgICAgICAgICAgICAgdGVzdCA9ICJwcm9wIiwgcmVzdWx0ID0gVFJVRSwgcC5hZGp1c3QubWV0aG9kID0gIm5vbmUiKSANCg0KIyBEYXRhIGZvciBQbG90DQpjYXQoIiMjIyBQcm9wb3J0aW9ucyAtIFBsb3Qgb2YgTG93LU5ldXRyYWwtSGlnaCIpDQpMaWtlcnRfdmFsIDwtIA0KICBEYXRhX1NlYXNvbl9tZWx0X25vbmEgJT4lDQogIGRwbHlyOjpzZWxlY3QoSUQsIFByb3RvY29sLCBncm91cCwgQW5vLCBWYWwpICU+JQ0KICBzcHJlYWQoa2V5ID0gQW5vLCB2YWx1ZSA9IFZhbCkgJT4lDQogIG11dGF0ZV9hdCh2YXJzKCJWYXJhIiwgIlByaW1hdmFyYSIsICJUb2FtbmEiLCAiSWFybmEiKSwgfmFzLmZhY3RvciguKSkNCg0KIyBQbG90cyAgIyBsaWJyYXJ5KGxpa2VydCkNCkxpa2VydG9ial9WYWwgPC0gbGlrZXJ0KExpa2VydF92YWxbLCBjKCJWYXJhIiwgIlByaW1hdmFyYSIsICJUb2FtbmEiLCAiSWFybmEiKV0sIG5sZXZlbHMgPSA3KSAgICMgaGVyZSBhcmUgcGVyY2VudGFnZXMNCkxpa2VydG9ial9WYWxfcGVyYyA8LSBMaWtlcnRvYmpfVmFsJHJlc3VsdHMNCiMgY2hlY2sgaWYgc2FtZSB3aXRoIFByb3AgZGF0YWZyYW1lIGFib3ZlOyBvciBwcm9wLnRhYmxlKHRhYmxlKExpa2VydF92YWwkVmFyYSkpDQoNCnBsb3QoTGlrZXJ0b2JqX1ZhbCwgdHlwZSA9ICJiYXIiLCANCiAgICAgY2VudGVyZWQgPSBUUlVFLCBjZW50ZXIgPSA0LCBpbmNsdWRlLmNlbnRlciA9IFRSVUUsICAgICAgICAgICAgICAjICI0IiBpcyBuZXV0cmFsDQogICAgIHdyYXAgPSAzMCwgbG93LmNvbG9yID0gJ2J1cmx5d29vZCcsIGhpZ2guY29sb3IgPSAnbWFyb29uJykgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSkpDQoNCmBgYA0KDQoNCiMjIExpa2VydCBQbG90cyBmb3IgU2Vhc29uDQoNCmBgYHtyIHJlbF9Bbm9mcmVxX1ZhbCwgcmVzdWx0cz0nYXNpcycsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTcsIGZpZy5hbGlnbj0nY2VudGVyJ30NCkFub2ZyZXFfVmFsIDwtIA0KICBEYXRhX1NlYXNvbl9tZWx0X25vbmEgJT4lDQogICAgZHBseXI6OnNlbGVjdChJRCwgUHJvdG9jb2wsIEFubywgVmFsKSAlPiUNCiAgICBncm91cF9ieShJRCwgQW5vKSAlPiUNCiAgICBkcGx5cjo6c3VtbWFyaXplKE1lYW5fVmFsID0gbWVhbihWYWwsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgRnJlcV9Bbm8gPSBuKCkpIA0KDQpjYXQoIiMjIyBTY2F0dGVyIHBsb3Qgd2l0aCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBmb3IgYWxsIFNlYXNvbnMiKQ0KZ2dwdWJyOjpnZ3NjYXR0ZXIoQW5vZnJlcV9WYWwsIHggPSAiRnJlcV9Bbm8iLCB5ID0gIk1lYW5fVmFsIiwNCiAgICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsICANCiAgICAgICAgICAgIGFkZC5wYXJhbXMgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBmaWxsID0gImxpZ2h0Z3JheSIpLCANCiAgICAgICAgICAgIGNvbmYuaW50ID0gVFJVRSApICsNCnN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDcsIGxhYmVsLnkgPSAxMCkNCg0KDQpjYXQoIiMjIyBTY2F0dGVyIHBsb3Qgd2l0aCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBmb3IgZWFjaCBTZWFzb24iKQ0KZ2dwdWJyOjpnZ3NjYXR0ZXIoQW5vZnJlcV9WYWwsIHggPSAiRnJlcV9Bbm8iLCB5ID0gIk1lYW5fVmFsIiwNCiAgIGNvbG9yID0gIkFubyIsIHBhbGV0dGUgPSAiamNvIiwNCiAgIGFkZCA9ICJyZWcubGluZSIsIGNvbmYuaW50ID0gVFJVRSwNCiAgIHhsaW0gPSBjKDAsIDE1KSwgeWxpbSA9IGMoMCwgOCkpICsgDQpzdGF0X2NvcihhZXMoY29sb3IgPSBBbm8pLCBtZXRob2QgPSAicGVhcnNvbiIsIGxhYmVsLnggPSAxMSkNCg0KYGBgDQoNCg0KDQo8YnI+DQoNCg0KDQoNCg0KPCEtLSBTZXNzaW9uIEluZm8gYW5kIExpY2Vuc2UgLS0+DQoNCjxicj4NCg0KIyBTZXNzaW9uIEluZm8NCmBgYHtyIHNlc3Npb25faW5mbywgZWNobyA9IEZBTFNFLCByZXN1bHRzID0gJ21hcmt1cCd9DQpzZXNzaW9uSW5mbygpICAgIA0KYGBgDQoNCjwhLS0gRm9vdGVyIC0tPg0KJm5ic3A7DQo8aHIgLz4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij5BIHdvcmsgYnkgPGEgaHJlZj0iaHR0cHM6Ly9naXRodWIuY29tL0NsYXVkaXVQYXBhc3RlcmkvIj5DbGF1ZGl1IFBhcGFzdGVyaTwvYT48L3A+DQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PHNwYW4gc3R5bGU9ImNvbG9yOiAjODA4MDgwOyI+PGVtPmNsYXVkaXUucGFwYXN0ZXJpQGdtYWlsLmNvbTwvZW0+PC9zcGFuPjwvcD4NCiZuYnNwOw0K