Read and Merge
The working directory was changed to E:/Cinetic idei noi/EXPERIMENTE OGL Frontiers (O.2 & O.0.3 & O.0.2) inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
DataTrust <- rio::import(file.path(wd, "O.2 REZULTATE\\O.2 Date PrelucrareSPSS cu NEO si STAI", "O.2 Date pt Trust BUN cu NEO si STAIY.xlsx"))
DataDG <- rio::import(file.path(wd, "O.2 REZULTATE\\O.2 Date PrelucrareSPSS cu NEO si STAI", "O.2 Date pt DG BUN cu NEO si STAIY.xlsx"))
DataVAS <- rio::import(file.path(wd, "O.2 REZULTATE\\O.2 VAS,IOS", "O.2 Date PrelucrareSPSS.xlsx"))
DataBIO <- rio::import(file.path(wd, "O.2 BIO", "O.2 Ox si Cortizol.xlsx"))
Data_merge1 <- merge(DataVAS, DataTrust)
Data_merge2 <- merge(Data_merge1, DataDG)
Data_merge3 <- merge(Data_merge2, DataBIO)
Data <- Data_merge3
test_names <- unique(unlist(lapply(list(DataTrust, DataDG, DataVAS, DataBIO), names)))
merge_names <- names(Data)
if(identical(merge_names[order(merge_names)], test_names[order(test_names)])){ # the order matters in identical()
cat("**Merge was succesful**")
rm("Data_merge1", "Data_merge2", "Data_merge3", "DataBIO", "DataDG", "DataTrust", "DataVAS", "test_names", "merge_names")
}else cat("**Merge unsuccesful**")
Merge was succesful
# Gender Dataframe
Data_Gen <- rio::import(file.path(wd, "Gen varsta O03 O02 O2.xlsx"), which = "O.2")
Data_Gen_merged <-
Data %>%
tidyr::separate(Indicativ, c("ID_tag", "ID", "study_tag"), "\\s+") %>% # split on white space
select(-c("ID_tag", "study_tag")) %>%
mutate(ID = as.numeric(as.character(ID))) %>%
dplyr::left_join(., Data_Gen, by = c("ID")) %>%
select(1:7, Gen, Varsta, everything())
Data_fem <-
Data_Gen_merged %>%
filter(Gen == "F")
Data_masc <-
Data_Gen_merged %>%
filter(Gen == "M")
Derive new variables
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Derive new variables
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Data$D_VasS_Poz <- Data[, "VasS_postPoz"] - Data[, "VasS_prePoz"]
Data$D_VasS_Neg <- Data[, "VasS_postNeg"] - Data[, "VasS_preNeg"]
Data$D_VasB_Poz <- Data[, "VasB_postPoz"] - Data[, "VasB_prePoz"]
Data$D_VasB_Neg <- Data[, "VasB_postNeg"] - Data[, "VasB_preNeg"]
Data$D_IOS_Poz <- Data[, "IOS_postPoz"] - Data[, "IOS_prePoz"]
Data$D_IOS_Neg <- Data[, "IOS_postNeg"] - Data[, "IOS_preNeg"]
Data$D_Sam1_Poz <- Data[, "Sam1_postPoz"] - Data[, "Sam1_prePoz"]
Data$D_Sam1_Neg <- Data[, "Sam1_postNeg"] - Data[, "Sam1_preNeg"]
Data$D_Sam2_Poz <- Data[, "Sam2_postPoz"] - Data[, "Sam2_prePoz"]
Data$D_Sam2_Neg <- Data[, "Sam2_postNeg"] - Data[, "Sam2_preNeg"]
Data$D_Sam3_Poz <- Data[, "Sam3_postPoz"] - Data[, "Sam3_prePoz"]
Data$D_Sam3_Neg <- Data[, "Sam3_postNeg"] - Data[, "Sam3_preNeg"]
Data$D_DG_Poz <- Data[, "DG_postPozTot"] - Data[, "DG_prePozTot"]
Data$D_DG_Neg <- Data[, "DG_postNegTot"] - Data[, "DG_preNegTot"]
Data$D_TrustMin_Poz <- Data[, "TrustMinPozPost"] - Data[, "TrustMinPozPre"]
Data$D_TrustMin_Neg <- Data[, "TrustMinNegPost"] - Data[, "TrustMinNegPre"]
Data$D_TrustTot_Poz <- Data[, "TrustTotPozPost"] - Data[, "TrustTotPozPre"]
Data$D_TrustTot_Neg <- Data[, "TrustTotNegPost"] - Data[, "TrustTotNegPre"]
Data$D_Cort_Poz <- Data[, "Cort_post_Poz"] - Data[, "Cort_pre_Poz"]
Data$D_Cort_Neg <- Data[, "Cort_post_Neg"] - Data[, "Cort_pre_Neg"]
Data$D_Ox_Poz <- Data[, "Ox_post_Poz"] - Data[, "Ox_pre_Poz"]
Data$D_Ox_Neg <- Data[, "Ox_post_Neg"] - Data[, "Ox_pre_Neg"]
Define Functions
subchunkify <- function(g, fig_height=7, fig_width=5) {
g_deparsed <- paste0(deparse(
function() {g}
), collapse = '')
sub_chunk <- paste0("
`","``{r sub_chunk_", floor(runif(1) * 10000), ", fig.height=", fig_height, ", fig.width=", fig_width, ", echo=FALSE}",
"\n(",
g_deparsed
, ")()",
"\n`","``
")
cat(knitr::knit(text = knitr::knit_expand(text = sub_chunk), quiet = TRUE))
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define Function for mining correlations
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Function for p-value significance -- both for func_ancova_multibox(), Get_Top_Relationships() and Correlations_With_One()
stars_signif <- function(pval) {
stars = "ns"
if(pval <= 0.001)
stars = "***"
if(pval > 0.001 & pval <= 0.01)
stars = "**"
if(pval > 0.01 & pval <= 0.05)
stars = "*"
if(pval > 0.05 & pval <= 0.1)
stars = "."
stars
}
## Function that returns correlations of all variables in descending order.
# Arg for threshold with default at .3 will keep only correlantions above .3 and below -.3. Also has threshhold for p-value.
Get_Top_Relationships <- function(data_set,
correlation_abs_threshold=0.3,
pvalue_threshold=0.05) {
require(psych)
require(dplyr)
feature_names <- names(data_set)
# strip var names to index for pair-wise identification
names(data_set) <- seq(1:ncol(data_set))
# calculate correlation and significance numbers
cor_data_df <- psych::corr.test(data_set)
# apply var names to correlation matrix over index
rownames(cor_data_df$r) <- feature_names
colnames(cor_data_df$r) <- feature_names
# top cor and sig
relationships_set <- cor_data_df$ci[,c('r','p')]
# apply var names to data over index pairs
relationships_set$feature_1 <- feature_names[as.numeric(sapply(strsplit(rownames(relationships_set), "-"), `[`, 1))]
relationships_set$feature_2 <- feature_names[as.numeric(
sapply(strsplit(rownames(relationships_set), "-"), `[`, 2))]
relationships_set <- dplyr::select(relationships_set, feature_1, feature_2, r, p) %>% dplyr::rename(correlation = r, p.value = p)
# return only the most insteresting relationships
return(filter(relationships_set, abs(correlation) > correlation_abs_threshold &
p.value < pvalue_threshold) %>%
arrange(p.value) %>%
mutate(p.signif = sapply(p.value, function(x) stars_signif(x))))
}
## Function that returns all correlation between numeric variables and one specific variable
Correlations_With_One <- function(data_set,
variable,
correlation_abs_threshold=0.3,
pvalue_threshold=0.05) {
require(psych)
require(dplyr)
# use all numeric columns only
numeric_cols <- unlist(lapply(data_set, is.numeric))
data_set <- data_set[, numeric_cols]
# calculate correlation and significance numbers
cor_data_df <- psych::corr.test(data_set[, names(data_set) != variable], data_set[, variable], minlength = 20, adjust="none")
# top cor and sig
relationships_set <- as.data.frame(cbind(cor_data_df$r, cor_data_df$p)) # same as cor_data_df$ci[,c('r','p')]
relationships_set <- tibble::rownames_to_column(relationships_set, "Variable") # relationships_set$Variable <- rownames(relationships_set)
colnames(relationships_set) <- c("Variable", "correlation", "p.value")
# return only the most insteresting relationships
cat("#### Correlations with ", variable, "\n")
return(filter(relationships_set, abs(correlation) > correlation_abs_threshold &
p.value < pvalue_threshold) %>%
arrange(p.value) %>%
mutate(p.signif = sapply(p.value, function(x) stars_signif(x)))) %>%
tibble::as.tibble()
}
## Function for ploting correlation data frames resulting from Get_Top_Relationships and Correlations_With_One()
func_dotplot_cor <- function(df){ # https://www.r-pkg.org/pkg/ggpubr
dotplotcor_scale_fill <- function(...){ # Fix colors to signif factor levels even if missing
ggplot2:::manual_scale(
'color',
values = setNames(
c("darkgreen", "green3", "lawngreen", "yellow", "red"),
c("***", "**", "*", ".", "ns")),
...
)
}
dtoplot_theme <-
ggpubr::theme_pubr() +
theme(axis.text.y = element_text(size = 10))
if(!"Variable" %in% colnames(df)){ # in oder to work for both Get_Top_Relationships and Correlations_With_One()
df <-
df %>%
unite(cor_between, c("feature_1", "feature_2"), sep = " X ") # unite 2 columns to x name from plot
}else df <- df %>% dplyr::rename(cor_between = Variable) # change Variable to x name from plot
df %>%
ggpubr::ggdotchart(x = "cor_between", y = "correlation",
color = "p.signif", # Color by sig
# palette = c("#00AFBB", "#E7B800", "#FC4E07"), # Custom color palette
sorting = "descending", # Sort value in descending order
add = "segments", # Add segments from y = 0 to dots
add.params = list(color = "lightgray", size = 2), # Change segment color and size
group = "p.signif", # Order by groups
dot.size = 8, # Large dot size
xlab = "",
rotate = TRUE, # Rotate vertically
label = round(.$correlation, 1), # Add mpg values as dot labels
font.label = list(color = "white", size = 9,
vjust = 0.5), # Adjust label parameters
ggtheme = dtoplot_theme) + # ggplot2 theme
dotplotcor_scale_fill() + # Fix colors to signif factor levels even if missing
geom_hline(yintercept = 0, linetype = 2, color = "lightgray")
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define Function for Pre-Post Plots, t Change and ANCOVA Post
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Func t test si boxplot simplu
func_t_box <- function(df, ind, pre_var, post_var, test_method = "t.test"){
df_modif <-
df %>%
select(ind, pre_var, post_var) %>%
tidyr::drop_na() %>%
gather(pre_var, post_var, key = "Cond", value = "value") %>%
mutate_at(vars(c(1, 2)), funs(as.factor)) %>%
mutate(Cond = factor(Cond, levels = c(pre_var, post_var)))
stat_comp <- ggpubr::compare_means(value ~ Cond, data = df_modif, method = test_method, paired = TRUE)
stat_comp2 <-
df_modif %>%
do(tidy(t.test(.$value ~ .$Cond,
paired = TRUE,
data=.)))
plot <-
ggpubr::ggpaired(df_modif, x = "Cond", y = "value", id = ind,
color = "Cond", line.color = "gray", line.size = 0.4,
palette = c("#00AFBB", "#FC4E07"), legend = "none") +
stat_summary(fun.data = mean_se, colour = "darkred") +
ggpubr::stat_compare_means(method = "t.test", paired = TRUE, label.x = as.numeric(df_modif$Cond)-0.4, label.y = max(df_modif$value)+0.5) +
ggpubr::stat_compare_means(method = "t.test", paired = TRUE, label = "p.signif", comparisons = list(c(pre_var, post_var)))
cat(paste0("#### ", pre_var, " ", post_var, "\n", "\n"))
print(stat_comp)
print(stat_comp2)
print(plot)
}
func_ancova_multibox <- function(df, ind, pre_var_c1, post_var_c1, pre_var_c2, post_var_c2){
diff_score_c1 <- paste0(post_var_c1, " - ", pre_var_c1)
diff_score_c2 <- paste0(post_var_c2, " - ", pre_var_c2)
## Plots and p-values for t tests
df_modif <-
df %>%
select(ind, pre_var_c1, post_var_c1, pre_var_c2, post_var_c2) %>%
tidyr::drop_na() %>%
gather(pre_var_c1, post_var_c1, pre_var_c2, post_var_c2, key = "Cond", value = "value") %>%
mutate_at(vars(c(1, 2)), funs(as.factor)) %>%
mutate(Cond = factor(Cond, levels = c(pre_var_c1, post_var_c1, pre_var_c2, post_var_c2)))
stat_comp <- ggpubr::compare_means(value ~ Cond, data = df_modif, method = "t.test", paired = TRUE, p.adjust.method = "holm")
plot <-
ggpubr::ggpaired(df_modif, x = "Cond", y = "value", id = ind,
color = "Cond", line.color = "gray", line.size = 0.4,
palette = c("#00AFBB", "#FC4E07", "#00AFBB", "#FC4E07"), legend = "none") +
stat_summary(fun.data = mean_se, colour = "darkred") +
ggpubr::stat_compare_means(method = "t.test", paired = TRUE, label = "p.signif",
label.y = c(max(df_modif$value) + 0.1*IQR(df_modif$value),
max(df_modif$value) + 0.1*IQR(df_modif$value),
seq(max(df_modif$value) + 0.3*IQR(df_modif$value),
max(df_modif$value) + 0.9*IQR(df_modif$value), length.out = 4)),
comparisons = list(c(pre_var_c1, post_var_c1),
c(pre_var_c2, post_var_c2),
c(post_var_c1, pre_var_c2),
c(pre_var_c1, pre_var_c2),
c(post_var_c1, post_var_c2),
c(pre_var_c1, post_var_c2)))
## For ttestChange or ANCOVAChange - we do ttestChange (Post-Pre) here, but it isnt very important
df_modif2 <-
df %>%
select(ind, pre_var_c1, post_var_c1, pre_var_c2, post_var_c2) %>%
tidyr::drop_na()
df_modif2[diff_score_c1] <- df_modif2[, post_var_c1] - df_modif2[, pre_var_c1]
df_modif2[diff_score_c2] <- df_modif2[, post_var_c2] - df_modif2[, pre_var_c2]
tChange <- t.test(df_modif2[, diff_score_c1], df_modif2[, diff_score_c2], paired = TRUE)
## For descriptives by 2 factors (PrePost and PozNeg)
df_modif3 <-
df %>%
select(ind, pre_var_c1, post_var_c1, pre_var_c2, post_var_c2) %>%
tidyr::drop_na() %>%
gather(pre_var_c1, post_var_c1, pre_var_c2, post_var_c2, key = "Cond", value = "value") %>%
mutate(PrePost = case_when(stringr::str_detect(.$"Cond", "pre|Pre") ~ "Pre",
stringr::str_detect(.$"Cond", "post|Post") ~ "Post",
TRUE ~ NA_character_),
PozNeg = case_when(stringr::str_detect(.$"Cond", "poz|Poz") ~ "Poz",
stringr::str_detect(.$"Cond", "neg|Neg") ~ "Neg",
TRUE ~ NA_character_)) %>%
mutate(PrePost = as.factor(PrePost),
PozNeg = as.factor(PozNeg))
## For ANCOVAPost - this is what we use
df_modif4 <-
df_modif3 %>%
select(-"Cond") %>%
spread("PrePost", "value")
## Models (here we use ANCOVAPost) # https://m-clark.github.io/docs/mixedModels/anovamixed.html#introduction
full_ancovaPost <- # this is better than using lm() and glht()
jmv::ancova(
formula = Post ~ Pre + PozNeg,
data = df_modif4,
homo = TRUE,
ss = "3",
postHoc = ~ PozNeg,
postHocCorr = list("tukey"),
effectSize = list("eta", "partEta")
)
# mod_ancovaPost <- lm(Post ~ Pre + PozNeg, data = df_modif4) # this is a Covariate Second model
# mod_ancovaPost_ss3 <- car::Anova(mod_ancovaPost, type = "III") # Type III sums of squares; see Andy Fields 2012
# postHocs <- multcomp::glht(mod_ancovaPost, linfct = multcomp::mcp(PozNeg = "Tukey")) # differences between the adjusted means,
# sum_postHocs <- summary(postHocs) # use Tukey or Dunnett?s post hoc tests
# conf_postHocs <- confint(postHocs)
scatter <- # Check for homogeneity of regression slopes
ggplot(df_modif4, aes(Pre, Post, colour = PozNeg)) +
geom_point(aes(shape = PozNeg), size = 3) +
geom_smooth(method = "lm", aes(fill = PozNeg), alpha = 0.1)
## Other Models that work for this date
# mod_ancovaPost <- lm(post ~ pre + treat) # exactly the same with aov(post ~ pre + treat)
# summary(mod_ancovaPost)
#
# mod_anovaRM <- aov(score ~ treat*time + Error(id), dflong)
# summary(mod_anovaRM)
#
# mod_lme <- lme4::lmer(score ~ treat*time + (1|id), data=dflong)
# anova(lmeModel)
## Output
print(plot)
cat(paste0("#### ", pre_var_c1, " ", post_var_c1, " ", pre_var_c2, " ", post_var_c2, "\n", "\n"))
cat("#### Descriptives")
psych::describeBy(df_modif3[, "value"], list(df_modif3[, "PrePost"], df_modif3[, "PozNeg"]), mat = TRUE) %>%
as.tibble() %>%
print()
cat("\n")
print(stat_comp)
cat("\n")
cat("#### t Change")
tidy(tChange) %>% print()
cat("\n")
cat("#### ANCOVA Post")
cat("\n")
cat("##### Homogeneity test")
print(tibble::as.tibble(full_ancovaPost$assump$homo))
cat("##### ANCOVA output")
print(tibble::as.tibble(full_ancovaPost$main))
# tidy(mod_ancovaPost) %>%
# mutate(p.signif = sapply(p.value, function(x) stars_signif(x))) %>%
# print()
# cat("\n")
cat("##### Post Hoc")
print(tibble::as.tibble(full_ancovaPost$postHoc[[1]]))
# tidy(sum_postHocs) %>%
# mutate(p.signif = sapply(p.value, function(x) stars_signif(x))) %>%
# print()
cat("\n")
cat("##### Homogeneity of regression slopes")
subchunkify(plot(scatter), 5, 5)
}
Descriptives - Gen Varsta
F M
0.7333333 0.2666667
cannot compute exact p-value with ties
Descriptive statistics by group
group: F
-------------------------------------------------------------------------------------------------------------
group: M
Analyses
Correlations between Diffrence Scores with other variables
Correlations with D_Ox_Poz
as.tibble()
is deprecated, use as_tibble()
(but mind the new semantics). [90mThis warning is displayed once per session.[39m
Correlations with D_Ox_Neg
Correlations with D_Cort_Poz
Correlations with D_Cort_Neg
Correlations with D_VasS_Poz
Correlations with D_VasS_Neg
Correlations with D_VasB_Poz
Correlations with D_VasB_Neg
Correlations with D_IOS_Poz
Correlations with D_IOS_Neg
Correlations with D_DG_Poz
Correlations with D_DG_Neg
Correlations with D_TrustMin_Poz
Correlations with D_TrustMin_Neg
Correlations with D_TrustTot_Poz
Correlations with D_TrustTot_Neg
## Simple before-after analyses with t test
func_t_box(Data, "Indicativ", "Ox_pre_Poz", "Ox_post_Poz") # sig
func_t_box(Data, "Indicativ", "Ox_pre_Neg", "Ox_post_Neg") # sig
func_t_box(Data, "Indicativ", "Cort_pre_Poz", "Cort_post_Poz") # nu
func_t_box(Data, "Indicativ", "Cort_pre_Neg", "Cort_post_Neg") # sig
func_t_box(Data, "Indicativ", "VasS_prePoz", "VasS_postPoz") # sig
func_t_box(Data, "Indicativ", "VasS_preNeg", "VasS_postNeg") # nu
func_t_box(Data, "Indicativ", "VasB_prePoz", "VasB_postPoz") # sig
func_t_box(Data, "Indicativ", "VasB_preNeg", "VasB_postNeg") # nu
func_t_box(Data, "Indicativ", "Sam1_prePoz", "Sam1_postPoz") # sig
func_t_box(Data, "Indicativ", "Sam1_preNeg", "Sam1_postNeg") # nu
func_t_box(Data, "Indicativ", "Sam2_prePoz", "Sam2_postPoz") # nu
func_t_box(Data, "Indicativ", "Sam2_preNeg", "Sam2_postNeg") # nu
func_t_box(Data, "Indicativ", "IOS_prePoz", "IOS_postPoz") # sig
func_t_box(Data, "Indicativ", "IOS_preNeg", "IOS_postNeg") # nu
func_t_box(Data, "Indicativ", "DG_prePozTot", "DG_postPozTot") # nu
func_t_box(Data, "Indicativ", "DG_preNegTot", "DG_postNegTot") # sig
func_t_box(Data, "Indicativ", "TrustMinPozPre", "TrustMinPozPost") # nu
func_t_box(Data, "Indicativ", "TrustMinNegPre", "TrustMinNegPost") # nu
func_t_box(Data, "Indicativ", "TrustTotPozPre", "TrustTotPozPost") # nu
func_t_box(Data, "Indicativ", "TrustTotNegPre", "TrustTotNegPost") # nu
tChance and ANCOVAPost
## tChance and ANCOVAPost
func_ancova_multibox(Data, "Indicativ", "Ox_pre_Poz", "Ox_post_Poz", "Ox_pre_Neg", "Ox_post_Neg")
func_ancova_multibox(Data, "Indicativ", "Cort_pre_Poz", "Cort_post_Poz", "Cort_pre_Neg", "Cort_post_Neg")
func_ancova_multibox(Data, "Indicativ", "VasS_prePoz", "VasS_postPoz", "VasS_preNeg", "VasS_postNeg")
func_ancova_multibox(Data, "Indicativ", "VasB_prePoz", "VasB_postPoz", "VasB_preNeg", "VasB_postNeg")
func_ancova_multibox(Data, "Indicativ", "Sam1_prePoz", "Sam1_postPoz", "Sam1_preNeg", "Sam1_postNeg")
func_ancova_multibox(Data, "Indicativ", "Sam2_prePoz", "Sam2_postPoz", "Sam2_preNeg", "Sam2_postNeg")
func_ancova_multibox(Data, "Indicativ", "IOS_prePoz", "IOS_postPoz", "IOS_preNeg", "IOS_postNeg")
func_ancova_multibox(Data, "Indicativ", "DG_prePozTot", "DG_postPozTot", "DG_preNegTot", "DG_postNegTot")
func_ancova_multibox(Data, "Indicativ", "TrustMinPozPre", "TrustMinPozPost", "TrustMinNegPre", "TrustMinNegPost")
func_ancova_multibox(Data, "Indicativ", "TrustTotPozPre", "TrustTotPozPost", "TrustTotNegPre", "TrustTotNegPost")
–>
Simple before-after analyses with t test by Gender
Females
funs() is soft deprecated as of dplyr 0.8.0 Please use a list of either functions or lambdas:
# Simple named list: list(mean = mean, median = median)
# Auto named with tibble::lst()
: tibble::lst(mean, median)
# Using lambdas list(~ mean(., trim = .2), ~ median(., na.rm = TRUE)) [90mThis warning is displayed once per session.[39m#### Ox_pre_Poz Ox_post_Poz
Ox_pre_Neg Ox_post_Neg
VasS_prePoz VasS_postPoz
VasS_preNeg VasS_postNeg
VasB_prePoz VasB_postPoz
VasB_preNeg VasB_postNeg
# func_t_box(Data_fem, "ID", "Sam1_prePoz", "Sam1_postPoz") # sig
# func_t_box(Data_fem, "ID", "Sam1_preNeg", "Sam1_postNeg") # nu
# func_t_box(Data_fem, "ID", "Sam2_prePoz", "Sam2_postPoz") # nu
# func_t_box(Data_fem, "ID", "Sam2_preNeg", "Sam2_postNeg") # nu
func_t_box(Data_fem, "ID", "IOS_prePoz", "IOS_postPoz") # sig
IOS_prePoz IOS_postPoz
IOS_preNeg IOS_postNeg
DG_prePozTot DG_postPozTot
DG_preNegTot DG_postNegTot
TrustMinPozPre TrustMinPozPost
TrustMinNegPre TrustMinNegPost
TrustTotPozPre TrustTotPozPost
TrustTotNegPre TrustTotNegPost
## tChance and ANCOVAPost
func_ancova_multibox(Data, "Indicativ", "Ox_pre_Poz", "Ox_post_Poz", "Ox_pre_Neg", "Ox_post_Neg")
func_ancova_multibox(Data, "Indicativ", "Cort_pre_Poz", "Cort_post_Poz", "Cort_pre_Neg", "Cort_post_Neg")
func_ancova_multibox(Data, "Indicativ", "VasS_prePoz", "VasS_postPoz", "VasS_preNeg", "VasS_postNeg")
func_ancova_multibox(Data, "Indicativ", "VasB_prePoz", "VasB_postPoz", "VasB_preNeg", "VasB_postNeg")
func_ancova_multibox(Data, "Indicativ", "Sam1_prePoz", "Sam1_postPoz", "Sam1_preNeg", "Sam1_postNeg")
func_ancova_multibox(Data, "Indicativ", "Sam2_prePoz", "Sam2_postPoz", "Sam2_preNeg", "Sam2_postNeg")
func_ancova_multibox(Data, "Indicativ", "IOS_prePoz", "IOS_postPoz", "IOS_preNeg", "IOS_postNeg")
func_ancova_multibox(Data, "Indicativ", "DG_prePozTot", "DG_postPozTot", "DG_preNegTot", "DG_postNegTot")
func_ancova_multibox(Data, "Indicativ", "TrustMinPozPre", "TrustMinPozPost", "TrustMinNegPre", "TrustMinNegPost")
func_ancova_multibox(Data, "Indicativ", "TrustTotPozPre", "TrustTotPozPost", "TrustTotNegPre", "TrustTotNegPost")
–>
## Mining Correlations with Oxy
df_OxyAll_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.05) %>%
dplyr::as_tibble() %>%
dplyr::filter_all(any_vars(grepl("Ox", .))) # only Oxy, but both Pre and Post Oxy
df_OxyAll_cor %>%
print(n = Inf)
df_OxyAll_cor %>%
func_dotplot_cor()
# Correlations only on Pre measures with Oxy -- nothing
df_OxyPre_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.1) %>%
dplyr::as_tibble() %>%
filter_at(vars(feature_1, feature_2), all_vars(grepl("pre|Pre", .))) %>%
dplyr::filter_all(any_vars(grepl("Ox", .)))
df_OxyPre_cor %>%
print(n = Inf)
# Correlations only on Post measures with Oxy
df_OxyPost_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.1) %>%
dplyr::as_tibble() %>%
filter_at(vars(feature_1, feature_2), all_vars(grepl("post|Post", .))) %>%
dplyr::filter_all(any_vars(grepl("Ox", .)))
df_OxyPost_cor %>%
print(n = Inf)
df_OxyPost_cor %>%
func_dotplot_cor()
Correlations with Stess
## Mining Correlations with VasS
df_VasSAll_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.05) %>%
dplyr::as_tibble() %>%
dplyr::filter_all(any_vars(grepl("VasS", .))) # only VasS, but both Pre and Post VasS
df_VasSAll_cor %>%
print(n = Inf)
# Correlations only on Pre measures with VasS
df_VasSPre_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.1) %>%
dplyr::as_tibble() %>%
filter_at(vars(feature_1, feature_2), all_vars(grepl("pre|Pre", .))) %>%
dplyr::filter_all(any_vars(grepl("VasS", .)))
df_VasSPre_cor %>%
print(n = Inf)
df_VasSPre_cor %>%
func_dotplot_cor()
# Correlations only on Post measures with VasS
df_VasSPost_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.1) %>%
dplyr::as_tibble() %>%
filter_at(vars(feature_1, feature_2), all_vars(grepl("post|Post", .))) %>%
dplyr::filter_all(any_vars(grepl("VasS", .)))
df_VasSPost_cor %>%
print(n = Inf)
df_VasSPost_cor %>%
func_dotplot_cor()
Correlations with Well Being
## Mining Correlations with VasB
df_VasBAll_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.05) %>%
dplyr::as_tibble() %>%
dplyr::filter_all(any_vars(grepl("VasB", .))) # only VasB, but both Pre and Post VasB
df_VasBAll_cor %>%
print(n = Inf)
# Correlations only on Pre measures with VasB
df_VasBPre_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.1) %>%
dplyr::as_tibble() %>%
filter_at(vars(feature_1, feature_2), all_vars(grepl("pre|Pre", .))) %>%
dplyr::filter_all(any_vars(grepl("VasB", .)))
df_VasBPre_cor %>%
print(n = Inf)
df_VasBPre_cor %>%
func_dotplot_cor()
# Correlations only on Post measures with VasB
df_VasBPost_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.1) %>%
dplyr::as_tibble() %>%
filter_at(vars(feature_1, feature_2), all_vars(grepl("post|Post", .))) %>%
dplyr::filter_all(any_vars(grepl("VasB", .)))
df_VasBPost_cor %>%
print(n = Inf)
df_VasBPost_cor %>%
func_dotplot_cor()
Correlations with IOS
## Mining Correlations with IOS
df_IOSAll_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.05) %>%
dplyr::as_tibble() %>%
dplyr::filter_all(any_vars(grepl("IOS", .))) # only IOS, but both Pre and Post IOS
df_IOSAll_cor %>%
print(n = Inf)
# Correlations only on Pre measures with IOS
df_IOSPre_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.1) %>%
dplyr::as_tibble() %>%
filter_at(vars(feature_1, feature_2), all_vars(grepl("pre|Pre", .))) %>%
dplyr::filter_all(any_vars(grepl("IOS", .)))
df_IOSPre_cor %>%
print(n = Inf)
df_IOSPre_cor %>%
func_dotplot_cor()
# Correlations only on Post measures with IOS
df_IOSPost_cor <-
Get_Top_Relationships(Data[,-c(1:7)], correlation_abs_threshold = 0.2, pvalue_threshold = 0.1) %>%
dplyr::as_tibble() %>%
filter_at(vars(feature_1, feature_2), all_vars(grepl("post|Post", .))) %>%
dplyr::filter_all(any_vars(grepl("IOS", .)))
df_IOSPost_cor %>%
print(n = Inf)
df_IOSPost_cor %>%
func_dotplot_cor()
–>
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] rio_0.5.16 plyr_1.8.4 summarytools_0.8.8 DT_0.5 ggpubr_0.2 magrittr_1.5 broom_0.5.2
[8] papaja_0.1.0.9842 psych_1.8.12 forcats_0.4.0 stringr_1.4.0 dplyr_0.8.3 purrr_0.3.2 readr_1.3.1
[15] tidyr_1.0.0 tibble_2.1.3 ggplot2_3.2.1 tidyverse_1.2.1 pacman_0.5.1
loaded via a namespace (and not attached):
[1] Rcpp_1.0.2 lubridate_1.7.4 lattice_0.20-38 assertthat_0.2.1 zeallot_0.1.0 digest_0.6.21 R6_2.4.0
[8] cellranger_1.1.0 backports_1.1.4 httr_1.4.0 pillar_1.4.2 rlang_0.4.0 curl_3.2 lazyeval_0.2.2
[15] readxl_1.1.0 data.table_1.11.8 rstudioapi_0.8 labeling_0.3 foreign_0.8-71 pander_0.6.3 htmlwidgets_1.3
[22] RCurl_1.95-4.11 munsell_0.5.0 compiler_3.6.1 modelr_0.1.5 xfun_0.9 pkgconfig_2.0.3 mnormt_1.5-5
[29] htmltools_0.3.6 tidyselect_0.2.5 codetools_0.2-16 matrixStats_0.54.0 crayon_1.3.4 withr_2.1.2 bitops_1.0-6
[36] grid_3.6.1 nlme_3.1-140 jsonlite_1.6 gtable_0.3.0 lifecycle_0.1.0 scales_1.0.0 zip_1.0.0
[43] cli_1.1.0 stringi_1.4.3 ggsignif_0.4.0 pryr_0.1.4 xml2_1.2.0 ellipsis_0.3.0 rapportools_1.0
[50] generics_0.0.2 vctrs_0.2.0 openxlsx_4.1.0 tools_3.6.1 glue_1.3.1 hms_0.5.1 parallel_3.6.1
[57] colorspace_1.4-1 rvest_0.3.2 knitr_1.25 haven_2.1.1
A work by Claudiu Papasteri
claudiu.papasteri@gmail.com
LS0tDQp0aXRsZTogIjxicj4gTy4yIFJlcG9ydCAtIEdlbmRlciIgDQpzdWJ0aXRsZTogIkZvY3VzIG9uIE9YVCBieSBHZW5kZXIiDQphdXRob3I6ICI8YnI+IENsYXVkaXUgUGFwYXN0ZXJpIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJW0gJVknKWAiDQpvdXRwdXQ6IA0KICAgIGh0bWxfbm90ZWJvb2s6DQogICAgICAgICAgIyBzZWxmX2NvbnRhaW5lZDogbm8NCiAgICAgICAgICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgICAgICAgICAgdG9jOiB0cnVlDQogICAgICAgICAgICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgdGhlbWU6IHNwYWNlbGFiDQogICAgICAgICAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgICAgICAgICBmb250LWZhbWlseTogQXJpYWwNCiAgICAgICAgICAgIGZpZ193aWR0aDogMTANCiAgICAgICAgICAgIGZpZ19oZWlnaHQ6IDkNCiAgICAgIyBwZGZfZG9jdW1lbnQ6IA0KICAgICAgICAgICAgIyB0b2M6IHRydWUNCiAgICAgICAgICAgICMgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICAjIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgIyBmb250c2l6ZTogMTFwdA0KICAgICAgICAgICAgIyBnZW9tZXRyeTogbWFyZ2luPTFpbg0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDcNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNg0KICAgICAgICAgICAgIyBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgICMgZ2l0aHViX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBodG1sX3ByZXZpZXc6IGZhbHNlDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNQ0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA1DQogICAgICAgICAgICAjIGRldjoganBlZw0KLS0tDQoNCg0KPCEtLSBTZXR1cCAtLT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gVFJVRSwgbWVzc2FnZSA9IFRSVUUsIGNhY2hlID0gVFJVRSAgICAgICAjIGVjaG8gPSBGYWxzZSBmb3IgZ2l0aHViX2RvY3VtZW50LCBidXQgd2lsbCBiZSBmb2xkZWQgaW4gaHRtbF9ub3RlYm9vaw0KKQ0KDQojIEdlbmVyYWwgUiBvcHRpb25zIGFuZCBpbmZvDQpzZXQuc2VlZCgxMTEpICAgICAgICAgICAgICAgIyBpbiBjYXNlIHdlIHVzZSByYW5kb21pemVkIHByb2NlZHVyZXMgICAgICAgDQpvcHRpb25zKHNjaXBlbiA9IDk5OSkgICAgICAgIyBwb3NpdGl2ZSB2YWx1ZXMgYmlhcyB0b3dhcmRzIGZpeGVkIGFuZCBuZWdhdGl2ZSB0b3dhcmRzIHNjaWVudGlmaWMgbm90YXRpb24NCg0KIyBMb2FkIHBhY2thZ2VzDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFja2FnZXMgPC0gYygNCiAgInRpZHl2ZXJzZSIsICAgICAgIyBiZXN0IHRoaW5nIHRoYXQgaGFwcGVuZCB0byBtZQ0KICAicHN5Y2giLCAgICAgICAgICAjIGdlbmVyYWwgcHVycG9zZSB0b29sYm94IGZvciBwZXJzb25hbGl0eSwgcHN5Y2hvbWV0cmljIHRoZW9yeSBhbmQgZXhwZXJpbWVudGFsIHBzeWNob2xvZ3kNCiAgInBhcGFqYSIsICAgICAgICAgIyBmb3IgQVBBIHN0eWxlDQogICJicm9vbSIsICAgICAgICAgICMgZm9yIHRpZHkgbW9kZWxsaW5nDQogICJnZ3Bsb3QyIiwgICAgICAgICMgYmVzdCBwbG90cw0KICAiZ2dwdWJyIiwgICAgICAgICAjIGdncGxvdDIgdG8gcHVibGljYXRpb24gcXVhbGl0eQ0KICAiRFQiLCAgICAgICAgICAgICAjIG5pY2Ugc2VhcmNoYWJsZSBhbmQgZG93bmxvYWRhYmxlIHRhYmxlcw0KICAic3VtbWFyeXRvb2xzIiwNCiAgInBseXIiLCANCiAgInJpbyINCiAgIyAsIC4uLg0KKQ0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY21hbjo6cF9sb2FkKGNoYXIgPSBwYWNrYWdlcykNCg0KIyBUaGVtZXMgZm9yIGdncGxvdDIgcGxvdGluZyAoaGVyZSB1c2VkIEFQQSBzdHlsZSkNCnRoZW1lX3NldCh0aGVtZV9hcGEoKSkNCmBgYA0KDQoNCg0KPCEtLSBSZXBvcnQgLS0+DQoNCg0KIyBSZWFkIGFuZCBNZXJnZQ0KDQoNCmBgYHtyIHJlYWRfbWVyZ2UsIHJlc3VsdHM9J2FzaXMnfQ0KI35+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+fg0KIyBSZWFkIGFuZCBNZXJnZQ0KI35+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+fg0Kd2QgPC0gIkU6L0NpbmV0aWMgaWRlaSBub2kvRVhQRVJJTUVOVEUgT0dMIEZyb250aWVycyAoTy4yICYgTy4wLjMgJiBPLjAuMikiDQpzZXR3ZCh3ZCkNCg0KRGF0YVRydXN0IDwtIHJpbzo6aW1wb3J0KGZpbGUucGF0aCh3ZCwgIk8uMiBSRVpVTFRBVEVcXE8uMiBEYXRlIFByZWx1Y3JhcmVTUFNTIGN1IE5FTyBzaSBTVEFJIiwgIk8uMiBEYXRlIHB0IFRydXN0IEJVTiBjdSBORU8gc2kgU1RBSVkueGxzeCIpKQ0KRGF0YURHIDwtIHJpbzo6aW1wb3J0KGZpbGUucGF0aCh3ZCwgIk8uMiBSRVpVTFRBVEVcXE8uMiBEYXRlIFByZWx1Y3JhcmVTUFNTIGN1IE5FTyBzaSBTVEFJIiwgIk8uMiBEYXRlIHB0IERHIEJVTiBjdSBORU8gc2kgU1RBSVkueGxzeCIpKQ0KRGF0YVZBUyA8LSByaW86OmltcG9ydChmaWxlLnBhdGgod2QsICJPLjIgUkVaVUxUQVRFXFxPLjIgVkFTLElPUyIsICJPLjIgRGF0ZSBQcmVsdWNyYXJlU1BTUy54bHN4IikpDQpEYXRhQklPIDwtIHJpbzo6aW1wb3J0KGZpbGUucGF0aCh3ZCwgIk8uMiBCSU8iLCAiTy4yIE94IHNpIENvcnRpem9sLnhsc3giKSkNCiAgDQpEYXRhX21lcmdlMSA8LSBtZXJnZShEYXRhVkFTLCBEYXRhVHJ1c3QpICANCkRhdGFfbWVyZ2UyIDwtIG1lcmdlKERhdGFfbWVyZ2UxLCBEYXRhREcpIA0KRGF0YV9tZXJnZTMgPC0gbWVyZ2UoRGF0YV9tZXJnZTIsIERhdGFCSU8pDQoNCkRhdGEgPC0gRGF0YV9tZXJnZTMNCg0KdGVzdF9uYW1lcyA8LSB1bmlxdWUodW5saXN0KGxhcHBseShsaXN0KERhdGFUcnVzdCwgRGF0YURHLCBEYXRhVkFTLCBEYXRhQklPKSwgbmFtZXMpKSkNCm1lcmdlX25hbWVzIDwtIG5hbWVzKERhdGEpDQoNCmlmKGlkZW50aWNhbChtZXJnZV9uYW1lc1tvcmRlcihtZXJnZV9uYW1lcyldLCB0ZXN0X25hbWVzW29yZGVyKHRlc3RfbmFtZXMpXSkpeyAgICAjIHRoZSBvcmRlciBtYXR0ZXJzIGluIGlkZW50aWNhbCgpDQogIGNhdCgiKipNZXJnZSB3YXMgc3VjY2VzZnVsKioiKQ0KICBybSgiRGF0YV9tZXJnZTEiLCAiRGF0YV9tZXJnZTIiLCAiRGF0YV9tZXJnZTMiLCAiRGF0YUJJTyIsICJEYXRhREciLCAiRGF0YVRydXN0IiwgIkRhdGFWQVMiLCAidGVzdF9uYW1lcyIsICJtZXJnZV9uYW1lcyIpDQp9ZWxzZSBjYXQoIioqTWVyZ2UgdW5zdWNjZXNmdWwqKiIpIA0KDQoNCiMgR2VuZGVyIERhdGFmcmFtZQ0KRGF0YV9HZW4gPC0gcmlvOjppbXBvcnQoZmlsZS5wYXRoKHdkLCAiR2VuIHZhcnN0YSBPMDMgTzAyIE8yLnhsc3giKSwgd2hpY2ggPSAiTy4yIikNCg0KRGF0YV9HZW5fbWVyZ2VkIDwtIA0KICBEYXRhICU+JQ0KICB0aWR5cjo6c2VwYXJhdGUoSW5kaWNhdGl2LCAgYygiSURfdGFnIiwgIklEIiwgInN0dWR5X3RhZyIpLCAiXFxzKyIpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNwbGl0IG9uIHdoaXRlIHNwYWNlDQogIHNlbGVjdCgtYygiSURfdGFnIiwgInN0dWR5X3RhZyIpKSAlPiUNCiAgbXV0YXRlKElEID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoSUQpKSkgJT4lDQogIGRwbHlyOjpsZWZ0X2pvaW4oLiwgRGF0YV9HZW4sIGJ5ID0gYygiSUQiKSkgJT4lDQogIHNlbGVjdCgxOjcsIEdlbiwgVmFyc3RhLCBldmVyeXRoaW5nKCkpDQoNCkRhdGFfZmVtIDwtIA0KICBEYXRhX0dlbl9tZXJnZWQgJT4lDQogIGZpbHRlcihHZW4gPT0gIkYiKQ0KDQpEYXRhX21hc2MgPC0gDQogIERhdGFfR2VuX21lcmdlZCAlPiUNCiAgZmlsdGVyKEdlbiA9PSAiTSIpDQpgYGANCg0KDQojIERlcml2ZSBuZXcgdmFyaWFibGVzDQoNCmBgYHtyIGRlcml2ZV92YXIsIGhpZGU9VFJVRX0NCiN+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+fn4NCiMgRGVyaXZlIG5ldyB2YXJpYWJsZXMNCiN+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+fn4NCkRhdGEkRF9WYXNTX1BveiA8LSBEYXRhWywgIlZhc1NfcG9zdFBveiJdIC0gRGF0YVssICJWYXNTX3ByZVBveiJdIA0KRGF0YSREX1Zhc1NfTmVnIDwtIERhdGFbLCAiVmFzU19wb3N0TmVnIl0gLSBEYXRhWywgIlZhc1NfcHJlTmVnIl0NCkRhdGEkRF9WYXNCX1BveiA8LSBEYXRhWywgIlZhc0JfcG9zdFBveiJdIC0gRGF0YVssICJWYXNCX3ByZVBveiJdIA0KRGF0YSREX1Zhc0JfTmVnIDwtIERhdGFbLCAiVmFzQl9wb3N0TmVnIl0gLSBEYXRhWywgIlZhc0JfcHJlTmVnIl0NCkRhdGEkRF9JT1NfUG96IDwtIERhdGFbLCAiSU9TX3Bvc3RQb3oiXSAtIERhdGFbLCAiSU9TX3ByZVBveiJdIA0KRGF0YSREX0lPU19OZWcgPC0gRGF0YVssICJJT1NfcG9zdE5lZyJdIC0gRGF0YVssICJJT1NfcHJlTmVnIl0NCg0KRGF0YSREX1NhbTFfUG96IDwtIERhdGFbLCAiU2FtMV9wb3N0UG96Il0gLSBEYXRhWywgIlNhbTFfcHJlUG96Il0gDQpEYXRhJERfU2FtMV9OZWcgPC0gRGF0YVssICJTYW0xX3Bvc3ROZWciXSAtIERhdGFbLCAiU2FtMV9wcmVOZWciXQ0KRGF0YSREX1NhbTJfUG96IDwtIERhdGFbLCAiU2FtMl9wb3N0UG96Il0gLSBEYXRhWywgIlNhbTJfcHJlUG96Il0gDQpEYXRhJERfU2FtMl9OZWcgPC0gRGF0YVssICJTYW0yX3Bvc3ROZWciXSAtIERhdGFbLCAiU2FtMl9wcmVOZWciXQ0KRGF0YSREX1NhbTNfUG96IDwtIERhdGFbLCAiU2FtM19wb3N0UG96Il0gLSBEYXRhWywgIlNhbTNfcHJlUG96Il0gDQpEYXRhJERfU2FtM19OZWcgPC0gRGF0YVssICJTYW0zX3Bvc3ROZWciXSAtIERhdGFbLCAiU2FtM19wcmVOZWciXQ0KDQpEYXRhJERfREdfUG96IDwtIERhdGFbLCAiREdfcG9zdFBvelRvdCJdIC0gRGF0YVssICJER19wcmVQb3pUb3QiXSANCkRhdGEkRF9ER19OZWcgPC0gRGF0YVssICJER19wb3N0TmVnVG90Il0gLSBEYXRhWywgIkRHX3ByZU5lZ1RvdCJdDQoNCkRhdGEkRF9UcnVzdE1pbl9Qb3ogPC0gRGF0YVssICJUcnVzdE1pblBvelBvc3QiXSAtIERhdGFbLCAiVHJ1c3RNaW5Qb3pQcmUiXSANCkRhdGEkRF9UcnVzdE1pbl9OZWcgPC0gRGF0YVssICJUcnVzdE1pbk5lZ1Bvc3QiXSAtIERhdGFbLCAiVHJ1c3RNaW5OZWdQcmUiXQ0KRGF0YSREX1RydXN0VG90X1BveiA8LSBEYXRhWywgIlRydXN0VG90UG96UG9zdCJdIC0gRGF0YVssICJUcnVzdFRvdFBvelByZSJdIA0KRGF0YSREX1RydXN0VG90X05lZyA8LSBEYXRhWywgIlRydXN0VG90TmVnUG9zdCJdIC0gRGF0YVssICJUcnVzdFRvdE5lZ1ByZSJdDQoNCkRhdGEkRF9Db3J0X1BveiA8LSBEYXRhWywgIkNvcnRfcG9zdF9Qb3oiXSAtIERhdGFbLCAiQ29ydF9wcmVfUG96Il0gDQpEYXRhJERfQ29ydF9OZWcgPC0gRGF0YVssICJDb3J0X3Bvc3RfTmVnIl0gLSBEYXRhWywgIkNvcnRfcHJlX05lZyJdDQpEYXRhJERfT3hfUG96IDwtIERhdGFbLCAiT3hfcG9zdF9Qb3oiXSAtIERhdGFbLCAiT3hfcHJlX1BveiJdIA0KRGF0YSREX094X05lZyA8LSBEYXRhWywgIk94X3Bvc3RfTmVnIl0gLSBEYXRhWywgIk94X3ByZV9OZWciXQ0KYGBgDQoNCg0KIyBEZWZpbmUgRnVuY3Rpb25zIA0KDQpgYGB7ciBkZWZfZnVuY19zdWJjaHVua3Bsb3QsIGhpZGU9VFJVRX0NCnN1YmNodW5raWZ5IDwtIGZ1bmN0aW9uKGcsIGZpZ19oZWlnaHQ9NywgZmlnX3dpZHRoPTUpIHsNCiAgZ19kZXBhcnNlZCA8LSBwYXN0ZTAoZGVwYXJzZSgNCiAgICBmdW5jdGlvbigpIHtnfQ0KICApLCBjb2xsYXBzZSA9ICcnKQ0KICANCiAgc3ViX2NodW5rIDwtIHBhc3RlMCgiDQogIGAiLCJgYHtyIHN1Yl9jaHVua18iLCBmbG9vcihydW5pZigxKSAqIDEwMDAwKSwgIiwgZmlnLmhlaWdodD0iLCBmaWdfaGVpZ2h0LCAiLCBmaWcud2lkdGg9IiwgZmlnX3dpZHRoLCAiLCBlY2hvPUZBTFNFfSIsDQogICJcbigiLCANCiAgICBnX2RlcGFyc2VkDQogICAgLCAiKSgpIiwNCiAgIlxuYCIsImBgDQogICIpDQogIA0KICBjYXQoa25pdHI6OmtuaXQodGV4dCA9IGtuaXRyOjprbml0X2V4cGFuZCh0ZXh0ID0gc3ViX2NodW5rKSwgcXVpZXQgPSBUUlVFKSkNCn0NCmBgYA0KDQpgYGB7ciBkZWZfZnVuYywgaGlkZT1UUlVFfQ0KI35+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+fg0KIyBEZWZpbmUgRnVuY3Rpb24gZm9yIG1pbmluZyBjb3JyZWxhdGlvbnMNCiN+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+fn4NCiMjIEZ1bmN0aW9uIGZvciBwLXZhbHVlIHNpZ25pZmljYW5jZSAtLSBib3RoIGZvciBmdW5jX2FuY292YV9tdWx0aWJveCgpLCBHZXRfVG9wX1JlbGF0aW9uc2hpcHMoKSBhbmQgQ29ycmVsYXRpb25zX1dpdGhfT25lKCkNCnN0YXJzX3NpZ25pZiA8LSBmdW5jdGlvbihwdmFsKSB7DQogIHN0YXJzID0gIm5zIg0KICBpZihwdmFsIDw9IDAuMDAxKQ0KICAgIHN0YXJzID0gIioqKiINCiAgaWYocHZhbCA+IDAuMDAxICYgcHZhbCA8PSAwLjAxKQ0KICAgIHN0YXJzID0gIioqIg0KICBpZihwdmFsID4gMC4wMSAmIHB2YWwgPD0gMC4wNSkNCiAgICBzdGFycyA9ICIqIg0KICBpZihwdmFsID4gMC4wNSAmIHB2YWwgPD0gMC4xKQ0KICAgIHN0YXJzID0gIi4iDQogIHN0YXJzDQp9DQoNCiMjIEZ1bmN0aW9uIHRoYXQgcmV0dXJucyBjb3JyZWxhdGlvbnMgb2YgYWxsIHZhcmlhYmxlcyBpbiBkZXNjZW5kaW5nIG9yZGVyLg0KIyBBcmcgZm9yIHRocmVzaG9sZCB3aXRoIGRlZmF1bHQgYXQgLjMgd2lsbCBrZWVwIG9ubHkgY29ycmVsYW50aW9ucyBhYm92ZSAuMyBhbmQgYmVsb3cgLS4zLiBBbHNvIGhhcyB0aHJlc2hob2xkIGZvciBwLXZhbHVlLiANCkdldF9Ub3BfUmVsYXRpb25zaGlwcyA8LSBmdW5jdGlvbihkYXRhX3NldCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZD0wLjMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbHVlX3RocmVzaG9sZD0wLjA1KSB7DQogIHJlcXVpcmUocHN5Y2gpDQogIHJlcXVpcmUoZHBseXIpDQogIGZlYXR1cmVfbmFtZXMgPC0gbmFtZXMoZGF0YV9zZXQpDQogICMgc3RyaXAgdmFyIG5hbWVzIHRvIGluZGV4IGZvciBwYWlyLXdpc2UgaWRlbnRpZmljYXRpb24NCiAgbmFtZXMoZGF0YV9zZXQpIDwtIHNlcSgxOm5jb2woZGF0YV9zZXQpKQ0KICAjIGNhbGN1bGF0ZSBjb3JyZWxhdGlvbiBhbmQgc2lnbmlmaWNhbmNlIG51bWJlcnMNCiAgY29yX2RhdGFfZGYgPC0gcHN5Y2g6OmNvcnIudGVzdChkYXRhX3NldCkNCiAgIyBhcHBseSB2YXIgbmFtZXMgdG8gY29ycmVsYXRpb24gbWF0cml4IG92ZXIgaW5kZXgNCiAgcm93bmFtZXMoY29yX2RhdGFfZGYkcikgPC0gZmVhdHVyZV9uYW1lcw0KICBjb2xuYW1lcyhjb3JfZGF0YV9kZiRyKSA8LSBmZWF0dXJlX25hbWVzDQogICMgdG9wIGNvciBhbmQgc2lnDQogIHJlbGF0aW9uc2hpcHNfc2V0IDwtIGNvcl9kYXRhX2RmJGNpWyxjKCdyJywncCcpXQ0KICAjIGFwcGx5IHZhciBuYW1lcyB0byBkYXRhIG92ZXIgaW5kZXggcGFpcnMNCiAgcmVsYXRpb25zaGlwc19zZXQkZmVhdHVyZV8xIDwtIGZlYXR1cmVfbmFtZXNbYXMubnVtZXJpYyhzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMocmVsYXRpb25zaGlwc19zZXQpLCAiLSIpLCBgW2AsIDEpKV0NCiAgcmVsYXRpb25zaGlwc19zZXQkZmVhdHVyZV8yIDwtIGZlYXR1cmVfbmFtZXNbYXMubnVtZXJpYygNCiAgICBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMocmVsYXRpb25zaGlwc19zZXQpLCAiLSIpLCBgW2AsIDIpKV0NCiAgcmVsYXRpb25zaGlwc19zZXQgPC0gZHBseXI6OnNlbGVjdChyZWxhdGlvbnNoaXBzX3NldCwgZmVhdHVyZV8xLCBmZWF0dXJlXzIsIHIsIHApICU+JSBkcGx5cjo6cmVuYW1lKGNvcnJlbGF0aW9uID0gciwgcC52YWx1ZSA9IHApDQogICMgcmV0dXJuIG9ubHkgdGhlIG1vc3QgaW5zdGVyZXN0aW5nIHJlbGF0aW9uc2hpcHMNCiAgcmV0dXJuKGZpbHRlcihyZWxhdGlvbnNoaXBzX3NldCwgYWJzKGNvcnJlbGF0aW9uKSA+IGNvcnJlbGF0aW9uX2Fic190aHJlc2hvbGQgJg0KICAgICAgICAgICAgICAgICAgcC52YWx1ZSA8IHB2YWx1ZV90aHJlc2hvbGQpICU+JSANCiAgICAgICAgYXJyYW5nZShwLnZhbHVlKSAlPiUNCiAgICAgICAgbXV0YXRlKHAuc2lnbmlmID0gc2FwcGx5KHAudmFsdWUsIGZ1bmN0aW9uKHgpIHN0YXJzX3NpZ25pZih4KSkpKQ0KfQ0KDQojIyBGdW5jdGlvbiB0aGF0IHJldHVybnMgYWxsIGNvcnJlbGF0aW9uIGJldHdlZW4gbnVtZXJpYyB2YXJpYWJsZXMgYW5kIG9uZSBzcGVjaWZpYyB2YXJpYWJsZQ0KQ29ycmVsYXRpb25zX1dpdGhfT25lIDwtIGZ1bmN0aW9uKGRhdGFfc2V0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uX2Fic190aHJlc2hvbGQ9MC4zLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZV90aHJlc2hvbGQ9MC4wNSkgew0KICByZXF1aXJlKHBzeWNoKQ0KICByZXF1aXJlKGRwbHlyKQ0KICAjIHVzZSBhbGwgbnVtZXJpYyBjb2x1bW5zIG9ubHkNCiAgbnVtZXJpY19jb2xzIDwtIHVubGlzdChsYXBwbHkoZGF0YV9zZXQsIGlzLm51bWVyaWMpKQ0KICBkYXRhX3NldCA8LSBkYXRhX3NldFssIG51bWVyaWNfY29sc10gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICMgY2FsY3VsYXRlIGNvcnJlbGF0aW9uIGFuZCBzaWduaWZpY2FuY2UgbnVtYmVycw0KICBjb3JfZGF0YV9kZiA8LSBwc3ljaDo6Y29yci50ZXN0KGRhdGFfc2V0WywgbmFtZXMoZGF0YV9zZXQpICE9IHZhcmlhYmxlXSwgZGF0YV9zZXRbLCB2YXJpYWJsZV0sIG1pbmxlbmd0aCA9IDIwLCBhZGp1c3Q9Im5vbmUiKQ0KICAjIHRvcCBjb3IgYW5kIHNpZw0KICByZWxhdGlvbnNoaXBzX3NldCA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKGNvcl9kYXRhX2RmJHIsIGNvcl9kYXRhX2RmJHApKSAgICAgIyBzYW1lIGFzICBjb3JfZGF0YV9kZiRjaVssYygncicsJ3AnKV0NCiAgcmVsYXRpb25zaGlwc19zZXQgPC0gdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4ocmVsYXRpb25zaGlwc19zZXQsICJWYXJpYWJsZSIpICAgIyByZWxhdGlvbnNoaXBzX3NldCRWYXJpYWJsZSA8LSByb3duYW1lcyhyZWxhdGlvbnNoaXBzX3NldCkNCiAgY29sbmFtZXMocmVsYXRpb25zaGlwc19zZXQpIDwtIGMoIlZhcmlhYmxlIiwgImNvcnJlbGF0aW9uIiwgInAudmFsdWUiKQ0KICAjIHJldHVybiBvbmx5IHRoZSBtb3N0IGluc3RlcmVzdGluZyByZWxhdGlvbnNoaXBzDQogIGNhdCgiIyMjIyBDb3JyZWxhdGlvbnMgd2l0aCAiLCB2YXJpYWJsZSwgIlxuIikNCiAgcmV0dXJuKGZpbHRlcihyZWxhdGlvbnNoaXBzX3NldCwgYWJzKGNvcnJlbGF0aW9uKSA+IGNvcnJlbGF0aW9uX2Fic190aHJlc2hvbGQgJg0KICAgICAgICAgICAgICAgICAgcC52YWx1ZSA8IHB2YWx1ZV90aHJlc2hvbGQpICU+JSANCiAgICAgICAgICAgYXJyYW5nZShwLnZhbHVlKSAlPiUNCiAgICAgICAgICAgbXV0YXRlKHAuc2lnbmlmID0gc2FwcGx5KHAudmFsdWUsIGZ1bmN0aW9uKHgpIHN0YXJzX3NpZ25pZih4KSkpKSAlPiUNCiAgICAgICAgICAgdGliYmxlOjphcy50aWJibGUoKQ0KfSAgDQoNCg0KIyMgRnVuY3Rpb24gZm9yIHBsb3RpbmcgY29ycmVsYXRpb24gZGF0YSBmcmFtZXMgcmVzdWx0aW5nIGZyb20gR2V0X1RvcF9SZWxhdGlvbnNoaXBzIGFuZCBDb3JyZWxhdGlvbnNfV2l0aF9PbmUoKQ0KZnVuY19kb3RwbG90X2NvciA8LSBmdW5jdGlvbihkZil7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaHR0cHM6Ly93d3cuci1wa2cub3JnL3BrZy9nZ3B1YnINCiAgZG90cGxvdGNvcl9zY2FsZV9maWxsIDwtIGZ1bmN0aW9uKC4uLil7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEZpeCBjb2xvcnMgdG8gc2lnbmlmIGZhY3RvciBsZXZlbHMgZXZlbiBpZiBtaXNzaW5nDQogICAgZ2dwbG90Mjo6Om1hbnVhbF9zY2FsZSggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgJ2NvbG9yJywgDQogICAgICB2YWx1ZXMgPSBzZXROYW1lcygNCiAgICAgICAgYygiZGFya2dyZWVuIiwgImdyZWVuMyIsICJsYXduZ3JlZW4iLCAieWVsbG93IiwgInJlZCIpLCANCiAgICAgICAgYygiKioqIiwgIioqIiwgIioiLCAiLiIsICJucyIpKSwgDQogICAgICAuLi4NCiAgICApDQogIH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIA0KICBkdG9wbG90X3RoZW1lIDwtIA0KICAgIGdncHVicjo6dGhlbWVfcHVicigpICsNCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKQ0KICANCiAgaWYoISJWYXJpYWJsZSIgJWluJSBjb2xuYW1lcyhkZikpeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gb2RlciB0byB3b3JrIGZvciBib3RoIEdldF9Ub3BfUmVsYXRpb25zaGlwcyBhbmQgQ29ycmVsYXRpb25zX1dpdGhfT25lKCkNCiAgZGYgPC0gDQogICAgZGYgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgIHVuaXRlKGNvcl9iZXR3ZWVuLCBjKCJmZWF0dXJlXzEiLCAiZmVhdHVyZV8yIiksIHNlcCA9ICIgWCAiKSAgICAgICAgICAgICAgICMgdW5pdGUgMiBjb2x1bW5zIHRvIHggbmFtZSBmcm9tIHBsb3QNCiAgfWVsc2UgZGYgPC0gZGYgJT4lIGRwbHlyOjpyZW5hbWUoY29yX2JldHdlZW4gPSBWYXJpYWJsZSkgICAgICAgICAgICAgICAgICAgICAgICMgY2hhbmdlIFZhcmlhYmxlIHRvIHggbmFtZSBmcm9tIHBsb3QNCiAgDQogIGRmICU+JQ0KICAgIGdncHVicjo6Z2dkb3RjaGFydCh4ID0gImNvcl9iZXR3ZWVuIiwgeSA9ICJjb3JyZWxhdGlvbiIsDQogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gInAuc2lnbmlmIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIENvbG9yIGJ5IHNpZw0KICAgICAgICAgICAgICAgICAgICAgICAjICAgcGFsZXR0ZSA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksICAgICAgICAgIyBDdXN0b20gY29sb3IgcGFsZXR0ZQ0KICAgICAgICAgICAgICAgICAgICAgICBzb3J0aW5nID0gImRlc2NlbmRpbmciLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBTb3J0IHZhbHVlIGluIGRlc2NlbmRpbmcgb3JkZXINCiAgICAgICAgICAgICAgICAgICAgICAgYWRkID0gInNlZ21lbnRzIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQWRkIHNlZ21lbnRzIGZyb20geSA9IDAgdG8gZG90cw0KICAgICAgICAgICAgICAgICAgICAgICBhZGQucGFyYW1zID0gbGlzdChjb2xvciA9ICJsaWdodGdyYXkiLCBzaXplID0gMiksICAgICAgICAgIyBDaGFuZ2Ugc2VnbWVudCBjb2xvciBhbmQgc2l6ZQ0KICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJwLnNpZ25pZiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBPcmRlciBieSBncm91cHMNCiAgICAgICAgICAgICAgICAgICAgICAgZG90LnNpemUgPSA4LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTGFyZ2UgZG90IHNpemUNCiAgICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICIiLA0KICAgICAgICAgICAgICAgICAgICAgICByb3RhdGUgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBSb3RhdGUgdmVydGljYWxseQ0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHJvdW5kKC4kY29ycmVsYXRpb24sIDEpLCAgICAgICAgICAgICAgICAgICAgICAgICAgIyBBZGQgbXBnIHZhbHVlcyBhcyBkb3QgbGFiZWxzDQogICAgICAgICAgICAgICAgICAgICAgIGZvbnQubGFiZWwgPSBsaXN0KGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSksICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBBZGp1c3QgbGFiZWwgcGFyYW1ldGVycw0KICAgICAgICAgICAgICAgICAgICAgICBnZ3RoZW1lID0gZHRvcGxvdF90aGVtZSkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBnZ3Bsb3QyIHRoZW1lDQogICAgZG90cGxvdGNvcl9zY2FsZV9maWxsKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBGaXggY29sb3JzIHRvIHNpZ25pZiBmYWN0b3IgbGV2ZWxzIGV2ZW4gaWYgbWlzc2luZw0KICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMiwgY29sb3IgPSAibGlnaHRncmF5IikNCn0NCg0KICANCiN+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+fn4NCiMgRGVmaW5lIEZ1bmN0aW9uIGZvciBQcmUtUG9zdCBQbG90cywgdCBDaGFuZ2UgYW5kIEFOQ09WQSBQb3N0DQojfn5+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+DQojIyBGdW5jIHQgdGVzdCBzaSBib3hwbG90IHNpbXBsdQ0KZnVuY190X2JveCA8LSBmdW5jdGlvbihkZiwgaW5kLCBwcmVfdmFyLCBwb3N0X3ZhciwgdGVzdF9tZXRob2QgPSAidC50ZXN0Iil7DQogIGRmX21vZGlmIDwtDQogICAgZGYgJT4lDQogICAgc2VsZWN0KGluZCwgcHJlX3ZhciwgcG9zdF92YXIpICU+JSANCiAgICB0aWR5cjo6ZHJvcF9uYSgpICU+JQ0KICAgIGdhdGhlcihwcmVfdmFyLCBwb3N0X3Zhciwga2V5ID0gIkNvbmQiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JSANCiAgICBtdXRhdGVfYXQodmFycyhjKDEsIDIpKSwgZnVucyhhcy5mYWN0b3IpKSAlPiUgDQogICAgbXV0YXRlKENvbmQgPSBmYWN0b3IoQ29uZCwgbGV2ZWxzID0gYyhwcmVfdmFyLCBwb3N0X3ZhcikpKSANCiAgDQogIHN0YXRfY29tcCA8LSBnZ3B1YnI6OmNvbXBhcmVfbWVhbnModmFsdWUgfiBDb25kLCBkYXRhID0gZGZfbW9kaWYsIG1ldGhvZCA9IHRlc3RfbWV0aG9kLCBwYWlyZWQgPSBUUlVFKQ0KICANCiAgc3RhdF9jb21wMiA8LQ0KICAgIGRmX21vZGlmICU+JSANCiAgICBkbyh0aWR5KHQudGVzdCguJHZhbHVlIH4gLiRDb25kLA0KICAgICAgICAgICAgICAgICAgIHBhaXJlZCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgZGF0YT0uKSkpDQogIA0KICBwbG90IDwtIA0KICAgIGdncHVicjo6Z2dwYWlyZWQoZGZfbW9kaWYsIHggPSAiQ29uZCIsIHkgPSAidmFsdWUiLCBpZCA9IGluZCwgDQogICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJDb25kIiwgbGluZS5jb2xvciA9ICJncmF5IiwgbGluZS5zaXplID0gMC40LA0KICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZSA9IGMoIiMwMEFGQkIiLCAiI0ZDNEUwNyIpLCBsZWdlbmQgPSAibm9uZSIpICsNCiAgICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsICBjb2xvdXIgPSAiZGFya3JlZCIpICsNCiAgICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFLCBsYWJlbC54ID0gYXMubnVtZXJpYyhkZl9tb2RpZiRDb25kKS0wLjQsIGxhYmVsLnkgPSBtYXgoZGZfbW9kaWYkdmFsdWUpKzAuNSkgKyANCiAgICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFLCBsYWJlbCA9ICJwLnNpZ25pZiIsIGNvbXBhcmlzb25zID0gbGlzdChjKHByZV92YXIsIHBvc3RfdmFyKSkpDQogIA0KICBjYXQocGFzdGUwKCIjIyMjICIsIHByZV92YXIsICIgIiwgcG9zdF92YXIsICJcbiIsICJcbiIpKQ0KICBwcmludChzdGF0X2NvbXApDQogIHByaW50KHN0YXRfY29tcDIpDQogIHByaW50KHBsb3QpDQp9DQoNCg0KZnVuY19hbmNvdmFfbXVsdGlib3ggPC0gZnVuY3Rpb24oZGYsIGluZCwgcHJlX3Zhcl9jMSwgcG9zdF92YXJfYzEsIHByZV92YXJfYzIsIHBvc3RfdmFyX2MyKXsNCiAgDQogIGRpZmZfc2NvcmVfYzEgPC0gcGFzdGUwKHBvc3RfdmFyX2MxLCAiIC0gIiwgcHJlX3Zhcl9jMSkNCiAgZGlmZl9zY29yZV9jMiA8LSBwYXN0ZTAocG9zdF92YXJfYzIsICIgLSAiLCBwcmVfdmFyX2MyKQ0KICANCiAgIyMgUGxvdHMgYW5kIHAtdmFsdWVzIGZvciB0IHRlc3RzDQogIGRmX21vZGlmIDwtDQogICAgZGYgJT4lDQogICAgc2VsZWN0KGluZCwgcHJlX3Zhcl9jMSwgcG9zdF92YXJfYzEsIHByZV92YXJfYzIsIHBvc3RfdmFyX2MyKSAlPiUgDQogICAgdGlkeXI6OmRyb3BfbmEoKSAlPiUNCiAgICBnYXRoZXIocHJlX3Zhcl9jMSwgcG9zdF92YXJfYzEsIHByZV92YXJfYzIsIHBvc3RfdmFyX2MyLCBrZXkgPSAiQ29uZCIsIHZhbHVlID0gInZhbHVlIikgJT4lIA0KICAgIG11dGF0ZV9hdCh2YXJzKGMoMSwgMikpLCBmdW5zKGFzLmZhY3RvcikpICU+JSANCiAgICBtdXRhdGUoQ29uZCA9IGZhY3RvcihDb25kLCBsZXZlbHMgPSBjKHByZV92YXJfYzEsIHBvc3RfdmFyX2MxLCBwcmVfdmFyX2MyLCBwb3N0X3Zhcl9jMikpKSANCiAgDQogIHN0YXRfY29tcCA8LSBnZ3B1YnI6OmNvbXBhcmVfbWVhbnModmFsdWUgfiBDb25kLCBkYXRhID0gZGZfbW9kaWYsIG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFLCBwLmFkanVzdC5tZXRob2QgPSAiaG9sbSIpDQogIA0KICBwbG90IDwtDQogICAgZ2dwdWJyOjpnZ3BhaXJlZChkZl9tb2RpZiwgeCA9ICJDb25kIiwgeSA9ICJ2YWx1ZSIsIGlkID0gaW5kLCANCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIkNvbmQiLCBsaW5lLmNvbG9yID0gImdyYXkiLCBsaW5lLnNpemUgPSAwLjQsDQogICAgICAgICAgICAgICAgICAgICBwYWxldHRlID0gYygiIzAwQUZCQiIsICIjRkM0RTA3IiwgIiMwMEFGQkIiLCAiI0ZDNEUwNyIpLCBsZWdlbmQgPSAibm9uZSIpICsNCiAgICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLCAgY29sb3VyID0gImRhcmtyZWQiKSArDQogICAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gInQudGVzdCIsIHBhaXJlZCA9IFRSVUUsIGxhYmVsID0gInAuc2lnbmlmIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwueSA9IGMobWF4KGRmX21vZGlmJHZhbHVlKSArIDAuMSpJUVIoZGZfbW9kaWYkdmFsdWUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChkZl9tb2RpZiR2YWx1ZSkgKyAwLjEqSVFSKGRmX21vZGlmJHZhbHVlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXEobWF4KGRmX21vZGlmJHZhbHVlKSArIDAuMypJUVIoZGZfbW9kaWYkdmFsdWUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KGRmX21vZGlmJHZhbHVlKSArIDAuOSpJUVIoZGZfbW9kaWYkdmFsdWUpLCBsZW5ndGgub3V0ID0gNCkpLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvbnMgPSBsaXN0KGMocHJlX3Zhcl9jMSwgcG9zdF92YXJfYzEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKHByZV92YXJfYzIsIHBvc3RfdmFyX2MyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYyhwb3N0X3Zhcl9jMSwgcHJlX3Zhcl9jMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMocHJlX3Zhcl9jMSwgcHJlX3Zhcl9jMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMocG9zdF92YXJfYzEsIHBvc3RfdmFyX2MyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYyhwcmVfdmFyX2MxLCBwb3N0X3Zhcl9jMikpKQ0KICANCiAgIyMgRm9yIHR0ZXN0Q2hhbmdlIG9yIEFOQ09WQUNoYW5nZSAtIHdlIGRvIHR0ZXN0Q2hhbmdlIChQb3N0LVByZSkgaGVyZSwgYnV0IGl0IGlzbnQgdmVyeSBpbXBvcnRhbnQNCiAgZGZfbW9kaWYyIDwtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgZGYgJT4lDQogICAgc2VsZWN0KGluZCwgcHJlX3Zhcl9jMSwgcG9zdF92YXJfYzEsIHByZV92YXJfYzIsIHBvc3RfdmFyX2MyKSAlPiUNCiAgICB0aWR5cjo6ZHJvcF9uYSgpIA0KICBkZl9tb2RpZjJbZGlmZl9zY29yZV9jMV0gPC0gZGZfbW9kaWYyWywgcG9zdF92YXJfYzFdIC0gZGZfbW9kaWYyWywgcHJlX3Zhcl9jMV0NCiAgZGZfbW9kaWYyW2RpZmZfc2NvcmVfYzJdIDwtIGRmX21vZGlmMlssIHBvc3RfdmFyX2MyXSAtIGRmX21vZGlmMlssIHByZV92YXJfYzJdDQogIA0KICB0Q2hhbmdlIDwtIHQudGVzdChkZl9tb2RpZjJbLCBkaWZmX3Njb3JlX2MxXSwgZGZfbW9kaWYyWywgZGlmZl9zY29yZV9jMl0sIHBhaXJlZCA9IFRSVUUpDQogIA0KICAjIyBGb3IgZGVzY3JpcHRpdmVzIGJ5IDIgZmFjdG9ycyAoUHJlUG9zdCBhbmQgUG96TmVnKQ0KICBkZl9tb2RpZjMgPC0NCiAgICBkZiAlPiUNCiAgICBzZWxlY3QoaW5kLCBwcmVfdmFyX2MxLCBwb3N0X3Zhcl9jMSwgcHJlX3Zhcl9jMiwgcG9zdF92YXJfYzIpICU+JQ0KICAgIHRpZHlyOjpkcm9wX25hKCkgJT4lDQogICAgZ2F0aGVyKHByZV92YXJfYzEsIHBvc3RfdmFyX2MxLCBwcmVfdmFyX2MyLCBwb3N0X3Zhcl9jMiwga2V5ID0gIkNvbmQiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JQ0KICAgIG11dGF0ZShQcmVQb3N0ID0gY2FzZV93aGVuKHN0cmluZ3I6OnN0cl9kZXRlY3QoLiQiQ29uZCIsICJwcmV8UHJlIikgfiAiUHJlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KC4kIkNvbmQiLCAicG9zdHxQb3N0IikgfiAiUG9zdCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pLA0KICAgICAgICAgICBQb3pOZWcgPSBjYXNlX3doZW4oc3RyaW5ncjo6c3RyX2RldGVjdCguJCJDb25kIiwgInBvenxQb3oiKSB+ICJQb3oiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX2RldGVjdCguJCJDb25kIiwgIm5lZ3xOZWciKSB+ICJOZWciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pKSAlPiUNCiAgICBtdXRhdGUoUHJlUG9zdCA9IGFzLmZhY3RvcihQcmVQb3N0KSwNCiAgICAgICAgICAgUG96TmVnID0gYXMuZmFjdG9yKFBvek5lZykpDQogIA0KICAjIyBGb3IgQU5DT1ZBUG9zdCAtIHRoaXMgaXMgd2hhdCB3ZSB1c2UNCiAgZGZfbW9kaWY0IDwtDQogICAgZGZfbW9kaWYzICU+JQ0KICAgIHNlbGVjdCgtIkNvbmQiKSAlPiUNCiAgICBzcHJlYWQoIlByZVBvc3QiLCAidmFsdWUiKQ0KICANCiAgIyMgTW9kZWxzIChoZXJlIHdlIHVzZSBBTkNPVkFQb3N0KSAgICAjIGh0dHBzOi8vbS1jbGFyay5naXRodWIuaW8vZG9jcy9taXhlZE1vZGVscy9hbm92YW1peGVkLmh0bWwjaW50cm9kdWN0aW9uDQogIGZ1bGxfYW5jb3ZhUG9zdCA8LSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpcyBpcyBiZXR0ZXIgdGhhbiB1c2luZyBsbSgpIGFuZCBnbGh0KCkNCiAgICAgIGptdjo6YW5jb3ZhKA0KICAgICAgICBmb3JtdWxhID0gUG9zdCB+IFByZSArIFBvek5lZywNCiAgICAgICAgZGF0YSA9IGRmX21vZGlmNCwNCiAgICAgICAgaG9tbyA9IFRSVUUsDQogICAgICAgIHNzID0gIjMiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgIHBvc3RIb2MgPSB+IFBvek5lZywNCiAgICAgICAgcG9zdEhvY0NvcnIgPSBsaXN0KCJ0dWtleSIpLA0KICAgICAgICBlZmZlY3RTaXplID0gbGlzdCgiZXRhIiwgInBhcnRFdGEiKQ0KICAgICAgKQ0KICANCiAgICAgICMgbW9kX2FuY292YVBvc3QgPC0gbG0oUG9zdCB+IFByZSArIFBvek5lZywgZGF0YSA9IGRmX21vZGlmNCkgICAgICAgICAgICAjIHRoaXMgaXMgYSBDb3ZhcmlhdGUgU2Vjb25kIG1vZGVsDQogICAgICAjIG1vZF9hbmNvdmFQb3N0X3NzMyA8LSBjYXI6OkFub3ZhKG1vZF9hbmNvdmFQb3N0LCB0eXBlID0gIklJSSIpICAgICAgICAgIyBUeXBlIElJSSBzdW1zIG9mIHNxdWFyZXM7IHNlZSBBbmR5IEZpZWxkcyAyMDEyDQogICAgICAjIHBvc3RIb2NzIDwtIG11bHRjb21wOjpnbGh0KG1vZF9hbmNvdmFQb3N0LCBsaW5mY3QgPSBtdWx0Y29tcDo6bWNwKFBvek5lZyA9ICJUdWtleSIpKSAgIyBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBhZGp1c3RlZCBtZWFucywNCiAgICAgICMgc3VtX3Bvc3RIb2NzIDwtIHN1bW1hcnkocG9zdEhvY3MpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHVzZSBUdWtleSBvciBEdW5uZXR0P3MgcG9zdCBob2MgdGVzdHMNCiAgICAgICMgY29uZl9wb3N0SG9jcyA8LSBjb25maW50KHBvc3RIb2NzKQ0KICBzY2F0dGVyIDwtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQ2hlY2sgZm9yIGhvbW9nZW5laXR5IG9mIHJlZ3Jlc3Npb24gc2xvcGVzDQogICAgZ2dwbG90KGRmX21vZGlmNCwgYWVzKFByZSwgUG9zdCwgY29sb3VyID0gUG96TmVnKSkgKw0KICAgIGdlb21fcG9pbnQoYWVzKHNoYXBlID0gUG96TmVnKSwgc2l6ZSA9IDMpICsNCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBhZXMoZmlsbCA9IFBvek5lZyksIGFscGhhID0gMC4xKQ0KICAgIA0KICANCiAgIyMgT3RoZXIgTW9kZWxzIHRoYXQgd29yayBmb3IgdGhpcyBkYXRlDQogICMgbW9kX2FuY292YVBvc3QgPC0gbG0ocG9zdCB+IHByZSArIHRyZWF0KSAgICAgICMgZXhhY3RseSB0aGUgc2FtZSB3aXRoIGFvdihwb3N0IH4gcHJlICsgdHJlYXQpDQogICMgc3VtbWFyeShtb2RfYW5jb3ZhUG9zdCkNCiAgIyANCiAgIyBtb2RfYW5vdmFSTSA8LSBhb3Yoc2NvcmUgfiB0cmVhdCp0aW1lICsgRXJyb3IoaWQpLCBkZmxvbmcpDQogICMgc3VtbWFyeShtb2RfYW5vdmFSTSkNCiAgIyANCiAgIyBtb2RfbG1lIDwtIGxtZTQ6OmxtZXIoc2NvcmUgfiB0cmVhdCp0aW1lICsgKDF8aWQpLCBkYXRhPWRmbG9uZykNCiAgIyBhbm92YShsbWVNb2RlbCkNCiAgDQogICMjIE91dHB1dA0KICBwcmludChwbG90KQ0KICBjYXQocGFzdGUwKCIjIyMjICIsIHByZV92YXJfYzEsICIgIiwgcG9zdF92YXJfYzEsICIgIiwgcHJlX3Zhcl9jMiwgIiAiLCBwb3N0X3Zhcl9jMiwgIlxuIiwgIlxuIikpDQogIA0KICBjYXQoIiMjIyMgRGVzY3JpcHRpdmVzIikNCiAgcHN5Y2g6OmRlc2NyaWJlQnkoZGZfbW9kaWYzWywgInZhbHVlIl0sIGxpc3QoZGZfbW9kaWYzWywgIlByZVBvc3QiXSwgZGZfbW9kaWYzWywgIlBvek5lZyJdKSwgbWF0ID0gVFJVRSkgJT4lIA0KICAgIGFzLnRpYmJsZSgpICU+JQ0KICAgIHByaW50KCkNCiAgY2F0KCJcbiIpDQogIA0KICBwcmludChzdGF0X2NvbXApDQogIGNhdCgiXG4iKQ0KICANCiAgY2F0KCIjIyMjIHQgQ2hhbmdlIikNCiAgdGlkeSh0Q2hhbmdlKSAlPiUgcHJpbnQoKQ0KICBjYXQoIlxuIikNCiAgDQogIGNhdCgiIyMjIyBBTkNPVkEgUG9zdCIpDQogIGNhdCgiXG4iKQ0KICBjYXQoIiMjIyMjIEhvbW9nZW5laXR5IHRlc3QiKQ0KICBwcmludCh0aWJibGU6OmFzLnRpYmJsZShmdWxsX2FuY292YVBvc3QkYXNzdW1wJGhvbW8pKQ0KICBjYXQoIiMjIyMjIEFOQ09WQSBvdXRwdXQiKQ0KICBwcmludCh0aWJibGU6OmFzLnRpYmJsZShmdWxsX2FuY292YVBvc3QkbWFpbikpDQogICMgdGlkeShtb2RfYW5jb3ZhUG9zdCkgJT4lIA0KICAjICAgbXV0YXRlKHAuc2lnbmlmID0gc2FwcGx5KHAudmFsdWUsIGZ1bmN0aW9uKHgpIHN0YXJzX3NpZ25pZih4KSkpICU+JSANCiAgIyAgIHByaW50KCkNCiAgIyBjYXQoIlxuIikNCiAgY2F0KCIjIyMjIyBQb3N0IEhvYyIpDQogIHByaW50KHRpYmJsZTo6YXMudGliYmxlKGZ1bGxfYW5jb3ZhUG9zdCRwb3N0SG9jW1sxXV0pKQ0KICAjIHRpZHkoc3VtX3Bvc3RIb2NzKSAlPiUgDQogICMgICBtdXRhdGUocC5zaWduaWYgPSBzYXBwbHkocC52YWx1ZSwgZnVuY3Rpb24oeCkgc3RhcnNfc2lnbmlmKHgpKSkgJT4lIA0KICAjICAgcHJpbnQoKQ0KICBjYXQoIlxuIikNCiAgY2F0KCIjIyMjIyBIb21vZ2VuZWl0eSBvZiByZWdyZXNzaW9uIHNsb3BlcyIpDQogIHN1YmNodW5raWZ5KHBsb3Qoc2NhdHRlciksIDUsIDUpDQp9DQpgYGANCg0KDQojIERlc2NyaXB0aXZlcyAtIEdlbiBWYXJzdGENCg0KYGBge3IgZGVzY19nZW5fdmFyc3RhfQ0KZGVzY3JpYmUoRGF0YV9HZW5fbWVyZ2VkJFZhcnN0YSkNCnByb3AudGFibGUodGFibGUoRGF0YV9HZW5fbWVyZ2VkJEdlbikpDQoNCnQudGVzdChEYXRhX0dlbl9tZXJnZWQkVmFyc3RhIH4gRGF0YV9HZW5fbWVyZ2VkJEdlbikgJT4lDQogIHRpZHkoKQ0KICANCndpbGNveC50ZXN0KERhdGFfR2VuX21lcmdlZCRWYXJzdGEgfiBEYXRhX0dlbl9tZXJnZWQkR2VuKSAlPiUNCiAgdGlkeSgpDQoNCnBzeWNoOjpkZXNjcmliZUJ5KERhdGFfR2VuX21lcmdlZCRWYXJzdGEsIGdyb3VwID0gRGF0YV9HZW5fbWVyZ2VkJEdlbikNCmBgYA0KDQoNCg0KIyBBbmFseXNlcw0KDQojIyBDb3JyZWxhdGlvbnMgYmV0d2VlbiBEaWZmcmVuY2UgU2NvcmVzIHdpdGggb3RoZXIgdmFyaWFibGVzDQoNCmBgYHtyIERfY29yX290aGVyLCByZXN1bHRzPSdhc2lzJ30NCiMjIENvcnJlbGF0aW9ucyBiZXR3ZWVuIERpZmZyZW5jZSBTY29yZXMgd2l0aCBvdGhlciB2YXJpYWJsZXMNCkNvcnJlbGF0aW9uc19XaXRoX09uZShEYXRhWywtYygxOjcpXSwgdmFyaWFibGUgPSAiRF9PeF9Qb3oiLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4wNSkgICMgRF9ER19Qb3osIE5lb19DNCwgTmVvX0UzDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfT3hfTmVnIiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIG5pbWljDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfQ29ydF9Qb3oiLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4wNSkgIyBEX1NhbTFfUG96LCBEX1RydXN0VG90X1BveiwgU3RhaVMNCkNvcnJlbGF0aW9uc19XaXRoX09uZShEYXRhWywtYygxOjcpXSwgdmFyaWFibGUgPSAiRF9Db3J0X05lZyIsIGNvcnJlbGF0aW9uX2Fic190aHJlc2hvbGQgPSAwLjIsIHB2YWx1ZV90aHJlc2hvbGQgPSAwLjA1KSAgIyBuaW1pYw0KQ29ycmVsYXRpb25zX1dpdGhfT25lKERhdGFbLC1jKDE6NyldLCB2YXJpYWJsZSA9ICJEX1Zhc1NfUG96IiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIG5pbWljDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfVmFzU19OZWciLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4wNSkgICMgRF9UcnVzdFRvdF9OZWcNCkNvcnJlbGF0aW9uc19XaXRoX09uZShEYXRhWywtYygxOjcpXSwgdmFyaWFibGUgPSAiRF9WYXNCX1BveiIsIGNvcnJlbGF0aW9uX2Fic190aHJlc2hvbGQgPSAwLjIsIHB2YWx1ZV90aHJlc2hvbGQgPSAwLjA1KSAgIyBEX1NhbTFfUG96DQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfVmFzQl9OZWciLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4wNSkgICMgRF9TYW0xX05lZw0KQ29ycmVsYXRpb25zX1dpdGhfT25lKERhdGFbLC1jKDE6NyldLCB2YXJpYWJsZSA9ICJEX0lPU19Qb3oiLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4wNSkgICMgbmltaWMNCkNvcnJlbGF0aW9uc19XaXRoX09uZShEYXRhWywtYygxOjcpXSwgdmFyaWFibGUgPSAiRF9JT1NfTmVnIiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIG5pbWljDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfREdfUG96IiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIG5pbWljDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfREdfTmVnIiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIG5pbWljDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfVHJ1c3RNaW5fUG96IiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIG5pbWljDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfVHJ1c3RNaW5fTmVnIiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIG5pbWljDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfVHJ1c3RUb3RfUG96IiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIG5pbWljDQpDb3JyZWxhdGlvbnNfV2l0aF9PbmUoRGF0YVssLWMoMTo3KV0sIHZhcmlhYmxlID0gIkRfVHJ1c3RUb3RfTmVnIiwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICAjIERfVmFzU19OZWcNCmBgYA0KDQoNCjwhLS0gDQoNCiMjIFNpbXBsZSBiZWZvcmUtYWZ0ZXIgYW5hbHlzZXMgd2l0aCB0IHRlc3QNCg0KYGBge3IgdF90ZXN0LCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD03LCByZXN1bHRzPSdhc2lzJ30NCiMjIFNpbXBsZSBiZWZvcmUtYWZ0ZXIgYW5hbHlzZXMgd2l0aCB0IHRlc3QNCmZ1bmNfdF9ib3goRGF0YSwgIkluZGljYXRpdiIsICJPeF9wcmVfUG96IiwgIk94X3Bvc3RfUG96IikgICMgc2lnICANCmZ1bmNfdF9ib3goRGF0YSwgIkluZGljYXRpdiIsICJPeF9wcmVfTmVnIiwgIk94X3Bvc3RfTmVnIikgICMgc2lnDQpmdW5jX3RfYm94KERhdGEsICJJbmRpY2F0aXYiLCAiQ29ydF9wcmVfUG96IiwgIkNvcnRfcG9zdF9Qb3oiKSAgIyBudSAgDQpmdW5jX3RfYm94KERhdGEsICJJbmRpY2F0aXYiLCAiQ29ydF9wcmVfTmVnIiwgIkNvcnRfcG9zdF9OZWciKSAgIyBzaWcNCg0KZnVuY190X2JveChEYXRhLCAiSW5kaWNhdGl2IiwgIlZhc1NfcHJlUG96IiwgIlZhc1NfcG9zdFBveiIpICAjIHNpZyAgDQpmdW5jX3RfYm94KERhdGEsICJJbmRpY2F0aXYiLCAiVmFzU19wcmVOZWciLCAiVmFzU19wb3N0TmVnIikgICMgbnUNCmZ1bmNfdF9ib3goRGF0YSwgIkluZGljYXRpdiIsICJWYXNCX3ByZVBveiIsICJWYXNCX3Bvc3RQb3oiKSAgIyBzaWcgIA0KZnVuY190X2JveChEYXRhLCAiSW5kaWNhdGl2IiwgIlZhc0JfcHJlTmVnIiwgIlZhc0JfcG9zdE5lZyIpICAjIG51DQpmdW5jX3RfYm94KERhdGEsICJJbmRpY2F0aXYiLCAiU2FtMV9wcmVQb3oiLCAiU2FtMV9wb3N0UG96IikgICMgc2lnICANCmZ1bmNfdF9ib3goRGF0YSwgIkluZGljYXRpdiIsICJTYW0xX3ByZU5lZyIsICJTYW0xX3Bvc3ROZWciKSAgIyBudQ0KZnVuY190X2JveChEYXRhLCAiSW5kaWNhdGl2IiwgIlNhbTJfcHJlUG96IiwgIlNhbTJfcG9zdFBveiIpICAjIG51ICANCmZ1bmNfdF9ib3goRGF0YSwgIkluZGljYXRpdiIsICJTYW0yX3ByZU5lZyIsICJTYW0yX3Bvc3ROZWciKSAgIyBudQ0KZnVuY190X2JveChEYXRhLCAiSW5kaWNhdGl2IiwgIklPU19wcmVQb3oiLCAiSU9TX3Bvc3RQb3oiKSAgIyBzaWcgIA0KZnVuY190X2JveChEYXRhLCAiSW5kaWNhdGl2IiwgIklPU19wcmVOZWciLCAiSU9TX3Bvc3ROZWciKSAgIyBudQ0KDQpmdW5jX3RfYm94KERhdGEsICJJbmRpY2F0aXYiLCAiREdfcHJlUG96VG90IiwgIkRHX3Bvc3RQb3pUb3QiKSAgIyBudSAgDQpmdW5jX3RfYm94KERhdGEsICJJbmRpY2F0aXYiLCAiREdfcHJlTmVnVG90IiwgIkRHX3Bvc3ROZWdUb3QiKSAgIyBzaWcNCg0KZnVuY190X2JveChEYXRhLCAiSW5kaWNhdGl2IiwgIlRydXN0TWluUG96UHJlIiwgIlRydXN0TWluUG96UG9zdCIpICAjIG51ICANCmZ1bmNfdF9ib3goRGF0YSwgIkluZGljYXRpdiIsICJUcnVzdE1pbk5lZ1ByZSIsICJUcnVzdE1pbk5lZ1Bvc3QiKSAgIyBudQ0KZnVuY190X2JveChEYXRhLCAiSW5kaWNhdGl2IiwgIlRydXN0VG90UG96UHJlIiwgIlRydXN0VG90UG96UG9zdCIpICAjIG51ICANCmZ1bmNfdF9ib3goRGF0YSwgIkluZGljYXRpdiIsICJUcnVzdFRvdE5lZ1ByZSIsICJUcnVzdFRvdE5lZ1Bvc3QiKSAgIyBudQ0KYGBgDQoNCg0KIyMgdENoYW5jZSBhbmQgQU5DT1ZBUG9zdA0KDQpgYGB7ciB0X0NoYW5nZV9BTkNPVkFfUG9zdHMsIGZpZy53aWR0aD0xMSwgZmlnLmhlaWdodD0xMiwgcmVzdWx0cz0nYXNpcyd9DQojIyB0Q2hhbmNlIGFuZCBBTkNPVkFQb3N0IA0KZnVuY19hbmNvdmFfbXVsdGlib3goRGF0YSwgIkluZGljYXRpdiIsICJPeF9wcmVfUG96IiwgIk94X3Bvc3RfUG96IiwgIk94X3ByZV9OZWciLCAiT3hfcG9zdF9OZWciKQ0KZnVuY19hbmNvdmFfbXVsdGlib3goRGF0YSwgIkluZGljYXRpdiIsICJDb3J0X3ByZV9Qb3oiLCAiQ29ydF9wb3N0X1BveiIsICJDb3J0X3ByZV9OZWciLCAiQ29ydF9wb3N0X05lZyIpDQoNCmZ1bmNfYW5jb3ZhX211bHRpYm94KERhdGEsICJJbmRpY2F0aXYiLCAiVmFzU19wcmVQb3oiLCAiVmFzU19wb3N0UG96IiwgIlZhc1NfcHJlTmVnIiwgIlZhc1NfcG9zdE5lZyIpDQpmdW5jX2FuY292YV9tdWx0aWJveChEYXRhLCAiSW5kaWNhdGl2IiwgIlZhc0JfcHJlUG96IiwgIlZhc0JfcG9zdFBveiIsICJWYXNCX3ByZU5lZyIsICJWYXNCX3Bvc3ROZWciKQ0KZnVuY19hbmNvdmFfbXVsdGlib3goRGF0YSwgIkluZGljYXRpdiIsICJTYW0xX3ByZVBveiIsICJTYW0xX3Bvc3RQb3oiLCAiU2FtMV9wcmVOZWciLCAiU2FtMV9wb3N0TmVnIikNCmZ1bmNfYW5jb3ZhX211bHRpYm94KERhdGEsICJJbmRpY2F0aXYiLCAiU2FtMl9wcmVQb3oiLCAiU2FtMl9wb3N0UG96IiwgIlNhbTJfcHJlTmVnIiwgIlNhbTJfcG9zdE5lZyIpDQpmdW5jX2FuY292YV9tdWx0aWJveChEYXRhLCAiSW5kaWNhdGl2IiwgIklPU19wcmVQb3oiLCAiSU9TX3Bvc3RQb3oiLCAiSU9TX3ByZU5lZyIsICJJT1NfcG9zdE5lZyIpIA0KDQpmdW5jX2FuY292YV9tdWx0aWJveChEYXRhLCAiSW5kaWNhdGl2IiwgIkRHX3ByZVBvelRvdCIsICJER19wb3N0UG96VG90IiwgIkRHX3ByZU5lZ1RvdCIsICJER19wb3N0TmVnVG90IikgDQoNCmZ1bmNfYW5jb3ZhX211bHRpYm94KERhdGEsICJJbmRpY2F0aXYiLCAiVHJ1c3RNaW5Qb3pQcmUiLCAiVHJ1c3RNaW5Qb3pQb3N0IiwgIlRydXN0TWluTmVnUHJlIiwgIlRydXN0TWluTmVnUG9zdCIpIA0KZnVuY19hbmNvdmFfbXVsdGlib3goRGF0YSwgIkluZGljYXRpdiIsICJUcnVzdFRvdFBvelByZSIsICJUcnVzdFRvdFBvelBvc3QiLCAiVHJ1c3RUb3ROZWdQcmUiLCAiVHJ1c3RUb3ROZWdQb3N0IikgDQpgYGANCg0KDQotLT4gDQoNCg0KIyMgU2ltcGxlIGJlZm9yZS1hZnRlciBhbmFseXNlcyB3aXRoIHQgdGVzdCBieSBHZW5kZXINCg0KYGBge3IgdF90ZXN0X2dlbiwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NywgcmVzdWx0cz0nYXNpcyd9DQojIEZlbWFsZXMNCmNhdCgiIyMjIEZlbWFsZXMiKQ0KIyBmdW5jX3RfYm94KERhdGFfZmVtLCAiSUQiLCAiT3hfcHJlX1BveiIsICJPeF9wb3N0X1BveiIsIHRlc3RfbWV0aG9kID0gIndpbGNveC50ZXN0IikgICAgICMgbnMgDQpmdW5jX3RfYm94KERhdGFfZmVtLCAiSUQiLCAiT3hfcHJlX1BveiIsICJPeF9wb3N0X1BveiIpICAjIG5zDQpmdW5jX3RfYm94KERhdGFfZmVtLCAiSUQiLCAiT3hfcHJlX05lZyIsICJPeF9wb3N0X05lZyIpICAgICAjIHNpZw0KIyBmdW5jX3RfYm94KERhdGFfZmVtLCAiSUQiLCAiQ29ydF9wcmVfUG96IiwgIkNvcnRfcG9zdF9Qb3oiKSAgIyBucyAgDQojIGZ1bmNfdF9ib3goRGF0YV9mZW0sICJJRCIsICJDb3J0X3ByZV9OZWciLCAiQ29ydF9wb3N0X05lZyIpICAjIHNpZw0KDQpmdW5jX3RfYm94KERhdGFfZmVtLCAiSUQiLCAiVmFzU19wcmVQb3oiLCAiVmFzU19wb3N0UG96IikgICMgc2lnICANCmZ1bmNfdF9ib3goRGF0YV9mZW0sICJJRCIsICJWYXNTX3ByZU5lZyIsICJWYXNTX3Bvc3ROZWciKSAgIyBucw0KZnVuY190X2JveChEYXRhX2ZlbSwgIklEIiwgIlZhc0JfcHJlUG96IiwgIlZhc0JfcG9zdFBveiIpICAjIHNpZyAgDQpmdW5jX3RfYm94KERhdGFfZmVtLCAiSUQiLCAiVmFzQl9wcmVOZWciLCAiVmFzQl9wb3N0TmVnIikgICMgbnMNCiMgZnVuY190X2JveChEYXRhX2ZlbSwgIklEIiwgIlNhbTFfcHJlUG96IiwgIlNhbTFfcG9zdFBveiIpICAjIHNpZyAgDQojIGZ1bmNfdF9ib3goRGF0YV9mZW0sICJJRCIsICJTYW0xX3ByZU5lZyIsICJTYW0xX3Bvc3ROZWciKSAgIyBudQ0KIyBmdW5jX3RfYm94KERhdGFfZmVtLCAiSUQiLCAiU2FtMl9wcmVQb3oiLCAiU2FtMl9wb3N0UG96IikgICMgbnUgIA0KIyBmdW5jX3RfYm94KERhdGFfZmVtLCAiSUQiLCAiU2FtMl9wcmVOZWciLCAiU2FtMl9wb3N0TmVnIikgICMgbnUNCmZ1bmNfdF9ib3goRGF0YV9mZW0sICJJRCIsICJJT1NfcHJlUG96IiwgIklPU19wb3N0UG96IikgICMgc2lnICANCmZ1bmNfdF9ib3goRGF0YV9mZW0sICJJRCIsICJJT1NfcHJlTmVnIiwgIklPU19wb3N0TmVnIikgICMgbnMNCg0KZnVuY190X2JveChEYXRhX2ZlbSwgIklEIiwgIkRHX3ByZVBvelRvdCIsICJER19wb3N0UG96VG90IikgICMgbnMgIA0KZnVuY190X2JveChEYXRhX2ZlbSwgIklEIiwgIkRHX3ByZU5lZ1RvdCIsICJER19wb3N0TmVnVG90IikgICMgbnMNCg0KZnVuY190X2JveChEYXRhX2ZlbSwgIklEIiwgIlRydXN0TWluUG96UHJlIiwgIlRydXN0TWluUG96UG9zdCIpICAjIG5zICANCmZ1bmNfdF9ib3goRGF0YV9mZW0sICJJRCIsICJUcnVzdE1pbk5lZ1ByZSIsICJUcnVzdE1pbk5lZ1Bvc3QiKSAgIyBucw0KZnVuY190X2JveChEYXRhX2ZlbSwgIklEIiwgIlRydXN0VG90UG96UHJlIiwgIlRydXN0VG90UG96UG9zdCIpICAjIG5zICANCmZ1bmNfdF9ib3goRGF0YV9mZW0sICJJRCIsICJUcnVzdFRvdE5lZ1ByZSIsICJUcnVzdFRvdE5lZ1Bvc3QiKSAgIyBucw0KYGBgDQoNCg0KPCEtLSANCg0KIyMgdENoYW5jZSBhbmQgQU5DT1ZBUG9zdCBieSBHZW5kZXINCg0KYGBge3IgdF9DaGFuZ2VfQU5DT1ZBX1Bvc3RzX2dlbiwgZmlnLndpZHRoPTExLCBmaWcuaGVpZ2h0PTEyLCByZXN1bHRzPSdhc2lzJ30NCiMjIHRDaGFuY2UgYW5kIEFOQ09WQVBvc3QgDQpmdW5jX2FuY292YV9tdWx0aWJveChEYXRhLCAiSW5kaWNhdGl2IiwgIk94X3ByZV9Qb3oiLCAiT3hfcG9zdF9Qb3oiLCAiT3hfcHJlX05lZyIsICJPeF9wb3N0X05lZyIpDQpmdW5jX2FuY292YV9tdWx0aWJveChEYXRhLCAiSW5kaWNhdGl2IiwgIkNvcnRfcHJlX1BveiIsICJDb3J0X3Bvc3RfUG96IiwgIkNvcnRfcHJlX05lZyIsICJDb3J0X3Bvc3RfTmVnIikNCg0KZnVuY19hbmNvdmFfbXVsdGlib3goRGF0YSwgIkluZGljYXRpdiIsICJWYXNTX3ByZVBveiIsICJWYXNTX3Bvc3RQb3oiLCAiVmFzU19wcmVOZWciLCAiVmFzU19wb3N0TmVnIikNCmZ1bmNfYW5jb3ZhX211bHRpYm94KERhdGEsICJJbmRpY2F0aXYiLCAiVmFzQl9wcmVQb3oiLCAiVmFzQl9wb3N0UG96IiwgIlZhc0JfcHJlTmVnIiwgIlZhc0JfcG9zdE5lZyIpDQpmdW5jX2FuY292YV9tdWx0aWJveChEYXRhLCAiSW5kaWNhdGl2IiwgIlNhbTFfcHJlUG96IiwgIlNhbTFfcG9zdFBveiIsICJTYW0xX3ByZU5lZyIsICJTYW0xX3Bvc3ROZWciKQ0KZnVuY19hbmNvdmFfbXVsdGlib3goRGF0YSwgIkluZGljYXRpdiIsICJTYW0yX3ByZVBveiIsICJTYW0yX3Bvc3RQb3oiLCAiU2FtMl9wcmVOZWciLCAiU2FtMl9wb3N0TmVnIikNCmZ1bmNfYW5jb3ZhX211bHRpYm94KERhdGEsICJJbmRpY2F0aXYiLCAiSU9TX3ByZVBveiIsICJJT1NfcG9zdFBveiIsICJJT1NfcHJlTmVnIiwgIklPU19wb3N0TmVnIikgDQoNCmZ1bmNfYW5jb3ZhX211bHRpYm94KERhdGEsICJJbmRpY2F0aXYiLCAiREdfcHJlUG96VG90IiwgIkRHX3Bvc3RQb3pUb3QiLCAiREdfcHJlTmVnVG90IiwgIkRHX3Bvc3ROZWdUb3QiKSANCg0KZnVuY19hbmNvdmFfbXVsdGlib3goRGF0YSwgIkluZGljYXRpdiIsICJUcnVzdE1pblBvelByZSIsICJUcnVzdE1pblBvelBvc3QiLCAiVHJ1c3RNaW5OZWdQcmUiLCAiVHJ1c3RNaW5OZWdQb3N0IikgDQpmdW5jX2FuY292YV9tdWx0aWJveChEYXRhLCAiSW5kaWNhdGl2IiwgIlRydXN0VG90UG96UHJlIiwgIlRydXN0VG90UG96UG9zdCIsICJUcnVzdFRvdE5lZ1ByZSIsICJUcnVzdFRvdE5lZ1Bvc3QiKSANCmBgYA0KDQoNCi0tPg0KDQoNCg0KPCEtLQ0KDQojIyBDb3JyZWxhdGlvbnMgd2l0aCBPeHkNCg0KYGBge3IgY29yX094LCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD03LCByZXN1bHRzPSdhc2lzJ30NCiMjIE1pbmluZyBDb3JyZWxhdGlvbnMgd2l0aCBPeHkNCmRmX094eUFsbF9jb3IgPC0NCiAgR2V0X1RvcF9SZWxhdGlvbnNoaXBzKERhdGFbLC1jKDE6NyldLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4wNSkgJT4lDQogICAgZHBseXI6OmFzX3RpYmJsZSgpICU+JQ0KICAgIGRwbHlyOjpmaWx0ZXJfYWxsKGFueV92YXJzKGdyZXBsKCJPeCIsIC4pKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG9ubHkgT3h5LCBidXQgYm90aCBQcmUgYW5kIFBvc3QgT3h5DQoNCmRmX094eUFsbF9jb3IgJT4lICAgICAgICAgICAgICANCiAgICBwcmludChuID0gSW5mKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmRmX094eUFsbF9jb3IgJT4lDQogIGZ1bmNfZG90cGxvdF9jb3IoKQ0KIA0KIyBDb3JyZWxhdGlvbnMgb25seSBvbiBQcmUgbWVhc3VyZXMgd2l0aCBPeHkgLS0gbm90aGluZw0KZGZfT3h5UHJlX2NvciA8LSANCiAgR2V0X1RvcF9SZWxhdGlvbnNoaXBzKERhdGFbLC1jKDE6NyldLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4xKSAlPiUNCiAgICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lDQogICAgZmlsdGVyX2F0KHZhcnMoZmVhdHVyZV8xLCBmZWF0dXJlXzIpLCBhbGxfdmFycyhncmVwbCgicHJlfFByZSIsIC4pKSkgJT4lDQogICAgZHBseXI6OmZpbHRlcl9hbGwoYW55X3ZhcnMoZ3JlcGwoIk94IiwgLikpKSANCg0KZGZfT3h5UHJlX2NvciAlPiUNCiAgcHJpbnQobiA9IEluZikNCg0KIyBDb3JyZWxhdGlvbnMgb25seSBvbiBQb3N0IG1lYXN1cmVzIHdpdGggT3h5DQpkZl9PeHlQb3N0X2NvciA8LQ0KICBHZXRfVG9wX1JlbGF0aW9uc2hpcHMoRGF0YVssLWMoMTo3KV0sIGNvcnJlbGF0aW9uX2Fic190aHJlc2hvbGQgPSAwLjIsIHB2YWx1ZV90aHJlc2hvbGQgPSAwLjEpICU+JQ0KICAgIGRwbHlyOjphc190aWJibGUoKSAlPiUNCiAgICBmaWx0ZXJfYXQodmFycyhmZWF0dXJlXzEsIGZlYXR1cmVfMiksIGFsbF92YXJzKGdyZXBsKCJwb3N0fFBvc3QiLCAuKSkpICU+JQ0KICAgIGRwbHlyOjpmaWx0ZXJfYWxsKGFueV92YXJzKGdyZXBsKCJPeCIsIC4pKSkgDQoNCmRmX094eVBvc3RfY29yICU+JQ0KICAgIHByaW50KG4gPSBJbmYpDQpkZl9PeHlQb3N0X2NvciAlPiUgDQogIGZ1bmNfZG90cGxvdF9jb3IoKQ0KYGBgDQoNCg0KIyMgQ29ycmVsYXRpb25zIHdpdGggU3Rlc3MNCg0KYGBge3IgY29yX1Zhc1MsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTcsIHJlc3VsdHM9J2FzaXMnfQ0KIyMgTWluaW5nIENvcnJlbGF0aW9ucyB3aXRoIFZhc1MNCmRmX1Zhc1NBbGxfY29yIDwtDQogIEdldF9Ub3BfUmVsYXRpb25zaGlwcyhEYXRhWywtYygxOjcpXSwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICU+JQ0KICAgIGRwbHlyOjphc190aWJibGUoKSAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyX2FsbChhbnlfdmFycyhncmVwbCgiVmFzUyIsIC4pKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG9ubHkgVmFzUywgYnV0IGJvdGggUHJlIGFuZCBQb3N0IFZhc1MNCg0KZGZfVmFzU0FsbF9jb3IgJT4lICAgICAgICAgICAgICANCiAgICBwcmludChuID0gSW5mKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KIyBDb3JyZWxhdGlvbnMgb25seSBvbiBQcmUgbWVhc3VyZXMgd2l0aCBWYXNTDQpkZl9WYXNTUHJlX2NvciA8LSANCiAgR2V0X1RvcF9SZWxhdGlvbnNoaXBzKERhdGFbLC1jKDE6NyldLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4xKSAlPiUNCiAgICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lDQogICAgZmlsdGVyX2F0KHZhcnMoZmVhdHVyZV8xLCBmZWF0dXJlXzIpLCBhbGxfdmFycyhncmVwbCgicHJlfFByZSIsIC4pKSkgJT4lDQogICAgZHBseXI6OmZpbHRlcl9hbGwoYW55X3ZhcnMoZ3JlcGwoIlZhc1MiLCAuKSkpIA0KDQpkZl9WYXNTUHJlX2NvciAlPiUNCiAgcHJpbnQobiA9IEluZikNCmRmX1Zhc1NQcmVfY29yICU+JSANCiAgZnVuY19kb3RwbG90X2NvcigpDQoNCiMgQ29ycmVsYXRpb25zIG9ubHkgb24gUG9zdCBtZWFzdXJlcyB3aXRoIFZhc1MNCmRmX1Zhc1NQb3N0X2NvciA8LQ0KICBHZXRfVG9wX1JlbGF0aW9uc2hpcHMoRGF0YVssLWMoMTo3KV0sIGNvcnJlbGF0aW9uX2Fic190aHJlc2hvbGQgPSAwLjIsIHB2YWx1ZV90aHJlc2hvbGQgPSAwLjEpICU+JQ0KICAgIGRwbHlyOjphc190aWJibGUoKSAlPiUNCiAgICBmaWx0ZXJfYXQodmFycyhmZWF0dXJlXzEsIGZlYXR1cmVfMiksIGFsbF92YXJzKGdyZXBsKCJwb3N0fFBvc3QiLCAuKSkpICU+JQ0KICAgIGRwbHlyOjpmaWx0ZXJfYWxsKGFueV92YXJzKGdyZXBsKCJWYXNTIiwgLikpKSANCg0KZGZfVmFzU1Bvc3RfY29yICU+JQ0KICAgIHByaW50KG4gPSBJbmYpDQpkZl9WYXNTUG9zdF9jb3IgJT4lIA0KICBmdW5jX2RvdHBsb3RfY29yKCkNCmBgYA0KDQoNCiMjIENvcnJlbGF0aW9ucyB3aXRoIFdlbGwgQmVpbmcNCg0KYGBge3IgY29yX1Zhc0IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTcsIHJlc3VsdHM9J2FzaXMnfQ0KIyMgTWluaW5nIENvcnJlbGF0aW9ucyB3aXRoIFZhc0INCmRmX1Zhc0JBbGxfY29yIDwtDQogIEdldF9Ub3BfUmVsYXRpb25zaGlwcyhEYXRhWywtYygxOjcpXSwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICU+JQ0KICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lDQogIGRwbHlyOjpmaWx0ZXJfYWxsKGFueV92YXJzKGdyZXBsKCJWYXNCIiwgLikpKSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgb25seSBWYXNCLCBidXQgYm90aCBQcmUgYW5kIFBvc3QgVmFzQg0KDQpkZl9WYXNCQWxsX2NvciAlPiUgICAgICAgICAgICAgIA0KICBwcmludChuID0gSW5mKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KIyBDb3JyZWxhdGlvbnMgb25seSBvbiBQcmUgbWVhc3VyZXMgd2l0aCBWYXNCDQpkZl9WYXNCUHJlX2NvciA8LSANCiAgR2V0X1RvcF9SZWxhdGlvbnNoaXBzKERhdGFbLC1jKDE6NyldLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4xKSAlPiUNCiAgZHBseXI6OmFzX3RpYmJsZSgpICU+JQ0KICBmaWx0ZXJfYXQodmFycyhmZWF0dXJlXzEsIGZlYXR1cmVfMiksIGFsbF92YXJzKGdyZXBsKCJwcmV8UHJlIiwgLikpKSAlPiUNCiAgZHBseXI6OmZpbHRlcl9hbGwoYW55X3ZhcnMoZ3JlcGwoIlZhc0IiLCAuKSkpIA0KDQpkZl9WYXNCUHJlX2NvciAlPiUNCiAgcHJpbnQobiA9IEluZikNCmRmX1Zhc0JQcmVfY29yICU+JQ0KICBmdW5jX2RvdHBsb3RfY29yKCkNCg0KIyBDb3JyZWxhdGlvbnMgb25seSBvbiBQb3N0IG1lYXN1cmVzIHdpdGggVmFzQg0KZGZfVmFzQlBvc3RfY29yIDwtDQogIEdldF9Ub3BfUmVsYXRpb25zaGlwcyhEYXRhWywtYygxOjcpXSwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMSkgJT4lDQogIGRwbHlyOjphc190aWJibGUoKSAlPiUNCiAgZmlsdGVyX2F0KHZhcnMoZmVhdHVyZV8xLCBmZWF0dXJlXzIpLCBhbGxfdmFycyhncmVwbCgicG9zdHxQb3N0IiwgLikpKSAlPiUNCiAgZHBseXI6OmZpbHRlcl9hbGwoYW55X3ZhcnMoZ3JlcGwoIlZhc0IiLCAuKSkpIA0KDQpkZl9WYXNCUG9zdF9jb3IgJT4lDQogIHByaW50KG4gPSBJbmYpDQpkZl9WYXNCUG9zdF9jb3IgJT4lIA0KICBmdW5jX2RvdHBsb3RfY29yKCkNCmBgYA0KDQoNCiMjIENvcnJlbGF0aW9ucyB3aXRoIElPUyANCg0KYGBge3IgY29yX0lPUywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NywgcmVzdWx0cz0nYXNpcyd9DQojIyBNaW5pbmcgQ29ycmVsYXRpb25zIHdpdGggSU9TDQpkZl9JT1NBbGxfY29yIDwtDQogIEdldF9Ub3BfUmVsYXRpb25zaGlwcyhEYXRhWywtYygxOjcpXSwgY29ycmVsYXRpb25fYWJzX3RocmVzaG9sZCA9IDAuMiwgcHZhbHVlX3RocmVzaG9sZCA9IDAuMDUpICU+JQ0KICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lDQogIGRwbHlyOjpmaWx0ZXJfYWxsKGFueV92YXJzKGdyZXBsKCJJT1MiLCAuKSkpICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBvbmx5IElPUywgYnV0IGJvdGggUHJlIGFuZCBQb3N0IElPUw0KDQpkZl9JT1NBbGxfY29yICU+JSAgICAgICAgICAgICAgDQogIHByaW50KG4gPSBJbmYpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQojIENvcnJlbGF0aW9ucyBvbmx5IG9uIFByZSBtZWFzdXJlcyB3aXRoIElPUw0KZGZfSU9TUHJlX2NvciA8LSANCiAgR2V0X1RvcF9SZWxhdGlvbnNoaXBzKERhdGFbLC1jKDE6NyldLCBjb3JyZWxhdGlvbl9hYnNfdGhyZXNob2xkID0gMC4yLCBwdmFsdWVfdGhyZXNob2xkID0gMC4xKSAlPiUNCiAgZHBseXI6OmFzX3RpYmJsZSgpICU+JQ0KICBmaWx0ZXJfYXQodmFycyhmZWF0dXJlXzEsIGZlYXR1cmVfMiksIGFsbF92YXJzKGdyZXBsKCJwcmV8UHJlIiwgLikpKSAlPiUNCiAgZHBseXI6OmZpbHRlcl9hbGwoYW55X3ZhcnMoZ3JlcGwoIklPUyIsIC4pKSkgDQoNCmRmX0lPU1ByZV9jb3IgJT4lDQogIHByaW50KG4gPSBJbmYpDQpkZl9JT1NQcmVfY29yICU+JQ0KICBmdW5jX2RvdHBsb3RfY29yKCkNCg0KIyBDb3JyZWxhdGlvbnMgb25seSBvbiBQb3N0IG1lYXN1cmVzIHdpdGggSU9TDQpkZl9JT1NQb3N0X2NvciA8LQ0KICBHZXRfVG9wX1JlbGF0aW9uc2hpcHMoRGF0YVssLWMoMTo3KV0sIGNvcnJlbGF0aW9uX2Fic190aHJlc2hvbGQgPSAwLjIsIHB2YWx1ZV90aHJlc2hvbGQgPSAwLjEpICU+JQ0KICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lDQogIGZpbHRlcl9hdCh2YXJzKGZlYXR1cmVfMSwgZmVhdHVyZV8yKSwgYWxsX3ZhcnMoZ3JlcGwoInBvc3R8UG9zdCIsIC4pKSkgJT4lDQogIGRwbHlyOjpmaWx0ZXJfYWxsKGFueV92YXJzKGdyZXBsKCJJT1MiLCAuKSkpIA0KDQpkZl9JT1NQb3N0X2NvciAlPiUNCiAgcHJpbnQobiA9IEluZikNCmRmX0lPU1Bvc3RfY29yICU+JSANCiAgZnVuY19kb3RwbG90X2NvcigpDQpgYGANCg0KDQoNCi0tPg0KDQoNCjxicj4NCg0KDQoNCjwhLS0gU2Vzc2lvbiBJbmZvIGFuZCBMaWNlbnNlIC0tPg0KDQo8YnI+DQoNCiMgU2Vzc2lvbiBJbmZvDQpgYGB7ciBzZXNzaW9uX2luZm8sIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9ICdtYXJrdXAnfQ0Kc2Vzc2lvbkluZm8oKSAgICANCmBgYA0KDQo8IS0tIEZvb3RlciAtLT4NCiZuYnNwOw0KPGhyIC8+DQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+QSB3b3JrIGJ5IDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9DbGF1ZGl1UGFwYXN0ZXJpLyI+Q2xhdWRpdSBQYXBhc3Rlcmk8L2E+PC9wPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxzcGFuIHN0eWxlPSJjb2xvcjogIzgwODA4MDsiPjxlbT5jbGF1ZGl1LnBhcGFzdGVyaUBnbWFpbC5jb208L2VtPjwvc3Bhbj48L3A+DQombmJzcDsNCg==