Define functions
## Define function that recodes to numeric, but watches out to coercion to not introduce NAs
colstonumeric <- function(df){
tryCatch({
df_num <- as.data.frame(
lapply(df,
function(x) { as.numeric(as.character(x))}))
},warning = function(stop_on_warning) {
message("Stoped the execution of numeric conversion: ", conditionMessage(stop_on_warning))
})
}
##
## Define function that reverse codes items
ReverseCode <- function(df, tonumeric = FALSE, min = NULL, max = NULL) {
if(tonumeric) df <- colstonumeric(df)
df <- (max + min) - df
}
##
## Define function that scores only rows with less than 10% NAs (returns NA if all or above threshold percentage of rows are NA); can reverse code if vector of column indexes and min, max are provided.
ScoreLikert <- function(df, napercent = .1, tonumeric = FALSE, reversecols = NULL, min = NULL, max = NULL) {
reverse_list <- list(reversecols = reversecols, min = min, max = max)
reverse_check <- !sapply(reverse_list, is.null)
# Recode to numeric, but watch out to coercion to not introduce NAs
colstonumeric <- function(df){
tryCatch({
df_num <- as.data.frame(
lapply(df,
function(x) { as.numeric(as.character(x))}))
},warning = function(stop_on_warning) {
message("Stoped the execution of numeric conversion: ", conditionMessage(stop_on_warning))
})
}
if(tonumeric) df <- colstonumeric(df)
if(all(reverse_check)){
df[ ,reversecols] <- (max + min) - df[ ,reversecols]
}else if(any(reverse_check)){
stop("Insuficient info for reversing. Please provide: ", paste(names(reverse_list)[!reverse_check], collapse = ", "))
}
ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
NA,
rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0)
)
}
##
## Func t test si boxplot simplu
func_t_box <- function(df, ind, pre_var, post_var){
vars <- c(ind, pre_var, post_var) # to avoid new tidyverse error of ambiguity due to external vectos
df_modif <-
df %>%
dplyr::select(tidyselect::all_of(vars)) %>%
tidyr::drop_na() %>%
gather(tidyselect::all_of(pre_var), tidyselect::all_of(post_var), key = "Cond", value = "value") %>%
mutate_at(vars(c(1, 2)), as.factor) %>%
mutate(Cond = factor(Cond, levels = c(pre_var, post_var)))
stat_comp <- ggpubr::compare_means(value ~ Cond, data = df_modif, method = "t.test", 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)
}
# library(tidyverse)
# library(ggpubr)
# library(rstatix)
# library(broom)
# library(emmeans)
# library(rlang)
# Function ANCOVAPost
# Takes Long Data
ANCOVAPost_func <-
function(data, id_var,
time_var, pre_label, post_label,
value_var = scores, cond_var,
assum_check = TRUE, posthoc = TRUE,
p_adjust_method = "bonferroni"){
id_var_enq <- rlang::enquo(id_var)
id_var_name <- rlang::as_name(id_var_enq)
time_var_enq <- rlang::enquo(time_var)
time_var_name <- rlang::as_name(time_var_enq)
pre_var_enq <- rlang::enquo(pre_label)
pre_var_name <- rlang::as_name(pre_var_enq)
post_var_enq <- rlang::enquo(post_label)
post_var_name <- rlang::as_name(post_var_enq)
cond_var_enq <- rlang::enquo(cond_var)
cond_var_name <- rlang::as_name(cond_var_enq)
value_var_enq <- rlang::enquo(value_var)
value_var_name <- rlang::as_name(value_var_enq)
data_wider <-
data %>%
dplyr::select(!!id_var_enq, !!time_var_enq, !!cond_var_enq, !!value_var_enq) %>%
spread(key = time_var_name, value = value_var_name) # %>% # if need to compute change score statistics go from here
# mutate(difference = !!post_var_enq - !!pre_var_enq)
# Assumptions
if(assum_check){
cat("\n Linearity assumptionLinearity assumption (linear relationship between pre-test and post-test for each group) \n")
# Create a scatter plot between the covariate (i.e., pretest) and the outcome variable (i.e., posttest)
scatter_lin <-
ggscatter(data_wider, x = pre_var_name, y = post_var_name, color = cond_var_name,
add = "reg.line", title = "Linearity assumption") +
stat_regline_equation(aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~~"), color = !!cond_var_enq))
cat("\n Homogeneity of regression slopes (interaction term is n.s.) \n")
data_wider %>%
anova_test(as.formula(paste0(post_var_name, " ~ ", cond_var_name, " * ", pre_var_name))) %>%
print()
cat("\n Normality of residuals (Model diagnostics & Shapiro Wilk) \n")
# Fit the model, the covariate goes first
model <-
lm(as.formula(paste0(post_var_name, " ~ ", cond_var_name, " + ", pre_var_name)),
data = data_wider)
cat("\n Inspect the model diagnostic metrics \n")
model.metrics <-
augment(model) %>%
dplyr::select(-.hat, -.sigma, -.fitted, -.se.fit) %>% # Remove details
print()
cat("\n Normality of residuals (Shapiro Wilk p>.05) \n")
shapiro_test(model.metrics$.resid) %>%
print()
cat("\n Homogeneity of variances (Levene’s test p>.05) \n")
model.metrics %>%
levene_test(as.formula(paste0(".resid", " ~ ", cond_var_name)) ) %>%
print()
cat("\n Outliers (needs to be 0) \n")
model.metrics %>%
filter(abs(.std.resid) > 3) %>%
as.data.frame() %>%
print()
}
cat("\n ANCOVAPost \n")
res_ancova <-
data_wider %>%
anova_test(as.formula(paste0(post_var_name, " ~ ", pre_var_name, " + ", cond_var_name))) # the covariate needs to be first term
get_anova_table(res_ancova) %>% print()
cat("\n Pairwise comparisons \n")
pwc <-
data_wider %>%
emmeans_test(as.formula(paste0(post_var_name, " ~ ", cond_var_name)),
covariate = !!pre_var_enq,
p.adjust.method = p_adjust_method)
pwc %>% print()
cat("\n Display the adjusted means of each group, also called as the estimated marginal means (emmeans) \n")
get_emmeans(pwc) %>% print()
# Visualization: line plots with p-values
pwc <-
pwc %>%
add_xy_position(x = cond_var_name, fun = "mean_se")
line_plot <-
ggline(get_emmeans(pwc), x = cond_var_name, y = "emmean") +
geom_errorbar(aes(ymin = conf.low, ymax = conf.high), width = 0.2) +
stat_pvalue_manual(pwc, hide.ns = TRUE, tip.length = FALSE) +
labs(subtitle = get_test_label(res_ancova, detailed = TRUE),
caption = get_pwc_label(pwc))
if(assum_check){
list(scatter_lin, line_plot)
}else{
line_plot
}
}
# ex.
# ANCOVAPost_func(new_anxiety, time_var = time, pre_label = pretest, post_label = posttest,
# value_var = scores, cond_var = group, assum_check = TRUE, p_adjust_method = "bonferroni")
# library(tidyverse)
# library(ggpubr)
# library(rstatix)
# library(rlang)
# Define Function for Mixed Anova
tw_mixedANOVA_func <-
function(data, id_var, cond_var, time_var, value_var,
assum_check = TRUE, posthoc_sig_interac = FALSE, posthoc_ns_interac = FALSE,
p_adjust_method = "bonferroni"){
# input dataframe needs to have columns names diffrent from "variable" and "value" because it collides with rstatix::shapiro_test
id_var_enq <- rlang::enquo(id_var)
cond_var_enq <- rlang::enquo(cond_var)
cond_var_name <- rlang::as_name(cond_var_enq)
time_var_enq <- rlang::enquo(time_var)
time_var_name <- rlang::as_name(time_var_enq)
value_var_enq <- rlang::enquo(value_var)
value_var_name <- rlang::as_name(value_var_enq)
data <- # need to subset becuase of strange contrasts error in anova_test()
data %>%
dplyr::select(!!id_var_enq, !!time_var_enq, !!cond_var_enq, !!value_var_enq)
# Assumptions
if(assum_check){
cat("\n Outliers \n")
data %>%
dplyr::group_by(!!time_var_enq, !!cond_var_enq) %>%
rstatix::identify_outliers(!!value_var_enq) %>% # outliers (needs to be 0)
print()
cat("\n Normality assumption (p>.05) \n")
data %>%
dplyr::group_by(!!time_var_enq, !!cond_var_enq) %>%
rstatix::shapiro_test(!!value_var_enq) %>% # normality assumption (p>.05)
print()
qq_plot <-
ggpubr::ggqqplot(data = data, value_var_name, ggtheme = theme_bw(), title = "QQ Plot") +
ggplot2::facet_grid(vars(!!time_var_enq), vars(!!cond_var_enq), labeller = "label_both") # QQ plot
cat("\n Homogneity of variance assumption - Levene’s test (p>.05) \n")
data %>%
group_by(!!time_var_enq ) %>%
levene_test(as.formula(paste0(value_var_name, " ~ ", cond_var_name))) %>%
print()
cat("\n Homogeneity of covariances assumption - Box’s test of equality of covariance matrices (p>.001) \n")
box_m(data = data[, value_var_name, drop = FALSE], group = data[, cond_var_name, drop = TRUE]) %>%
print
}
# Two-way rmANOVA - check for interaction (ex. F(2, 22) = 30.4, p < 0.0001)
cat("\n Two-way rmANOVA \n")
res_aov <-
anova_test(data = data, dv = !!value_var_enq, wid = !!id_var_enq, # automatically does sphericity Mauchly’s test
within = !!time_var_enq, between = !!cond_var_enq)
get_anova_table(res_aov) %>% # ges: Greenhouse-Geisser sphericity correction is automatically applied to factors violating the sphericity assumption
print()
# ------------------------------------------------------------------------
#- Procedure for a significant two-way interaction -
if(posthoc_sig_interac){
cat("\n Effect of group at each time point - One-way ANOVA\n")
one_way <-
data %>%
group_by(!!time_var_enq) %>%
anova_test(dv = !!value_var_enq, wid = !!id_var_enq, between = !!cond_var_enq) %>%
get_anova_table() %>%
adjust_pvalue(method = p_adjust_method)
one_way %>% print()
cat("\n Pairwise comparisons between group levels \n")
pwc <-
data %>%
group_by(!!time_var_enq) %>%
pairwise_t_test(as.formula(paste0(value_var_name, " ~ ", cond_var_name)),
p.adjust.method = p_adjust_method)
pwc %>% print()
cat("\n Effect of time at each level of exercises group - One-way ANOVA \n")
one_way2 <-
data %>%
group_by(!!cond_var_enq) %>%
anova_test(dv = !!value_var_enq, wid = !!id_var_enq, within = !!time_var_enq) %>%
get_anova_table() %>%
adjust_pvalue(method = p_adjust_method)
one_way2 %>% print()
cat("\n Pairwise comparisons between time points at each group levels (we have repeated measures by time) \n")
pwc2 <-
data %>%
group_by(!!cond_var_enq) %>%
pairwise_t_test(
as.formula(paste0(value_var_name, " ~ ", time_var_name)), # paste formula, not quosure
paired = TRUE,
p.adjust.method = p_adjust_method
)
pwc2 %>% print()
}
#- Procedure for non-significant two-way interaction-
# If the interaction is not significant, you need to interpret the main effects for each of the two variables: treatment and time.
if(posthoc_ns_interac){
cat("\n Comparisons for treatment variable \n")
pwc_cond <-
data %>%
pairwise_t_test(
as.formula(paste0(value_var_name, " ~ ", cond_var_name)), # paste formula, not quosure
paired = FALSE,
p.adjust.method = p_adjust_method
)
pwc_cond %>% print()
cat("\n Comparisons for time variable \n")
pwc_time <-
data %>%
pairwise_t_test(
as.formula(paste0(value_var_name, " ~ ", time_var_name)), # paste formula, not quosure
paired = TRUE,
p.adjust.method = p_adjust_method
)
pwc_time %>% print()
}
# Visualization
bx_plot <-
ggboxplot(data, x = time_var_name, y = value_var_name,
color = cond_var_name, palette = "jco")
pwc <-
pwc %>%
add_xy_position(x = time_var_name)
bx_plot <-
bx_plot +
stat_pvalue_manual(pwc, tip.length = 0, hide.ns = TRUE) +
labs(
subtitle = get_test_label(res_aov, detailed = TRUE),
caption = get_pwc_label(pwc)
)
if(assum_check){
list(qq_plot, bx_plot)
}else{
bx_plot
}
}
# ex. - run on long format
# tw_mixedANOVA_func(data = anxiety, id_var = id, cond_var = group, time_var = time, value_var = score,
# posthoc_sig_interac = TRUE, posthoc_ns_interac = TRUE)
Read, Clean, Recode
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Read, Clean, Recode, Unite
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Read files
folder <- "C:/Users/Mihai/Desktop/R Notebooks/notebooks/M2-report"
file <- "DateM2 final.xlsx"
setwd(folder)
Data_pre <- rio::import(file.path(folder, file),
skip = 3, which = "M2 PRE")
Data_post <- rio::import(file.path(folder, file),
skip = 3, which = "M2 POST")
# PRE = colnames(Data_pre); POST = colnames(Data_post)
# cbind(PRE, POST) # "s1.7" var is missing form POST -- missmatch row 12
# # also missing "s2.7" and others
# index from "DateM2.xlsx"
# index_ryff_pre <- 94:135
# index_pss_pre <- 136:149
# index_ryff_post <- 94:135 - 5
# index_pss_post <- 136:149 - 5
index_ryff_pre <- 83:124
index_pss_pre <- 125:138
index_ryff_post <- 81:122
index_pss_post <- 123:136
colnames(Data_pre)[1] <- "ID"
colnames(Data_pre)[colnames(Data_pre) == "Stres pre"] <- "VAS_stress_pre"
colnames(Data_pre)[colnames(Data_pre) == "Stres post"] <- "VAS_stress_post"
colnames(Data_pre)[index_ryff_pre] <- sprintf("ryff_%01d", seq(1, 42))
colnames(Data_pre)[index_pss_pre] <- sprintf("pss_%01d", seq(1, 14))
Data_pre <-
Data_pre %>%
drop_na(ID) %>%
dplyr::mutate_if(is.character, list(~dplyr::na_if(., "na")))
Data_pre[index_ryff_pre] <- colstonumeric(Data_pre[index_ryff_pre])
Data_pre$pss_8[Data_pre$pss_8 == "++++++"] <- NA # typo
Data_pre[index_pss_pre] <- colstonumeric(Data_pre[index_pss_pre])
colnames(Data_post)[1] <- "ID"
colnames(Data_post)[colnames(Data_post) == "Stres pre"] <- "VAS_stress_pre"
colnames(Data_post)[colnames(Data_post) == "Stres post"] <- "VAS_stress_post"
colnames(Data_post)[index_ryff_post] <- sprintf("ryff_%01d", seq(1, 42))
colnames(Data_post)[index_pss_post] <- sprintf("pss_%01d", seq(1, 14))
Data_post <-
Data_post %>%
dplyr::mutate_if(is.character, list(~dplyr::na_if(., "na")))
Data_post[index_ryff_post] <- colstonumeric(Data_post[index_ryff_post])
Data_post[index_pss_post] <- colstonumeric(Data_post[index_pss_post])
# typos
# check_numeric <- as.data.frame(sapply(Data_pre[index_pss_pre], varhandle::check.numeric))
# sapply(check_numeric, function(x) length(which(!x)))
colnames(Data_pre)[colnames(Data_pre) == "s1.1."] <- "s1.1"
colnames(Data_post)[colnames(Data_post) == "s1.1."] <- "s1.1"
Data_post$s2.10[which(Data_post$s2.10 == ".")] <- NA
Data_post$s2.10 <- as.numeric(Data_post$s2.10)
Data_post$s3.16[which(Data_post$s3.16 == "kq")] <- NA
Data_post$s3.16 <- as.numeric(Data_post$s3.16)
## PSS-SF 14 (likert 0-4)
# Items 4, 5, 6, 7, 9, 10, and 13 are scored in reverse direction.
indexitem_revPSS <- c(4, 5, 6, 7, 9, 10, 13)
Data_pre[, index_pss_pre][indexitem_revPSS] <- ReverseCode(Data_pre[, index_pss_pre][indexitem_revPSS], tonumeric = FALSE, min = 0, max = 4)
Data_post[, index_pss_post][indexitem_revPSS] <- ReverseCode(Data_post[, index_pss_post][indexitem_revPSS], tonumeric = FALSE, min = 0, max = 4)
Data_pre$PSS <- ScoreLikert(Data_pre[, index_pss_pre], napercent = .4)
Data_post$PSS <- ScoreLikert(Data_post[, index_pss_post], napercent = .4)
## Ryff (likert 1-6)
# Recode negative phrased items: 3,5,10,13,14,15,16,17,18,19,23,26,27,30,31,32,34,36,39,41.
# Autonomy: 1,7,13,19,25,31,37
# Environmental mastery: 2,8,14,20,26,32,38
# Personal Growth: 3,9,15,21,27,33,39
# Positive Relations: 4,10,16,22,28,34,40
# Purpose in life: 5,11,17,23,29,35,41
# Self-acceptance: 6,12,18,24,30,36,42
indexitem_revRYFF <- c(3,5,10,13,14,15,16,17,18,19,23,26,27,30,31,32,34,36,39,41)
Data_pre[, index_ryff_pre][indexitem_revRYFF] <- ReverseCode(Data_pre[, index_ryff_pre][indexitem_revRYFF], tonumeric = FALSE, min = 1, max = 6)
Data_post[, index_ryff_post][indexitem_revRYFF] <- ReverseCode(Data_post[, index_ryff_post][indexitem_revRYFF], tonumeric = FALSE, min = 1, max = 6)
indexitem_Auto <- c(1,7,13,19,25,31,37)
indexitem_EnvM <- c(2,8,14,20,26,32,38)
indexitem_PersG <- c(3,9,15,21,27,33,39)
indexitem_PosRel <- c(4,10,16,22,28,34,40)
indexitem_PurLif <- c(5,11,17,23,29,35,41)
indexitem_SelfAc <- c(6,12,18,24,30,36,42)
Data_pre$Auto <- ScoreLikert(Data_pre[, index_ryff_pre][indexitem_Auto], napercent = .4)
Data_pre$EnvM <- ScoreLikert(Data_pre[, index_ryff_pre][indexitem_EnvM], napercent = .4)
Data_pre$PersG <- ScoreLikert(Data_pre[, index_ryff_pre][indexitem_PersG], napercent = .4)
Data_pre$PosRel <- ScoreLikert(Data_pre[, index_ryff_pre][indexitem_PosRel], napercent = .4)
Data_pre$PurLif <- ScoreLikert(Data_pre[, index_ryff_pre][indexitem_PurLif], napercent = .4)
Data_pre$SelfAc <- ScoreLikert(Data_pre[, index_ryff_pre][indexitem_SelfAc], napercent = .4)
Data_post$Auto <- ScoreLikert(Data_post[, index_ryff_post][indexitem_Auto], napercent = .4)
Data_post$EnvM <- ScoreLikert(Data_post[, index_ryff_post][indexitem_EnvM], napercent = .4)
Data_post$PersG <- ScoreLikert(Data_post[, index_ryff_post][indexitem_PersG], napercent = .4)
Data_post$PosRel <- ScoreLikert(Data_post[, index_ryff_post][indexitem_PosRel], napercent = .4)
Data_post$PurLif <- ScoreLikert(Data_post[, index_ryff_post][indexitem_PurLif], napercent = .4)
Data_post$SelfAc <- ScoreLikert(Data_post[, index_ryff_post][indexitem_SelfAc], napercent = .4)
## Save Scores
# rio::export(Data_pre[, c(1, 150:156)])
# rio::export(Data_post[, c(1, 149:155)])
# nlastcol <- 7
# rio::export(list(PRE = Data_pre[, c(1, (ncol(Data_pre)-nlastcol+1):ncol(Data_pre))], POST = Data_post[, c(1, (ncol(Data_post)-nlastcol+1):ncol(Data_post))]),
# "M2 PSS Ryff final.xlsx")
Data_pre$S1_Mean <- rowMeans(Data_pre[, sprintf("s1.%d", c(1:6, 8:16))], na.rm = TRUE) # Data_pre[, grep("s1.", colnames(Data_pre))]
Data_pre$S2_Mean <- rowMeans(Data_pre[, sprintf("s2.%d", c(1:6, 8:16))], na.rm = TRUE) # Data_pre[, grep("s2.", colnames(Data_pre))]
Data_pre$S3_Mean <- rowMeans(Data_pre[, sprintf("s3.%d", c(1:6, 8:16))], na.rm = TRUE) # Data_pre[, grep("s3.", colnames(Data_pre))]
Data_post$S1_Mean <- rowMeans(Data_post[, sprintf("s1.%d", c(1:6, 8:16))], na.rm = TRUE) # Data_post[, grep("s1.", colnames(Data_post))]
Data_post$S2_Mean <- rowMeans(Data_post[, sprintf("s2.%d", c(1:6, 8:16))], na.rm = TRUE) # Data_post[, grep("s2.", colnames(Data_post))]
Data_post$S3_Mean <- rowMeans(Data_post[, sprintf("s3.%d", c(1:6, 8:16))], na.rm = TRUE) # Data_post[, grep("s3.", colnames(Data_post))]
Add TR & CTRL groups
tr_ids <- paste0(c(1, 2, 4, 5, 6, 10, 13, 14, 15, 16, 24, 25, 26, 32, 34, 35, 39, 40, 42, 46, 47, 48, 51, 53, 59, 60, 62, 63, 64), " M2")
ctrl_ids <- paste0(c(3, 7, 8, 9, 11, 12, 17, 18, 19, 20, 21, 22, 23, 27, 28, 30, 33, 36, 37, 38, 41, 43, 45, 49, 52, 54, 55, 56, 57, 58), " M2")
# Subj from TR: Data_pre[which(Data_pre$ID %in% tr_ids),]
# Subj from CTRL: Data_pre[which(Data_pre$ID %in% ctrl_ids),]
Data_pre$Cond <- dplyr::case_when(Data_pre$ID %in% tr_ids ~ "TR",
Data_pre$ID %in% ctrl_ids ~ "CTRL",
TRUE ~ NA_character_)
Data_post$Cond <- dplyr::case_when(Data_post$ID %in% tr_ids ~ "TR",
Data_post$ID %in% ctrl_ids ~ "CTRL",
TRUE ~ NA_character_)
Add Count-vars & Post-Vars
names(Data_post)[137:139] <- c("spontaneous", "voluntary", "dreams")
Data_pre$s1.count <- rowSums(!is.na(Data_pre[, grepl("s1.*", names(Data_pre))]))
Data_pre$s2.count <- rowSums(!is.na(Data_pre[, grepl("s1.*", names(Data_pre))]))
Data_pre$s3.count <- rowSums(!is.na(Data_pre[, grepl("s3.*", names(Data_pre))]))
Data_post$s1.count <- rowSums(!is.na(Data_post[, grepl("s1.*", names(Data_post))]))
Data_post$s2.count <- rowSums(!is.na(Data_post[, grepl("s1.*", names(Data_post))])) # for some reason it has +1 count from all rest
Data_post$s3.count <- rowSums(!is.na(Data_post[, grepl("s3.*", names(Data_post))]))
Unite data frames
## Number of subjects in pre
## Number of subjects in post
Data_pre$PrePost <- rep("Pre", nrow(Data_pre))
Data_post$PrePost <- rep("Post", nrow(Data_post))
Data_pre_scales <- Data_pre[, c("ID", "Varsta",
"VAS_stress_pre", "VAS_stress_post", "PSS",
"Auto", "EnvM", "PersG", "PosRel", "PurLif", "SelfAc", "S1_Mean", "S2_Mean", "S3_Mean",
"PrePost", "Cond",
"s1.count", "s2.count", "s3.count")]
Data_post_scales <- Data_post[, c("ID", "Varsta",
"VAS_stress_pre", "VAS_stress_post", "PSS",
"Auto", "EnvM", "PersG", "PosRel", "PurLif", "SelfAc", "S1_Mean", "S2_Mean", "S3_Mean",
"PrePost", "Cond",
"s1.count", "s2.count", "s3.count",
"spontaneous", "voluntary", "dreams")]
Data_unif_long <- dplyr::bind_rows(Data_pre_scales, Data_post_scales)
Data_unif_wide <-
Data_unif_long %>%
tidyr::pivot_wider(id_cols = ID, names_from = PrePost, values_from = c(VAS_stress_pre, VAS_stress_post, PSS, Auto, EnvM, PersG, PosRel, PurLif, SelfAc, Cond,
S1_Mean, S2_Mean, S3_Mean, s1.count, s2.count, s3.count, spontaneous, voluntary, dreams))
Data_unif_long <-
Data_unif_long %>%
dplyr::mutate(ID = as.factor(ID),
Cond = as.factor(Cond),
PrePost = as.factor(PrePost)) %>%
dplyr::mutate(Vas_Diff = VAS_stress_post - VAS_stress_pre,
Vas_Mean = rowMeans(dplyr::select(.data = ., VAS_stress_post, VAS_stress_pre), na.rm = TRUE))
# Export data
# rio::export(Data_unif_wide, "M2 wide_format_2.xlsx")
# rio::export(Data_unif_long, "M2 long_format_2.xlsx")
# Export data for RMN in specified order
# rmn_order_ids <- paste0(c(1, 14, 13, 6, 4, 5, 10, 15, 2, 16, 42, 34, 24, 25, 26, 35, 39, 40, 32, 59, 53, 64, 46, 47, 62, 63, 48, 51, 60,
# 8, 20, 12, 18, 9, 17, 19, 7, 3, 43, 41, 27, 23, 38, 22, 33, 28, 30, 21, 37, 49, 56, 58, 57, 52, 45, 55, 54), " ", "M2")
#
# RMN_df <- Data_unif_wide[match(rmn_order_ids, Data_unif_wide$ID),] # only 57 subjs for RMN
#
# rio::export(RMN_df, "RMN ordered M2 wide_format_2.xlsx")
Read NFkB
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Read, Clean, Recode, Unite
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Read files
folder <- "C:/Users/Mihai/Desktop/R Notebooks/notebooks/M2-report"
file <- "lista_M2 cu rezultate NFkB.xlsx"
setwd(folder)
Data_nfkb_TR <- readxl::read_xlsx(file.path(folder, file),
range = "A1:F30", sheet = "NFkB")
Data_nfkb_CTRL <- readxl::read_xlsx(file.path(folder, file),
range = "H1:M31", sheet = "NFkB")
Data_nfkb_TR <- Data_nfkb_TR[-1, ]
colnames(Data_nfkb_TR)[c(1, 4, 6)] <- c("ID", "NFkB_Pre", "NFkB_Post")
Data_nfkb_TR <-
Data_nfkb_TR %>%
dplyr::rename_all(~stringr::str_replace_all(., " ", "_")) %>%
dplyr::select(-starts_with("ID_Parhon")) %>%
dplyr::mutate(Cond = rep("TR", nrow(Data_nfkb_TR))) %>%
dplyr::mutate(ID = stringr::str_remove(ID, "ID")) %>%
dplyr::mutate(ID = stringr::str_remove(ID, " ")) %>%
dplyr::mutate(ID = stringr::str_c(ID, " M2"))
Data_nfkb_CTRL <- Data_nfkb_CTRL[-1, ]
colnames(Data_nfkb_CTRL)[c(1, 4, 6)] <- c("ID", "NFkB_Pre", "NFkB_Post")
Data_nfkb_CTRL <-
Data_nfkb_CTRL %>%
dplyr::rename_all(~stringr::str_replace_all(., " ", "_")) %>%
dplyr::select(-starts_with("ID_Parhon")) %>%
dplyr::mutate(Cond = rep("CTRL", nrow(Data_nfkb_CTRL))) %>%
dplyr::mutate(ID = stringr::str_remove(ID, "ID")) %>%
dplyr::mutate(ID = stringr::str_remove(ID, " ")) %>%
dplyr::mutate(ID = stringr::str_c(ID, " M2"))
Unite with nfkb
[1] TRUE
[1] "'is.NA' value mismatch: 2 in current 0 in target"
NfKB
#### NFkB_Pre NFkB_Post
#### NFkB_Pre NFkB_Post
New Ideas: Correlations Number of memories & remembering
PRE-POST Comparisons by Cond: TR
## PRE-POST Comparisons by Cond: CTRL
## POST-vars Comparisons by Cond
## Correlation - whole sample
## Correlation - TR
## Correlation - CTRL
LS0tDQp0aXRsZTogIjxicj4gTTIiIA0Kc3VidGl0bGU6ICJSZXBvcnQiDQphdXRob3I6ICI8YnI+IENsYXVkaXUgUGFwYXN0ZXJpIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJW0gJVknKWAiDQpvdXRwdXQ6IA0KICAgIGh0bWxfbm90ZWJvb2s6DQogICAgICAgICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICAgICAgICAgIHRvYzogdHJ1ZQ0KICAgICAgICAgICAgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICAgICAgICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgICAgICAgICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgICAgICAgICAgZm9udC1mYW1pbHk6IEFyaWFsDQogICAgICAgICAgICBmaWdfd2lkdGg6IDEwDQogICAgICAgICAgICBmaWdfaGVpZ2h0OiA5DQogICAgIyBwZGZfZG9jdW1lbnQ6IA0KICAgICAgICAgICAgIyB0b2M6IHRydWUNCiAgICAgICAgICAgICMgIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICAjIGZvbnRzaXplOiAxMXB0DQogICAgICAgICAgICAjIGdlb21ldHJ5OiBtYXJnaW49MWluDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNw0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA2DQogICAgICAgICAgICAjIGZpZ19jYXB0aW9uOiB0cnVlDQogICAgIyBnaXRodWJfZG9jdW1lbnQ6IA0KICAgICAgICAgICAgIyB0b2M6IHRydWUNCiAgICAgICAgICAgICMgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICAjIGh0bWxfcHJldmlldzogZmFsc2UNCiAgICAgICAgICAgICMgZmlnX3dpZHRoOiA1DQogICAgICAgICAgICAjIGZpZ19oZWlnaHQ6IDUNCiAgICAgICAgICAgICMgZGV2OiBqcGVnDQotLS0NCg0KDQo8IS0tIFNldHVwIC0tPg0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBraW50ciBvcHRpb25zDQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGNvbW1lbnQgPSAiIyIsDQogIGNvbGxhcHNlID0gVFJVRSwNCiAgZXJyb3IgPSBUUlVFLA0KICBlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGNhY2hlID0gVFJVRSAgICAgICAjIGVjaG8gPSBGYWxzZSBmb3IgZ2l0aHViX2RvY3VtZW50LCBidXQgd2lsbCBiZSBmb2xkZWQgaW4gaHRtbF9ub3RlYm9vaw0KKQ0KDQojIEdlbmVyYWwgUiBvcHRpb25zIGFuZCBpbmZvDQpzZXQuc2VlZCgxMTEpICAgICAgICAgICAgICAgIyBpbiBjYXNlIHdlIHVzZSByYW5kb21pemVkIHByb2NlZHVyZXMgICAgICAgDQpvcHRpb25zKHNjaXBlbiA9IDk5OSkgICAgICAgIyBwb3NpdGl2ZSB2YWx1ZXMgYmlhcyB0b3dhcmRzIGZpeGVkIGFuZCBuZWdhdGl2ZSB0b3dhcmRzIHNjaWVudGlmaWMgbm90YXRpb24NCg0KIyBMb2FkIHBhY2thZ2VzDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFja2FnZXMgPC0gYygNCiAgInBhcGFqYSIsDQogICJ0aWR5dmVyc2UiLCAgICAgICANCiAgInBzeWNoIiwgIlBlcmZvcm1hbmNlQW5hbHl0aWNzIiwgICAgICAgICAgDQogICJicm9vbSIsICJyc3RhdGl4IiwNCiAgInN1bW1hcnl0b29scyIsICJ0YWRhYXRvb2xib3giLCAgICAgICAgICAgDQogICJnZ3Bsb3QyIiwgImdncHViciIsICJzY2FsZXMiLCAgICAgICAgDQogICJyaW8iLA0KICAiZ2dwdWJyIiwgInJzdGF0aXgiLCAiYnJvb20iLCAiZW1tZWFucyIsICJybGFuZyINCiAgIyAsIC4uLg0KKQ0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY21hbjo6cF9sb2FkKGNoYXIgPSBwYWNrYWdlcykNCg0KIyBUaGVtZXMgZm9yIGdncGxvdDIgcGxvdGluZyAoaGVyZSB1c2VkIEFQQSBzdHlsZSkNCnRoZW1lX3NldCh0aGVtZV9hcGEoKSkNCmBgYA0KDQoNCg0KDQoNCjwhLS0gUmVwb3J0IC0tPg0KDQojIERlZmluZSBmdW5jdGlvbnMNCg0KYGBge3IgZGVmX2Z1bmN9DQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCByZWNvZGVzIHRvIG51bWVyaWMsIGJ1dCB3YXRjaGVzIG91dCB0byBjb2VyY2lvbiB0byBub3QgaW50cm9kdWNlIE5Bcw0KY29sc3RvbnVtZXJpYyA8LSBmdW5jdGlvbihkZil7DQogIHRyeUNhdGNoKHsNCiAgICBkZl9udW0gPC0gYXMuZGF0YS5mcmFtZSgNCiAgICAgIGxhcHBseShkZiwNCiAgICAgICAgICAgICBmdW5jdGlvbih4KSB7IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHgpKX0pKSANCiAgfSx3YXJuaW5nID0gZnVuY3Rpb24oc3RvcF9vbl93YXJuaW5nKSB7DQogICAgbWVzc2FnZSgiU3RvcGVkIHRoZSBleGVjdXRpb24gb2YgbnVtZXJpYyBjb252ZXJzaW9uOiAiLCBjb25kaXRpb25NZXNzYWdlKHN0b3Bfb25fd2FybmluZykpDQogIH0pIA0KfQ0KIyMNCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHJldmVyc2UgY29kZXMgaXRlbXMNClJldmVyc2VDb2RlIDwtIGZ1bmN0aW9uKGRmLCB0b251bWVyaWMgPSBGQUxTRSwgbWluID0gTlVMTCwgbWF4ID0gTlVMTCkgew0KICBpZih0b251bWVyaWMpIGRmIDwtIGNvbHN0b251bWVyaWMoZGYpDQogIGRmIDwtIChtYXggKyBtaW4pIC0gZGYNCn0NCiMjDQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCBzY29yZXMgb25seSByb3dzIHdpdGggbGVzcyB0aGFuIDEwJSBOQXMgKHJldHVybnMgTkEgaWYgYWxsIG9yIGFib3ZlIHRocmVzaG9sZCBwZXJjZW50YWdlIG9mIHJvd3MgYXJlIE5BKTsgY2FuIHJldmVyc2UgY29kZSBpZiB2ZWN0b3Igb2YgY29sdW1uIGluZGV4ZXMgYW5kIG1pbiwgbWF4IGFyZSBwcm92aWRlZC4NClNjb3JlTGlrZXJ0IDwtIGZ1bmN0aW9uKGRmLCBuYXBlcmNlbnQgPSAuMSwgdG9udW1lcmljID0gRkFMU0UsIHJldmVyc2Vjb2xzID0gTlVMTCwgbWluID0gTlVMTCwgbWF4ID0gTlVMTCkgew0KICByZXZlcnNlX2xpc3QgPC0gbGlzdChyZXZlcnNlY29scyA9IHJldmVyc2Vjb2xzLCBtaW4gPSBtaW4sIG1heCA9IG1heCkNCiAgcmV2ZXJzZV9jaGVjayA8LSAhc2FwcGx5KHJldmVyc2VfbGlzdCwgaXMubnVsbCkNCiAgDQogICMgUmVjb2RlIHRvIG51bWVyaWMsIGJ1dCB3YXRjaCBvdXQgdG8gY29lcmNpb24gdG8gbm90IGludHJvZHVjZSBOQXMNCiAgY29sc3RvbnVtZXJpYyA8LSBmdW5jdGlvbihkZil7DQogICAgdHJ5Q2F0Y2goew0KICAgICAgZGZfbnVtIDwtIGFzLmRhdGEuZnJhbWUoDQogICAgICAgIGxhcHBseShkZiwNCiAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHsgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpfSkpIA0KICAgIH0sd2FybmluZyA9IGZ1bmN0aW9uKHN0b3Bfb25fd2FybmluZykgew0KICAgICAgbWVzc2FnZSgiU3RvcGVkIHRoZSBleGVjdXRpb24gb2YgbnVtZXJpYyBjb252ZXJzaW9uOiAiLCBjb25kaXRpb25NZXNzYWdlKHN0b3Bfb25fd2FybmluZykpDQogICAgfSkgDQogIH0NCiAgDQogIGlmKHRvbnVtZXJpYykgZGYgPC0gY29sc3RvbnVtZXJpYyhkZikNCiAgDQogIGlmKGFsbChyZXZlcnNlX2NoZWNrKSl7DQogICAgZGZbICxyZXZlcnNlY29sc10gPC0gKG1heCArIG1pbikgLSBkZlsgLHJldmVyc2Vjb2xzXQ0KICB9ZWxzZSBpZihhbnkocmV2ZXJzZV9jaGVjaykpew0KICAgIHN0b3AoIkluc3VmaWNpZW50IGluZm8gZm9yIHJldmVyc2luZy4gUGxlYXNlIHByb3ZpZGU6ICIsIHBhc3RlKG5hbWVzKHJldmVyc2VfbGlzdClbIXJldmVyc2VfY2hlY2tdLCBjb2xsYXBzZSA9ICIsICIpKQ0KICB9DQogIA0KICBpZmVsc2Uocm93U3Vtcyhpcy5uYShkZikpID4gbmNvbChkZikgKiBuYXBlcmNlbnQsDQogICAgICAgICBOQSwNCiAgICAgICAgIHJvd1N1bXMoZGYsIG5hLnJtID0gVFJVRSkgKiBOQSBeIChyb3dTdW1zKCFpcy5uYShkZikpID09IDApDQogICkNCn0NCiMjDQpgYGANCg0KDQpgYGB7ciBkZWZfZnVuY190dGVzdCwgaGlkZT1UUlVFfQ0KIyMgRnVuYyB0IHRlc3Qgc2kgYm94cGxvdCBzaW1wbHUNCmZ1bmNfdF9ib3ggPC0gZnVuY3Rpb24oZGYsIGluZCwgcHJlX3ZhciwgcG9zdF92YXIpew0KICB2YXJzIDwtIGMoaW5kLCBwcmVfdmFyLCBwb3N0X3ZhcikgICAgICAgICAgICAgICAgIyB0byBhdm9pZCBuZXcgdGlkeXZlcnNlIGVycm9yIG9mIGFtYmlndWl0eSBkdWUgdG8gZXh0ZXJuYWwgdmVjdG9zDQogIGRmX21vZGlmIDwtDQogICAgZGYgJT4lDQogICAgZHBseXI6OnNlbGVjdCh0aWR5c2VsZWN0OjphbGxfb2YodmFycykpICU+JSANCiAgICB0aWR5cjo6ZHJvcF9uYSgpICU+JQ0KICAgIGdhdGhlcih0aWR5c2VsZWN0OjphbGxfb2YocHJlX3ZhciksIHRpZHlzZWxlY3Q6OmFsbF9vZihwb3N0X3ZhciksIGtleSA9ICJDb25kIiwgdmFsdWUgPSAidmFsdWUiKSAlPiUgDQogICAgbXV0YXRlX2F0KHZhcnMoYygxLCAyKSksIGFzLmZhY3RvcikgJT4lIA0KICAgIG11dGF0ZShDb25kID0gZmFjdG9yKENvbmQsIGxldmVscyA9IGMocHJlX3ZhciwgcG9zdF92YXIpKSkgDQogIA0KICBzdGF0X2NvbXAgPC0gZ2dwdWJyOjpjb21wYXJlX21lYW5zKHZhbHVlIH4gQ29uZCwgZGF0YSA9IGRmX21vZGlmLCBtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gVFJVRSkNCiAgDQogIHN0YXRfY29tcDIgPC0NCiAgICBkZl9tb2RpZiAlPiUgDQogICAgZG8odGlkeSh0LnRlc3QoLiR2YWx1ZSB+IC4kQ29uZCwNCiAgICAgICAgICAgICAgICAgICBwYWlyZWQgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIGRhdGE9LikpKQ0KICANCiAgcGxvdCA8LSANCiAgICBnZ3B1YnI6OmdncGFpcmVkKGRmX21vZGlmLCB4ID0gIkNvbmQiLCB5ID0gInZhbHVlIiwgaWQgPSBpbmQsIA0KICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiQ29uZCIsIGxpbmUuY29sb3IgPSAiZ3JheSIsIGxpbmUuc2l6ZSA9IDAuNCwNCiAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSBjKCIjMDBBRkJCIiwgIiNGQzRFMDciKSwgbGVnZW5kID0gIm5vbmUiKSArDQogICAgICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLCAgY29sb3VyID0gImRhcmtyZWQiKSArDQogICAgICBnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gVFJVRSwgbGFiZWwueCA9IGFzLm51bWVyaWMoZGZfbW9kaWYkQ29uZCktMC40LCBsYWJlbC55ID0gbWF4KGRmX21vZGlmJHZhbHVlKSswLjUpICsgDQogICAgICBnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gVFJVRSwgbGFiZWwgPSAicC5zaWduaWYiLCBjb21wYXJpc29ucyA9IGxpc3QoYyhwcmVfdmFyLCBwb3N0X3ZhcikpKQ0KICANCiAgY2F0KHBhc3RlMCgiIyMjIyAiLCBwcmVfdmFyLCAiICIsIHBvc3RfdmFyLCAiXG4iLCAiXG4iKSkNCiAgcHJpbnQoc3RhdF9jb21wKQ0KICBwcmludChzdGF0X2NvbXAyKQ0KICBwcmludChwbG90KQ0KfQ0KYGBgDQoNCg0KYGBge3IgZGVmX2Z1bmNfQU5DT1ZBUG9zdH0NCiMgbGlicmFyeSh0aWR5dmVyc2UpDQojIGxpYnJhcnkoZ2dwdWJyKQ0KIyBsaWJyYXJ5KHJzdGF0aXgpDQojIGxpYnJhcnkoYnJvb20pDQojIGxpYnJhcnkoZW1tZWFucykNCiMgbGlicmFyeShybGFuZykNCg0KDQojIEZ1bmN0aW9uIEFOQ09WQVBvc3QNCiMgVGFrZXMgTG9uZyBEYXRhDQpBTkNPVkFQb3N0X2Z1bmMgPC0gDQogIGZ1bmN0aW9uKGRhdGEsIGlkX3ZhciwgDQogICAgICAgICAgIHRpbWVfdmFyLCBwcmVfbGFiZWwsIHBvc3RfbGFiZWwsDQogICAgICAgICAgIHZhbHVlX3ZhciA9IHNjb3JlcywgY29uZF92YXIsIA0KICAgICAgICAgICBhc3N1bV9jaGVjayA9IFRSVUUsIHBvc3Rob2MgPSBUUlVFLCANCiAgICAgICAgICAgcF9hZGp1c3RfbWV0aG9kID0gImJvbmZlcnJvbmkiKXsNCiAgDQogIGlkX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKGlkX3ZhcikNCiAgaWRfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUoaWRfdmFyX2VucSkgICAgDQogIHRpbWVfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8odGltZV92YXIpDQogIHRpbWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodGltZV92YXJfZW5xKQ0KICBwcmVfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8ocHJlX2xhYmVsKQ0KICBwcmVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUocHJlX3Zhcl9lbnEpICANCiAgcG9zdF92YXJfZW5xIDwtIHJsYW5nOjplbnF1byhwb3N0X2xhYmVsKQ0KICBwb3N0X3Zhcl9uYW1lIDwtIHJsYW5nOjphc19uYW1lKHBvc3RfdmFyX2VucSkNCiAgY29uZF92YXJfZW5xIDwtIHJsYW5nOjplbnF1byhjb25kX3ZhcikNCiAgY29uZF92YXJfbmFtZSA8LSBybGFuZzo6YXNfbmFtZShjb25kX3Zhcl9lbnEpDQogIHZhbHVlX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKHZhbHVlX3ZhcikNCiAgdmFsdWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodmFsdWVfdmFyX2VucSkgDQogIA0KICBkYXRhX3dpZGVyIDwtDQogICAgZGF0YSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KCEhaWRfdmFyX2VucSwgISF0aW1lX3Zhcl9lbnEsICEhY29uZF92YXJfZW5xLCAhIXZhbHVlX3Zhcl9lbnEpICU+JQ0KICAgIHNwcmVhZChrZXkgPSB0aW1lX3Zhcl9uYW1lLCB2YWx1ZSA9IHZhbHVlX3Zhcl9uYW1lKSAjICU+JSAgICAgIyBpZiBuZWVkIHRvIGNvbXB1dGUgY2hhbmdlIHNjb3JlIHN0YXRpc3RpY3MgZ28gZnJvbSBoZXJlDQogICAgIyBtdXRhdGUoZGlmZmVyZW5jZSA9ICEhcG9zdF92YXJfZW5xIC0gISFwcmVfdmFyX2VucSkgIA0KICAgIA0KICAjIEFzc3VtcHRpb25zDQogIGlmKGFzc3VtX2NoZWNrKXsNCiAgY2F0KCJcbiBMaW5lYXJpdHkgYXNzdW1wdGlvbkxpbmVhcml0eSBhc3N1bXB0aW9uIChsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gcHJlLXRlc3QgYW5kIHBvc3QtdGVzdCBmb3IgZWFjaCBncm91cCkgXG4iKQ0KICAjIENyZWF0ZSBhIHNjYXR0ZXIgcGxvdCBiZXR3ZWVuIHRoZSBjb3ZhcmlhdGUgKGkuZS4sIHByZXRlc3QpIGFuZCB0aGUgb3V0Y29tZSB2YXJpYWJsZSAoaS5lLiwgcG9zdHRlc3QpDQogIHNjYXR0ZXJfbGluIDwtICANCiAgICBnZ3NjYXR0ZXIoZGF0YV93aWRlciwgeCA9IHByZV92YXJfbmFtZSwgeSA9IHBvc3RfdmFyX25hbWUsIGNvbG9yID0gY29uZF92YXJfbmFtZSwgDQogICAgICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIHRpdGxlID0gIkxpbmVhcml0eSBhc3N1bXB0aW9uIikgKw0KICAgICAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGFlcyhsYWJlbCA9ICBwYXN0ZSguLmVxLmxhYmVsLi4sIC4ucnIubGFiZWwuLiwgc2VwID0gIn5+fn4iKSwgY29sb3IgPSAhIWNvbmRfdmFyX2VucSkpDQogIA0KICBjYXQoIlxuIEhvbW9nZW5laXR5IG9mIHJlZ3Jlc3Npb24gc2xvcGVzIChpbnRlcmFjdGlvbiB0ZXJtIGlzIG4ucy4pIFxuIikNCiAgZGF0YV93aWRlciAlPiUgDQogICAgYW5vdmFfdGVzdChhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSwgIiAqICIsIHByZV92YXJfbmFtZSkpKSAlPiUgDQogICAgcHJpbnQoKSAgIA0KICANCiAgY2F0KCJcbiBOb3JtYWxpdHkgb2YgcmVzaWR1YWxzIChNb2RlbCBkaWFnbm9zdGljcyAmIFNoYXBpcm8gV2lsaykgXG4iKQ0KICAjIEZpdCB0aGUgbW9kZWwsIHRoZSBjb3ZhcmlhdGUgZ29lcyBmaXJzdA0KICBtb2RlbCA8LSANCiAgICBsbShhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSwgIiArICIsIHByZV92YXJfbmFtZSkpLA0KICAgICAgIGRhdGEgPSBkYXRhX3dpZGVyKQ0KICBjYXQoIlxuIEluc3BlY3QgdGhlIG1vZGVsIGRpYWdub3N0aWMgbWV0cmljcyBcbiIpDQogIG1vZGVsLm1ldHJpY3MgPC0gDQogICAgYXVnbWVudChtb2RlbCkgJT4lDQogICAgZHBseXI6OnNlbGVjdCgtLmhhdCwgLS5zaWdtYSwgLS5maXR0ZWQsIC0uc2UuZml0KSAgJT4lICAgICMgUmVtb3ZlIGRldGFpbHMNCiAgICBwcmludCgpDQogIGNhdCgiXG4gTm9ybWFsaXR5IG9mIHJlc2lkdWFscyAoU2hhcGlybyBXaWxrIHA+LjA1KSBcbiIpDQogIHNoYXBpcm9fdGVzdChtb2RlbC5tZXRyaWNzJC5yZXNpZCkgJT4lIA0KICAgIHByaW50KCkNCiAgDQogIGNhdCgiXG4gSG9tb2dlbmVpdHkgb2YgdmFyaWFuY2VzIChMZXZlbmXigJlzIHRlc3QgcD4uMDUpIFxuIikNCiAgbW9kZWwubWV0cmljcyAlPiUgDQogICAgbGV2ZW5lX3Rlc3QoYXMuZm9ybXVsYShwYXN0ZTAoIi5yZXNpZCIsICIgfiAiLCBjb25kX3Zhcl9uYW1lKSkgKSAlPiUgICAgIA0KICAgIHByaW50KCkNCiAgDQogIGNhdCgiXG4gT3V0bGllcnMgKG5lZWRzIHRvIGJlIDApIFxuIikNCiAgbW9kZWwubWV0cmljcyAlPiUgDQogICAgZmlsdGVyKGFicyguc3RkLnJlc2lkKSA+IDMpICU+JQ0KICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgDQogICAgcHJpbnQoKQ0KICANCiAgfQ0KICANCiAgY2F0KCJcbiBBTkNPVkFQb3N0IFxuIikNCiAgcmVzX2FuY292YSA8LSANCiAgICBkYXRhX3dpZGVyICU+JSANCiAgICBhbm92YV90ZXN0KGFzLmZvcm11bGEocGFzdGUwKHBvc3RfdmFyX25hbWUsICIgfiAiLCAgcHJlX3Zhcl9uYW1lLCAiICsgIiwgY29uZF92YXJfbmFtZSkpKSAgICAgICAjIHRoZSBjb3ZhcmlhdGUgbmVlZHMgdG8gYmUgZmlyc3QgdGVybSANCiAgZ2V0X2Fub3ZhX3RhYmxlKHJlc19hbmNvdmEpICU+JSBwcmludCgpDQogIA0KICBjYXQoIlxuIFBhaXJ3aXNlIGNvbXBhcmlzb25zIFxuIikNCiAgcHdjIDwtIA0KICAgIGRhdGFfd2lkZXIgJT4lIA0KICAgIGVtbWVhbnNfdGVzdChhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpLCAgICAgICANCiAgICAgICAgICAgICAgICAgY292YXJpYXRlID0gISFwcmVfdmFyX2VucSwNCiAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gcF9hZGp1c3RfbWV0aG9kKQ0KICBwd2MgJT4lIHByaW50KCkNCiAgY2F0KCJcbiBEaXNwbGF5IHRoZSBhZGp1c3RlZCBtZWFucyBvZiBlYWNoIGdyb3VwLCBhbHNvIGNhbGxlZCBhcyB0aGUgZXN0aW1hdGVkIG1hcmdpbmFsIG1lYW5zIChlbW1lYW5zKSBcbiIpDQogIGdldF9lbW1lYW5zKHB3YykgJT4lIHByaW50KCkNCiAgDQogICMgVmlzdWFsaXphdGlvbjogbGluZSBwbG90cyB3aXRoIHAtdmFsdWVzDQogIHB3YyA8LSANCiAgICBwd2MgJT4lIA0KICAgIGFkZF94eV9wb3NpdGlvbih4ID0gY29uZF92YXJfbmFtZSwgZnVuID0gIm1lYW5fc2UiKQ0KICANCiAgbGluZV9wbG90IDwtIA0KICAgIGdnbGluZShnZXRfZW1tZWFucyhwd2MpLCB4ID0gY29uZF92YXJfbmFtZSwgeSA9ICJlbW1lYW4iKSArDQogICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gY29uZi5sb3csIHltYXggPSBjb25mLmhpZ2gpLCB3aWR0aCA9IDAuMikgKyANCiAgICAgIHN0YXRfcHZhbHVlX21hbnVhbChwd2MsIGhpZGUubnMgPSBUUlVFLCB0aXAubGVuZ3RoID0gRkFMU0UpICsNCiAgICAgIGxhYnMoc3VidGl0bGUgPSBnZXRfdGVzdF9sYWJlbChyZXNfYW5jb3ZhLCBkZXRhaWxlZCA9IFRSVUUpLA0KICAgICAgICAgICBjYXB0aW9uID0gZ2V0X3B3Y19sYWJlbChwd2MpKQ0KICANCiAgaWYoYXNzdW1fY2hlY2spew0KICAgIGxpc3Qoc2NhdHRlcl9saW4sIGxpbmVfcGxvdCkNCiAgfWVsc2V7DQogICAgbGluZV9wbG90DQogIH0NCiAgDQp9DQoNCiMgZXguDQojIEFOQ09WQVBvc3RfZnVuYyhuZXdfYW54aWV0eSwgdGltZV92YXIgPSB0aW1lLCBwcmVfbGFiZWwgPSBwcmV0ZXN0LCBwb3N0X2xhYmVsID0gcG9zdHRlc3QsDQojICAgICAgICAgICB2YWx1ZV92YXIgPSBzY29yZXMsIGNvbmRfdmFyID0gZ3JvdXAsIGFzc3VtX2NoZWNrID0gVFJVRSwgcF9hZGp1c3RfbWV0aG9kID0gImJvbmZlcnJvbmkiKQ0KYGBgDQoNCg0KYGBge3IgZGVmX2Z1bmNfbWl4ZWRBTk9WQX0NCiMgbGlicmFyeSh0aWR5dmVyc2UpDQojIGxpYnJhcnkoZ2dwdWJyKQ0KIyBsaWJyYXJ5KHJzdGF0aXgpDQojIGxpYnJhcnkocmxhbmcpDQoNCiMgRGVmaW5lIEZ1bmN0aW9uIGZvciBNaXhlZCBBbm92YQ0KdHdfbWl4ZWRBTk9WQV9mdW5jIDwtIA0KICBmdW5jdGlvbihkYXRhLCBpZF92YXIsIGNvbmRfdmFyLCB0aW1lX3ZhciwgdmFsdWVfdmFyLCANCiAgICAgICAgICAgYXNzdW1fY2hlY2sgPSBUUlVFLCBwb3N0aG9jX3NpZ19pbnRlcmFjID0gRkFMU0UsIHBvc3Rob2NfbnNfaW50ZXJhYyA9IEZBTFNFLA0KICAgICAgICAgICBwX2FkanVzdF9tZXRob2QgPSAiYm9uZmVycm9uaSIpew0KICAgIA0KICAgICMgaW5wdXQgZGF0YWZyYW1lIG5lZWRzIHRvIGhhdmUgY29sdW1ucyBuYW1lcyBkaWZmcmVudCBmcm9tICJ2YXJpYWJsZSIgYW5kICJ2YWx1ZSIgYmVjYXVzZSBpdCBjb2xsaWRlcyB3aXRoIHJzdGF0aXg6OnNoYXBpcm9fdGVzdA0KICAgIA0KICAgIGlkX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKGlkX3ZhcikgIA0KICAgIGNvbmRfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8oY29uZF92YXIpDQogICAgY29uZF92YXJfbmFtZSA8LSBybGFuZzo6YXNfbmFtZShjb25kX3Zhcl9lbnEpDQogICAgdGltZV92YXJfZW5xIDwtIHJsYW5nOjplbnF1byh0aW1lX3ZhcikNCiAgICB0aW1lX3Zhcl9uYW1lIDwtIHJsYW5nOjphc19uYW1lKHRpbWVfdmFyX2VucSkNCiAgICB2YWx1ZV92YXJfZW5xIDwtIHJsYW5nOjplbnF1byh2YWx1ZV92YXIpDQogICAgdmFsdWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodmFsdWVfdmFyX2VucSkNCiAgICANCiAgICBkYXRhIDwtICAgICAgICAgICAgICAgICAgIyBuZWVkIHRvIHN1YnNldCBiZWN1YXNlIG9mIHN0cmFuZ2UgY29udHJhc3RzIGVycm9yIGluIGFub3ZhX3Rlc3QoKQ0KICAgICAgZGF0YSAlPiUNCiAgICAgIGRwbHlyOjpzZWxlY3QoISFpZF92YXJfZW5xLCAhIXRpbWVfdmFyX2VucSwgISFjb25kX3Zhcl9lbnEsICEhdmFsdWVfdmFyX2VucSkgDQogICAgDQogICAgIyBBc3N1bXB0aW9ucw0KICAgIGlmKGFzc3VtX2NoZWNrKXsNCiAgICAgIGNhdCgiXG4gT3V0bGllcnMgXG4iKQ0KICAgICAgZGF0YSAlPiUNCiAgICAgICAgZHBseXI6Omdyb3VwX2J5KCEhdGltZV92YXJfZW5xLCAhIWNvbmRfdmFyX2VucSkgJT4lDQogICAgICAgIHJzdGF0aXg6OmlkZW50aWZ5X291dGxpZXJzKCEhdmFsdWVfdmFyX2VucSkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgb3V0bGllcnMgKG5lZWRzIHRvIGJlIDApDQogICAgICAgIHByaW50KCkNCiAgICAgIA0KICAgICAgY2F0KCJcbiBOb3JtYWxpdHkgYXNzdW1wdGlvbiAocD4uMDUpIFxuIikNCiAgICAgIGRhdGEgJT4lDQogICAgICAgIGRwbHlyOjpncm91cF9ieSghIXRpbWVfdmFyX2VucSwgISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICByc3RhdGl4OjpzaGFwaXJvX3Rlc3QoISF2YWx1ZV92YXJfZW5xKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBub3JtYWxpdHkgYXNzdW1wdGlvbiAocD4uMDUpDQogICAgICAgIHByaW50KCkNCiAgICAgIA0KICAgICAgcXFfcGxvdCA8LSANCiAgICAgICAgZ2dwdWJyOjpnZ3FxcGxvdChkYXRhID0gZGF0YSwgdmFsdWVfdmFyX25hbWUsIGdndGhlbWUgPSB0aGVtZV9idygpLCB0aXRsZSA9ICJRUSBQbG90IikgKw0KICAgICAgICBnZ3Bsb3QyOjpmYWNldF9ncmlkKHZhcnMoISF0aW1lX3Zhcl9lbnEpLCB2YXJzKCEhY29uZF92YXJfZW5xKSwgbGFiZWxsZXIgPSAibGFiZWxfYm90aCIpICAgICMgUVEgcGxvdA0KICAgICAgDQogICAgICBjYXQoIlxuIEhvbW9nbmVpdHkgb2YgdmFyaWFuY2UgYXNzdW1wdGlvbiAtIExldmVuZeKAmXMgdGVzdCAocD4uMDUpIFxuIikNCiAgICAgIGRhdGEgJT4lDQogICAgICAgIGdyb3VwX2J5KCEhdGltZV92YXJfZW5xICkgJT4lDQogICAgICAgIGxldmVuZV90ZXN0KGFzLmZvcm11bGEocGFzdGUwKHZhbHVlX3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpKSAlPiUNCiAgICAgICAgcHJpbnQoKQ0KICAgICAgDQogICAgICBjYXQoIlxuIEhvbW9nZW5laXR5IG9mIGNvdmFyaWFuY2VzIGFzc3VtcHRpb24gLSBCb3jigJlzIHRlc3Qgb2YgZXF1YWxpdHkgb2YgY292YXJpYW5jZSBtYXRyaWNlcyAocD4uMDAxKSBcbiIpDQogICAgICBib3hfbShkYXRhID0gZGF0YVssIHZhbHVlX3Zhcl9uYW1lLCBkcm9wID0gRkFMU0VdLCBncm91cCA9IGRhdGFbLCBjb25kX3Zhcl9uYW1lLCBkcm9wID0gVFJVRV0pICU+JQ0KICAgICAgICBwcmludA0KICAgIH0NCiAgICANCiAgICAjIFR3by13YXkgcm1BTk9WQSAtIGNoZWNrIGZvciBpbnRlcmFjdGlvbiAoZXguIEYoMiwgMjIpID0gMzAuNCwgcCA8IDAuMDAwMSkNCiAgICBjYXQoIlxuIFR3by13YXkgcm1BTk9WQSBcbiIpDQogICAgcmVzX2FvdiA8LSANCiAgICAgIGFub3ZhX3Rlc3QoZGF0YSA9IGRhdGEsIGR2ID0gISF2YWx1ZV92YXJfZW5xLCB3aWQgPSAhIWlkX3Zhcl9lbnEsICAgICAgICAgICAgICAgIyBhdXRvbWF0aWNhbGx5IGRvZXMgc3BoZXJpY2l0eSBNYXVjaGx54oCZcyB0ZXN0DQogICAgICAgICAgICAgICAgIHdpdGhpbiA9ICEhdGltZV92YXJfZW5xLCBiZXR3ZWVuID0gISFjb25kX3Zhcl9lbnEpDQogICAgZ2V0X2Fub3ZhX3RhYmxlKHJlc19hb3YpICU+JSAgIyBnZXM6IEdyZWVuaG91c2UtR2Vpc3NlciBzcGhlcmljaXR5IGNvcnJlY3Rpb24gaXMgYXV0b21hdGljYWxseSBhcHBsaWVkIHRvIGZhY3RvcnMgdmlvbGF0aW5nIHRoZSBzcGhlcmljaXR5IGFzc3VtcHRpb24gIA0KICAgICAgcHJpbnQoKQ0KICAgIA0KICAgIA0KICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQogICAgDQogICAgIy0gUHJvY2VkdXJlIGZvciBhIHNpZ25pZmljYW50IHR3by13YXkgaW50ZXJhY3Rpb24gLQ0KICAgIGlmKHBvc3Rob2Nfc2lnX2ludGVyYWMpew0KICAgICAgY2F0KCJcbiBFZmZlY3Qgb2YgZ3JvdXAgYXQgZWFjaCB0aW1lIHBvaW50IC0gT25lLXdheSBBTk9WQVxuIikNCiAgICAgIG9uZV93YXkgPC0gDQogICAgICAgIGRhdGEgJT4lDQogICAgICAgIGdyb3VwX2J5KCEhdGltZV92YXJfZW5xKSAlPiUNCiAgICAgICAgYW5vdmFfdGVzdChkdiA9ICEhdmFsdWVfdmFyX2VucSwgd2lkID0gISFpZF92YXJfZW5xLCBiZXR3ZWVuID0gISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBnZXRfYW5vdmFfdGFibGUoKSAlPiUNCiAgICAgICAgYWRqdXN0X3B2YWx1ZShtZXRob2QgPSBwX2FkanVzdF9tZXRob2QpDQogICAgICBvbmVfd2F5ICU+JSBwcmludCgpDQogICAgICANCiAgICAgIGNhdCgiXG4gUGFpcndpc2UgY29tcGFyaXNvbnMgYmV0d2VlbiBncm91cCBsZXZlbHMgXG4iKQ0KICAgICAgcHdjIDwtIA0KICAgICAgICBkYXRhICU+JQ0KICAgICAgICBncm91cF9ieSghIXRpbWVfdmFyX2VucSkgJT4lDQogICAgICAgIHBhaXJ3aXNlX3RfdGVzdChhcy5mb3JtdWxhKHBhc3RlMCh2YWx1ZV92YXJfbmFtZSwgIiB+ICIsIGNvbmRfdmFyX25hbWUpKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QpDQogICAgICBwd2MgJT4lIHByaW50KCkNCiAgICAgIGNhdCgiXG4gRWZmZWN0IG9mIHRpbWUgYXQgZWFjaCBsZXZlbCBvZiBleGVyY2lzZXMgZ3JvdXAgIC0gT25lLXdheSBBTk9WQSBcbiIpDQogICAgICBvbmVfd2F5MiA8LSANCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgZ3JvdXBfYnkoISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBhbm92YV90ZXN0KGR2ID0gISF2YWx1ZV92YXJfZW5xLCB3aWQgPSAhIWlkX3Zhcl9lbnEsIHdpdGhpbiA9ICEhdGltZV92YXJfZW5xKSAlPiUNCiAgICAgICAgZ2V0X2Fub3ZhX3RhYmxlKCkgJT4lDQogICAgICAgIGFkanVzdF9wdmFsdWUobWV0aG9kID0gcF9hZGp1c3RfbWV0aG9kKQ0KICAgICAgb25lX3dheTIgJT4lIHByaW50KCkNCiAgICAgIA0KICAgICAgY2F0KCJcbiBQYWlyd2lzZSBjb21wYXJpc29ucyBiZXR3ZWVuIHRpbWUgcG9pbnRzIGF0IGVhY2ggZ3JvdXAgbGV2ZWxzICh3ZSBoYXZlIHJlcGVhdGVkIG1lYXN1cmVzIGJ5IHRpbWUpIFxuIikNCiAgICAgIHB3YzIgPC0NCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgZ3JvdXBfYnkoISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBwYWlyd2lzZV90X3Rlc3QoDQogICAgICAgICAgYXMuZm9ybXVsYShwYXN0ZTAodmFsdWVfdmFyX25hbWUsICIgfiAiLCB0aW1lX3Zhcl9uYW1lKSksICAgICAjIHBhc3RlIGZvcm11bGEsIG5vdCBxdW9zdXJlDQogICAgICAgICAgcGFpcmVkID0gVFJVRSwNCiAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QNCiAgICAgICAgKQ0KICAgICAgcHdjMiAgJT4lIHByaW50KCkNCiAgICB9DQogICAgDQogICAgIy0gUHJvY2VkdXJlIGZvciBub24tc2lnbmlmaWNhbnQgdHdvLXdheSBpbnRlcmFjdGlvbi0gDQogICAgIyBJZiB0aGUgaW50ZXJhY3Rpb24gaXMgbm90IHNpZ25pZmljYW50LCB5b3UgbmVlZCB0byBpbnRlcnByZXQgdGhlIG1haW4gZWZmZWN0cyBmb3IgZWFjaCBvZiB0aGUgdHdvIHZhcmlhYmxlczogdHJlYXRtZW50IGFuZCB0aW1lLg0KICAgIGlmKHBvc3Rob2NfbnNfaW50ZXJhYyl7DQogICAgICBjYXQoIlxuIENvbXBhcmlzb25zIGZvciB0cmVhdG1lbnQgdmFyaWFibGUgXG4iKQ0KICAgICAgcHdjX2NvbmQgPC0NCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgcGFpcndpc2VfdF90ZXN0KA0KICAgICAgICAgIGFzLmZvcm11bGEocGFzdGUwKHZhbHVlX3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpLCAgICAgIyBwYXN0ZSBmb3JtdWxhLCBub3QgcXVvc3VyZSAgICAgICAgICAgICANCiAgICAgICAgICBwYWlyZWQgPSBGQUxTRSwNCiAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QNCiAgICAgICAgKQ0KICAgICAgcHdjX2NvbmQgJT4lIHByaW50KCkNCiAgICAgIGNhdCgiXG4gQ29tcGFyaXNvbnMgZm9yIHRpbWUgdmFyaWFibGUgXG4iKQ0KICAgICAgcHdjX3RpbWUgPC0NCiAgICAgICAgZGF0YSAlPiUgDQogICAgICAgIHBhaXJ3aXNlX3RfdGVzdCgNCiAgICAgICAgICBhcy5mb3JtdWxhKHBhc3RlMCh2YWx1ZV92YXJfbmFtZSwgIiB+ICIsIHRpbWVfdmFyX25hbWUpKSwgICAgICMgcGFzdGUgZm9ybXVsYSwgbm90IHF1b3N1cmUNCiAgICAgICAgICBwYWlyZWQgPSBUUlVFLA0KICAgICAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9IHBfYWRqdXN0X21ldGhvZA0KICAgICAgICApDQogICAgICBwd2NfdGltZSAlPiUgcHJpbnQoKQ0KICAgIH0NCiAgICANCiAgICAjIFZpc3VhbGl6YXRpb24NCiAgICBieF9wbG90IDwtIA0KICAgICAgZ2dib3hwbG90KGRhdGEsIHggPSB0aW1lX3Zhcl9uYW1lLCB5ID0gdmFsdWVfdmFyX25hbWUsDQogICAgICAgICAgICAgICAgY29sb3IgPSBjb25kX3Zhcl9uYW1lLCBwYWxldHRlID0gImpjbyIpDQogICAgcHdjIDwtIA0KICAgICAgcHdjICU+JSANCiAgICAgIGFkZF94eV9wb3NpdGlvbih4ID0gdGltZV92YXJfbmFtZSkNCiAgICBieF9wbG90IDwtIA0KICAgICAgYnhfcGxvdCArIA0KICAgICAgc3RhdF9wdmFsdWVfbWFudWFsKHB3YywgdGlwLmxlbmd0aCA9IDAsIGhpZGUubnMgPSBUUlVFKSArDQogICAgICBsYWJzKA0KICAgICAgICBzdWJ0aXRsZSA9IGdldF90ZXN0X2xhYmVsKHJlc19hb3YsIGRldGFpbGVkID0gVFJVRSksDQogICAgICAgIGNhcHRpb24gPSBnZXRfcHdjX2xhYmVsKHB3YykNCiAgICAgICkNCiAgICANCiAgICBpZihhc3N1bV9jaGVjayl7IA0KICAgICAgbGlzdChxcV9wbG90LCBieF9wbG90KQ0KICAgIH1lbHNlew0KICAgICAgYnhfcGxvdA0KICAgIH0gDQogICAgDQogIH0NCg0KIyBleC4gLSBydW4gb24gbG9uZyBmb3JtYXQNCiMgdHdfbWl4ZWRBTk9WQV9mdW5jKGRhdGEgPSBhbnhpZXR5LCBpZF92YXIgPSBpZCwgY29uZF92YXIgPSBncm91cCwgdGltZV92YXIgPSB0aW1lLCB2YWx1ZV92YXIgPSBzY29yZSwNCiMgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KDQpgYGANCg0KDQoNCiMgUmVhZCwgQ2xlYW4sIFJlY29kZQ0KDQpgYGB7ciByZWFkX2NsZWFuX3JlY29kZV9tZXJnZSwgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0V9DQojfn5+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+fg0KIyBSZWFkLCBDbGVhbiwgUmVjb2RlLCBVbml0ZQ0KI35+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+fn4NCg0KIyMgUmVhZCBmaWxlcw0KZm9sZGVyIDwtICJDOi9Vc2Vycy9NaWhhaS9EZXNrdG9wL1IgTm90ZWJvb2tzL25vdGVib29rcy9NMi1yZXBvcnQiDQpmaWxlIDwtICJEYXRlTTIgZmluYWwueGxzeCINCg0Kc2V0d2QoZm9sZGVyKQ0KRGF0YV9wcmUgPC0gcmlvOjppbXBvcnQoZmlsZS5wYXRoKGZvbGRlciwgZmlsZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBza2lwID0gMywgd2hpY2ggPSAiTTIgUFJFIikNCg0KRGF0YV9wb3N0IDwtIHJpbzo6aW1wb3J0KGZpbGUucGF0aChmb2xkZXIsIGZpbGUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDMsIHdoaWNoID0gIk0yIFBPU1QiKQ0KDQoNCg0KIyBQUkUgPSBjb2xuYW1lcyhEYXRhX3ByZSk7IFBPU1QgPSBjb2xuYW1lcyhEYXRhX3Bvc3QpIA0KIyBjYmluZChQUkUsIFBPU1QpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyAiczEuNyIgdmFyIGlzIG1pc3NpbmcgZm9ybSBQT1NUIC0tIG1pc3NtYXRjaCByb3cgMTINCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYWxzbyBtaXNzaW5nICJzMi43IiBhbmQgb3RoZXJzDQoNCg0KIyBpbmRleCBmcm9tICJEYXRlTTIueGxzeCINCiMgaW5kZXhfcnlmZl9wcmUgPC0gOTQ6MTM1DQojIGluZGV4X3Bzc19wcmUgPC0gMTM2OjE0OQ0KIyBpbmRleF9yeWZmX3Bvc3QgPC0gOTQ6MTM1IC0gNQ0KIyBpbmRleF9wc3NfcG9zdCA8LSAxMzY6MTQ5IC0gNQ0KDQppbmRleF9yeWZmX3ByZSA8LSA4MzoxMjQNCmluZGV4X3Bzc19wcmUgPC0gMTI1OjEzOA0KaW5kZXhfcnlmZl9wb3N0IDwtIDgxOjEyMg0KaW5kZXhfcHNzX3Bvc3QgPC0gMTIzOjEzNg0KDQoNCmNvbG5hbWVzKERhdGFfcHJlKVsxXSA8LSAiSUQiDQpjb2xuYW1lcyhEYXRhX3ByZSlbY29sbmFtZXMoRGF0YV9wcmUpID09ICJTdHJlcyBwcmUiXSA8LSAiVkFTX3N0cmVzc19wcmUiDQpjb2xuYW1lcyhEYXRhX3ByZSlbY29sbmFtZXMoRGF0YV9wcmUpID09ICJTdHJlcyBwb3N0Il0gPC0gIlZBU19zdHJlc3NfcG9zdCINCmNvbG5hbWVzKERhdGFfcHJlKVtpbmRleF9yeWZmX3ByZV0gPC0gc3ByaW50ZigicnlmZl8lMDFkIiwgc2VxKDEsIDQyKSkNCmNvbG5hbWVzKERhdGFfcHJlKVtpbmRleF9wc3NfcHJlXSA8LSBzcHJpbnRmKCJwc3NfJTAxZCIsIHNlcSgxLCAxNCkpDQpEYXRhX3ByZSA8LQ0KICBEYXRhX3ByZSAlPiUNCiAgZHJvcF9uYShJRCkgJT4lDQogIGRwbHlyOjptdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBsaXN0KH5kcGx5cjo6bmFfaWYoLiwgIm5hIikpKSANCkRhdGFfcHJlW2luZGV4X3J5ZmZfcHJlXSA8LSBjb2xzdG9udW1lcmljKERhdGFfcHJlW2luZGV4X3J5ZmZfcHJlXSkNCkRhdGFfcHJlJHBzc184W0RhdGFfcHJlJHBzc184ID09ICIrKysrKysiXSA8LSBOQSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdHlwbw0KRGF0YV9wcmVbaW5kZXhfcHNzX3ByZV0gPC0gY29sc3RvbnVtZXJpYyhEYXRhX3ByZVtpbmRleF9wc3NfcHJlXSkNCg0KY29sbmFtZXMoRGF0YV9wb3N0KVsxXSA8LSAiSUQiDQpjb2xuYW1lcyhEYXRhX3Bvc3QpW2NvbG5hbWVzKERhdGFfcG9zdCkgPT0gIlN0cmVzIHByZSJdIDwtICJWQVNfc3RyZXNzX3ByZSINCmNvbG5hbWVzKERhdGFfcG9zdClbY29sbmFtZXMoRGF0YV9wb3N0KSA9PSAiU3RyZXMgcG9zdCJdIDwtICJWQVNfc3RyZXNzX3Bvc3QiDQpjb2xuYW1lcyhEYXRhX3Bvc3QpW2luZGV4X3J5ZmZfcG9zdF0gPC0gc3ByaW50ZigicnlmZl8lMDFkIiwgc2VxKDEsIDQyKSkNCmNvbG5hbWVzKERhdGFfcG9zdClbaW5kZXhfcHNzX3Bvc3RdIDwtIHNwcmludGYoInBzc18lMDFkIiwgc2VxKDEsIDE0KSkNCkRhdGFfcG9zdCA8LQ0KICBEYXRhX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBsaXN0KH5kcGx5cjo6bmFfaWYoLiwgIm5hIikpKSANCkRhdGFfcG9zdFtpbmRleF9yeWZmX3Bvc3RdIDwtIGNvbHN0b251bWVyaWMoRGF0YV9wb3N0W2luZGV4X3J5ZmZfcG9zdF0pDQpEYXRhX3Bvc3RbaW5kZXhfcHNzX3Bvc3RdIDwtIGNvbHN0b251bWVyaWMoRGF0YV9wb3N0W2luZGV4X3Bzc19wb3N0XSkNCg0KIyB0eXBvcw0KIyBjaGVja19udW1lcmljIDwtIGFzLmRhdGEuZnJhbWUoc2FwcGx5KERhdGFfcHJlW2luZGV4X3Bzc19wcmVdLCB2YXJoYW5kbGU6OmNoZWNrLm51bWVyaWMpKSANCiMgc2FwcGx5KGNoZWNrX251bWVyaWMsIGZ1bmN0aW9uKHgpIGxlbmd0aCh3aGljaCgheCkpKQ0KDQpjb2xuYW1lcyhEYXRhX3ByZSlbY29sbmFtZXMoRGF0YV9wcmUpID09ICJzMS4xLiJdIDwtICJzMS4xIg0KY29sbmFtZXMoRGF0YV9wb3N0KVtjb2xuYW1lcyhEYXRhX3Bvc3QpID09ICJzMS4xLiJdIDwtICJzMS4xIg0KDQpEYXRhX3Bvc3QkczIuMTBbd2hpY2goRGF0YV9wb3N0JHMyLjEwID09ICIuIildIDwtIE5BDQpEYXRhX3Bvc3QkczIuMTAgPC0gYXMubnVtZXJpYyhEYXRhX3Bvc3QkczIuMTApDQpEYXRhX3Bvc3QkczMuMTZbd2hpY2goRGF0YV9wb3N0JHMzLjE2ID09ICJrcSIpXSA8LSBOQQ0KRGF0YV9wb3N0JHMzLjE2IDwtIGFzLm51bWVyaWMoRGF0YV9wb3N0JHMzLjE2KQ0KDQpgYGANCg0KDQpgYGB7ciBzY29yaW5nLCByZXN1bHRzPSdoaWRlJ30NCiMjIFBTUy1TRiAxNCAobGlrZXJ0IDAtNCkNCiMgSXRlbXMgNCwgNSwgNiwgNywgOSwgMTAsIGFuZCAxMyBhcmUgc2NvcmVkIGluIHJldmVyc2UgZGlyZWN0aW9uLg0KDQppbmRleGl0ZW1fcmV2UFNTIDwtIGMoNCwgNSwgNiwgNywgOSwgMTAsIDEzKQ0KDQpEYXRhX3ByZVssIGluZGV4X3Bzc19wcmVdW2luZGV4aXRlbV9yZXZQU1NdIDwtIFJldmVyc2VDb2RlKERhdGFfcHJlWywgaW5kZXhfcHNzX3ByZV1baW5kZXhpdGVtX3JldlBTU10sIHRvbnVtZXJpYyA9IEZBTFNFLCBtaW4gPSAwLCBtYXggPSA0KQ0KRGF0YV9wb3N0WywgaW5kZXhfcHNzX3Bvc3RdW2luZGV4aXRlbV9yZXZQU1NdIDwtIFJldmVyc2VDb2RlKERhdGFfcG9zdFssIGluZGV4X3Bzc19wb3N0XVtpbmRleGl0ZW1fcmV2UFNTXSwgdG9udW1lcmljID0gRkFMU0UsIG1pbiA9IDAsIG1heCA9IDQpDQoNCkRhdGFfcHJlJFBTUyA8LSBTY29yZUxpa2VydChEYXRhX3ByZVssIGluZGV4X3Bzc19wcmVdLCBuYXBlcmNlbnQgPSAuNCkNCkRhdGFfcG9zdCRQU1MgPC0gU2NvcmVMaWtlcnQoRGF0YV9wb3N0WywgaW5kZXhfcHNzX3Bvc3RdLCBuYXBlcmNlbnQgPSAuNCkNCiAgDQoNCiMjIFJ5ZmYgKGxpa2VydCAxLTYpDQojIFJlY29kZSBuZWdhdGl2ZSBwaHJhc2VkIGl0ZW1zOiAgMyw1LDEwLDEzLDE0LDE1LDE2LDE3LDE4LDE5LDIzLDI2LDI3LDMwLDMxLDMyLDM0LDM2LDM5LDQxLg0KIyBBdXRvbm9teTogMSw3LDEzLDE5LDI1LDMxLDM3DQojIEVudmlyb25tZW50YWwgbWFzdGVyeTogMiw4LDE0LDIwLDI2LDMyLDM4DQojIFBlcnNvbmFsIEdyb3d0aDogMyw5LDE1LDIxLDI3LDMzLDM5DQojIFBvc2l0aXZlIFJlbGF0aW9uczogNCwxMCwxNiwyMiwyOCwzNCw0MA0KIyBQdXJwb3NlIGluIGxpZmU6IDUsMTEsMTcsMjMsMjksMzUsNDENCiMgU2VsZi1hY2NlcHRhbmNlOiA2LDEyLDE4LDI0LDMwLDM2LDQyDQoNCmluZGV4aXRlbV9yZXZSWUZGIDwtIGMoMyw1LDEwLDEzLDE0LDE1LDE2LDE3LDE4LDE5LDIzLDI2LDI3LDMwLDMxLDMyLDM0LDM2LDM5LDQxKQ0KDQpEYXRhX3ByZVssIGluZGV4X3J5ZmZfcHJlXVtpbmRleGl0ZW1fcmV2UllGRl0gPC0gUmV2ZXJzZUNvZGUoRGF0YV9wcmVbLCBpbmRleF9yeWZmX3ByZV1baW5kZXhpdGVtX3JldlJZRkZdLCB0b251bWVyaWMgPSBGQUxTRSwgbWluID0gMSwgbWF4ID0gNikNCkRhdGFfcG9zdFssIGluZGV4X3J5ZmZfcG9zdF1baW5kZXhpdGVtX3JldlJZRkZdIDwtIFJldmVyc2VDb2RlKERhdGFfcG9zdFssIGluZGV4X3J5ZmZfcG9zdF1baW5kZXhpdGVtX3JldlJZRkZdLCB0b251bWVyaWMgPSBGQUxTRSwgbWluID0gMSwgbWF4ID0gNikNCg0KaW5kZXhpdGVtX0F1dG8gPC0gYygxLDcsMTMsMTksMjUsMzEsMzcpDQppbmRleGl0ZW1fRW52TSA8LSBjKDIsOCwxNCwyMCwyNiwzMiwzOCkNCmluZGV4aXRlbV9QZXJzRyA8LSBjKDMsOSwxNSwyMSwyNywzMywzOSkNCmluZGV4aXRlbV9Qb3NSZWwgPC0gYyg0LDEwLDE2LDIyLDI4LDM0LDQwKQ0KaW5kZXhpdGVtX1B1ckxpZiA8LSBjKDUsMTEsMTcsMjMsMjksMzUsNDEpDQppbmRleGl0ZW1fU2VsZkFjIDwtIGMoNiwxMiwxOCwyNCwzMCwzNiw0MikNCg0KDQpEYXRhX3ByZSRBdXRvIDwtIFNjb3JlTGlrZXJ0KERhdGFfcHJlWywgaW5kZXhfcnlmZl9wcmVdW2luZGV4aXRlbV9BdXRvXSwgbmFwZXJjZW50ID0gLjQpDQpEYXRhX3ByZSRFbnZNIDwtIFNjb3JlTGlrZXJ0KERhdGFfcHJlWywgaW5kZXhfcnlmZl9wcmVdW2luZGV4aXRlbV9FbnZNXSwgbmFwZXJjZW50ID0gLjQpDQpEYXRhX3ByZSRQZXJzRyA8LSBTY29yZUxpa2VydChEYXRhX3ByZVssIGluZGV4X3J5ZmZfcHJlXVtpbmRleGl0ZW1fUGVyc0ddLCBuYXBlcmNlbnQgPSAuNCkNCkRhdGFfcHJlJFBvc1JlbCA8LSBTY29yZUxpa2VydChEYXRhX3ByZVssIGluZGV4X3J5ZmZfcHJlXVtpbmRleGl0ZW1fUG9zUmVsXSwgbmFwZXJjZW50ID0gLjQpDQpEYXRhX3ByZSRQdXJMaWYgPC0gU2NvcmVMaWtlcnQoRGF0YV9wcmVbLCBpbmRleF9yeWZmX3ByZV1baW5kZXhpdGVtX1B1ckxpZl0sIG5hcGVyY2VudCA9IC40KQ0KRGF0YV9wcmUkU2VsZkFjIDwtIFNjb3JlTGlrZXJ0KERhdGFfcHJlWywgaW5kZXhfcnlmZl9wcmVdW2luZGV4aXRlbV9TZWxmQWNdLCBuYXBlcmNlbnQgPSAuNCkNCg0KRGF0YV9wb3N0JEF1dG8gPC0gU2NvcmVMaWtlcnQoRGF0YV9wb3N0WywgaW5kZXhfcnlmZl9wb3N0XVtpbmRleGl0ZW1fQXV0b10sIG5hcGVyY2VudCA9IC40KQ0KRGF0YV9wb3N0JEVudk0gPC0gU2NvcmVMaWtlcnQoRGF0YV9wb3N0WywgaW5kZXhfcnlmZl9wb3N0XVtpbmRleGl0ZW1fRW52TV0sIG5hcGVyY2VudCA9IC40KQ0KRGF0YV9wb3N0JFBlcnNHIDwtIFNjb3JlTGlrZXJ0KERhdGFfcG9zdFssIGluZGV4X3J5ZmZfcG9zdF1baW5kZXhpdGVtX1BlcnNHXSwgbmFwZXJjZW50ID0gLjQpDQpEYXRhX3Bvc3QkUG9zUmVsIDwtIFNjb3JlTGlrZXJ0KERhdGFfcG9zdFssIGluZGV4X3J5ZmZfcG9zdF1baW5kZXhpdGVtX1Bvc1JlbF0sIG5hcGVyY2VudCA9IC40KQ0KRGF0YV9wb3N0JFB1ckxpZiA8LSBTY29yZUxpa2VydChEYXRhX3Bvc3RbLCBpbmRleF9yeWZmX3Bvc3RdW2luZGV4aXRlbV9QdXJMaWZdLCBuYXBlcmNlbnQgPSAuNCkNCkRhdGFfcG9zdCRTZWxmQWMgPC0gU2NvcmVMaWtlcnQoRGF0YV9wb3N0WywgaW5kZXhfcnlmZl9wb3N0XVtpbmRleGl0ZW1fU2VsZkFjXSwgbmFwZXJjZW50ID0gLjQpDQoNCiMjIFNhdmUgU2NvcmVzDQojIHJpbzo6ZXhwb3J0KERhdGFfcHJlWywgYygxLCAxNTA6MTU2KV0pDQojIHJpbzo6ZXhwb3J0KERhdGFfcG9zdFssIGMoMSwgMTQ5OjE1NSldKQ0KIyBubGFzdGNvbCA8LSA3DQojIHJpbzo6ZXhwb3J0KGxpc3QoUFJFID0gRGF0YV9wcmVbLCBjKDEsIChuY29sKERhdGFfcHJlKS1ubGFzdGNvbCsxKTpuY29sKERhdGFfcHJlKSldLCBQT1NUID0gRGF0YV9wb3N0WywgYygxLCAobmNvbChEYXRhX3Bvc3QpLW5sYXN0Y29sKzEpOm5jb2woRGF0YV9wb3N0KSldKSwgDQojICAgICAgICAgICAgICJNMiBQU1MgUnlmZiBmaW5hbC54bHN4IikNCg0KRGF0YV9wcmUkUzFfTWVhbiA8LSByb3dNZWFucyhEYXRhX3ByZVssIHNwcmludGYoInMxLiVkIiwgYygxOjYsIDg6MTYpKV0sIG5hLnJtID0gVFJVRSkgICMgRGF0YV9wcmVbLCBncmVwKCJzMS4iLCBjb2xuYW1lcyhEYXRhX3ByZSkpXQ0KRGF0YV9wcmUkUzJfTWVhbiA8LSByb3dNZWFucyhEYXRhX3ByZVssIHNwcmludGYoInMyLiVkIiwgYygxOjYsIDg6MTYpKV0sIG5hLnJtID0gVFJVRSkgICMgRGF0YV9wcmVbLCBncmVwKCJzMi4iLCBjb2xuYW1lcyhEYXRhX3ByZSkpXQ0KRGF0YV9wcmUkUzNfTWVhbiA8LSByb3dNZWFucyhEYXRhX3ByZVssIHNwcmludGYoInMzLiVkIiwgYygxOjYsIDg6MTYpKV0sIG5hLnJtID0gVFJVRSkgICMgRGF0YV9wcmVbLCBncmVwKCJzMy4iLCBjb2xuYW1lcyhEYXRhX3ByZSkpXQ0KDQpEYXRhX3Bvc3QkUzFfTWVhbiA8LSByb3dNZWFucyhEYXRhX3Bvc3RbLCBzcHJpbnRmKCJzMS4lZCIsIGMoMTo2LCA4OjE2KSldLCBuYS5ybSA9IFRSVUUpICAjIERhdGFfcG9zdFssIGdyZXAoInMxLiIsIGNvbG5hbWVzKERhdGFfcG9zdCkpXQ0KRGF0YV9wb3N0JFMyX01lYW4gPC0gcm93TWVhbnMoRGF0YV9wb3N0Wywgc3ByaW50ZigiczIuJWQiLCBjKDE6NiwgODoxNikpXSwgbmEucm0gPSBUUlVFKSAgIyBEYXRhX3Bvc3RbLCBncmVwKCJzMi4iLCBjb2xuYW1lcyhEYXRhX3Bvc3QpKV0NCkRhdGFfcG9zdCRTM19NZWFuIDwtIHJvd01lYW5zKERhdGFfcG9zdFssIHNwcmludGYoInMzLiVkIiwgYygxOjYsIDg6MTYpKV0sIG5hLnJtID0gVFJVRSkgICMgRGF0YV9wb3N0WywgZ3JlcCgiczMuIiwgY29sbmFtZXMoRGF0YV9wb3N0KSldDQpgYGANCg0KDQojIEFkZCBUUiAmIENUUkwgZ3JvdXBzDQoNCmBgYHtyIGNvbmRncm91cHNfZGZ9DQp0cl9pZHMgPC0gcGFzdGUwKGMoMSwgMiwgNCwgNSwgNiwgMTAsIDEzLCAxNCwgMTUsIDE2LCAyNCwgMjUsIDI2LCAzMiwgMzQsIDM1LCAzOSwgNDAsIDQyLCA0NiwgNDcsIDQ4LCA1MSwgNTMsIDU5LCA2MCwgNjIsIDYzLCA2NCksICIgTTIiKSANCmN0cmxfaWRzIDwtIHBhc3RlMChjKDMsIDcsIDgsIDksIDExLCAxMiwgMTcsIDE4LCAxOSwgMjAsIDIxLCAyMiwgMjMsIDI3LCAyOCwgMzAsIDMzLCAzNiwgMzcsIDM4LCA0MSwgNDMsIDQ1LCA0OSwgNTIsIDU0LCA1NSwgNTYsIDU3LCA1OCksICIgTTIiKSANCiMgU3ViaiBmcm9tIFRSOiBEYXRhX3ByZVt3aGljaChEYXRhX3ByZSRJRCAlaW4lIHRyX2lkcyksXSAgDQojIFN1YmogZnJvbSBDVFJMOiBEYXRhX3ByZVt3aGljaChEYXRhX3ByZSRJRCAlaW4lIGN0cmxfaWRzKSxdIA0KDQpEYXRhX3ByZSRDb25kIDwtIGRwbHlyOjpjYXNlX3doZW4oRGF0YV9wcmUkSUQgJWluJSB0cl9pZHMgfiAiVFIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERhdGFfcHJlJElEICVpbiUgY3RybF9pZHMgfiAiQ1RSTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pDQpEYXRhX3Bvc3QkQ29uZCA8LSBkcGx5cjo6Y2FzZV93aGVuKERhdGFfcG9zdCRJRCAlaW4lIHRyX2lkcyB+ICJUUiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0YV9wb3N0JElEICVpbiUgY3RybF9pZHMgfiAiQ1RSTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pDQpgYGANCg0KDQojIEFkZCBDb3VudC12YXJzICYgUG9zdC1WYXJzDQoNCmBgYHtyIHBvc3RfdmFyc30NCm5hbWVzKERhdGFfcG9zdClbMTM3OjEzOV0gPC0gYygic3BvbnRhbmVvdXMiLCAidm9sdW50YXJ5IiwgImRyZWFtcyIpDQoNCkRhdGFfcHJlJHMxLmNvdW50IDwtIHJvd1N1bXMoIWlzLm5hKERhdGFfcHJlWywgZ3JlcGwoInMxLioiLCBuYW1lcyhEYXRhX3ByZSkpXSkpDQpEYXRhX3ByZSRzMi5jb3VudCA8LSByb3dTdW1zKCFpcy5uYShEYXRhX3ByZVssIGdyZXBsKCJzMS4qIiwgbmFtZXMoRGF0YV9wcmUpKV0pKSAgIA0KRGF0YV9wcmUkczMuY291bnQgPC0gcm93U3VtcyghaXMubmEoRGF0YV9wcmVbLCBncmVwbCgiczMuKiIsIG5hbWVzKERhdGFfcHJlKSldKSkNCg0KRGF0YV9wb3N0JHMxLmNvdW50IDwtIHJvd1N1bXMoIWlzLm5hKERhdGFfcG9zdFssIGdyZXBsKCJzMS4qIiwgbmFtZXMoRGF0YV9wb3N0KSldKSkNCkRhdGFfcG9zdCRzMi5jb3VudCA8LSByb3dTdW1zKCFpcy5uYShEYXRhX3Bvc3RbLCBncmVwbCgiczEuKiIsIG5hbWVzKERhdGFfcG9zdCkpXSkpICAgICMgZm9yIHNvbWUgcmVhc29uIGl0IGhhcyArMSBjb3VudCBmcm9tIGFsbCByZXN0DQpEYXRhX3Bvc3QkczMuY291bnQgPC0gcm93U3VtcyghaXMubmEoRGF0YV9wb3N0WywgZ3JlcGwoInMzLioiLCBuYW1lcyhEYXRhX3Bvc3QpKV0pKQ0KYGBgDQoNCg0KDQojIFVuaXRlIGRhdGEgZnJhbWVzDQoNCmBgYHtyIHVuaXRlX2RmfQ0KY2F0KCIjIyBOdW1iZXIgb2Ygc3ViamVjdHMgaW4gcHJlIikNCkRhdGFfcHJlICU+JSANCiBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gZHBseXI6Om5fZGlzdGluY3QoSUQpKQ0KDQpjYXQoIiMjIE51bWJlciBvZiBzdWJqZWN0cyBpbiBwb3N0IikNCkRhdGFfcG9zdCAlPiUNCiBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gZHBseXI6Om5fZGlzdGluY3QoSUQpKQ0KDQpEYXRhX3ByZSRQcmVQb3N0IDwtIHJlcCgiUHJlIiwgbnJvdyhEYXRhX3ByZSkpDQpEYXRhX3Bvc3QkUHJlUG9zdCA8LSByZXAoIlBvc3QiLCBucm93KERhdGFfcG9zdCkpDQoNCkRhdGFfcHJlX3NjYWxlcyA8LSBEYXRhX3ByZVssIGMoIklEIiwgIlZhcnN0YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWQVNfc3RyZXNzX3ByZSIsICJWQVNfc3RyZXNzX3Bvc3QiLCAiUFNTIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBdXRvIiwgIkVudk0iLCAiUGVyc0ciLCAiUG9zUmVsIiwgIlB1ckxpZiIsICAiU2VsZkFjIiwgIlMxX01lYW4iLCAiUzJfTWVhbiIsICJTM19NZWFuIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQcmVQb3N0IiwgIkNvbmQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiczEuY291bnQiLCAiczIuY291bnQiLCAiczMuY291bnQiKV0NCkRhdGFfcG9zdF9zY2FsZXMgPC0gRGF0YV9wb3N0WywgYygiSUQiLCAiVmFyc3RhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVkFTX3N0cmVzc19wcmUiLCAiVkFTX3N0cmVzc19wb3N0IiwgIlBTUyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBdXRvIiwgIkVudk0iLCAiUGVyc0ciLCAiUG9zUmVsIiwgIlB1ckxpZiIsICAiU2VsZkFjIiwgIlMxX01lYW4iLCAiUzJfTWVhbiIsICJTM19NZWFuIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlByZVBvc3QiLCAiQ29uZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInMxLmNvdW50IiwgInMyLmNvdW50IiwgInMzLmNvdW50IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3BvbnRhbmVvdXMiLCAidm9sdW50YXJ5IiwgImRyZWFtcyIpXQ0KDQpEYXRhX3VuaWZfbG9uZyA8LSBkcGx5cjo6YmluZF9yb3dzKERhdGFfcHJlX3NjYWxlcywgRGF0YV9wb3N0X3NjYWxlcykNCkRhdGFfdW5pZl93aWRlIDwtDQogIERhdGFfdW5pZl9sb25nICU+JQ0KICB0aWR5cjo6cGl2b3Rfd2lkZXIoaWRfY29scyA9IElELCBuYW1lc19mcm9tID0gUHJlUG9zdCwgdmFsdWVzX2Zyb20gPSBjKFZBU19zdHJlc3NfcHJlLCBWQVNfc3RyZXNzX3Bvc3QsIFBTUywgQXV0bywgRW52TSwgUGVyc0csIFBvc1JlbCwgUHVyTGlmLCBTZWxmQWMsIENvbmQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFMxX01lYW4sIFMyX01lYW4sIFMzX01lYW4sIHMxLmNvdW50LCBzMi5jb3VudCwgczMuY291bnQsIHNwb250YW5lb3VzLCB2b2x1bnRhcnksIGRyZWFtcykpDQoNCkRhdGFfdW5pZl9sb25nIDwtDQogIERhdGFfdW5pZl9sb25nICU+JQ0KICAgIGRwbHlyOjptdXRhdGUoSUQgPSBhcy5mYWN0b3IoSUQpLA0KICAgICAgICAgICAgICAgICAgQ29uZCA9IGFzLmZhY3RvcihDb25kKSwNCiAgICAgICAgICAgICAgICAgIFByZVBvc3QgPSBhcy5mYWN0b3IoUHJlUG9zdCkpICU+JQ0KICAgZHBseXI6Om11dGF0ZShWYXNfRGlmZiA9IFZBU19zdHJlc3NfcG9zdCAtIFZBU19zdHJlc3NfcHJlLA0KICAgICAgICAgICAgICAgICBWYXNfTWVhbiA9IHJvd01lYW5zKGRwbHlyOjpzZWxlY3QoLmRhdGEgPSAuLCBWQVNfc3RyZXNzX3Bvc3QsIFZBU19zdHJlc3NfcHJlKSwgbmEucm0gPSBUUlVFKSkNCg0KDQoNCg0KIyBFeHBvcnQgZGF0YQ0KIyByaW86OmV4cG9ydChEYXRhX3VuaWZfd2lkZSwgIk0yIHdpZGVfZm9ybWF0XzIueGxzeCIpDQojIHJpbzo6ZXhwb3J0KERhdGFfdW5pZl9sb25nLCAiTTIgbG9uZ19mb3JtYXRfMi54bHN4IikNCg0KDQojIEV4cG9ydCBkYXRhIGZvciBSTU4gaW4gc3BlY2lmaWVkIG9yZGVyDQojIHJtbl9vcmRlcl9pZHMgPC0gcGFzdGUwKGMoMSwgMTQsIDEzLCA2LCA0LCA1LCAxMCwgMTUsIDIsIDE2LCA0MiwgMzQsIDI0LCAyNSwgMjYsIDM1LCAzOSwgNDAsIDMyLCA1OSwgNTMsIDY0LCA0NiwgNDcsIDYyLCA2MywgNDgsIDUxLCA2MCwNCiMgICAgICAgICAgICAgICAgICAgIDgsIDIwLCAxMiwgMTgsIDksIDE3LCAxOSwgNywgMywgNDMsIDQxLCAyNywgMjMsIDM4LCAyMiwgMzMsIDI4LCAzMCwgMjEsIDM3LCA0OSwgNTYsIDU4LCA1NywgNTIsIDQ1LCA1NSwgNTQpLCAiICIsICJNMiIpDQojIA0KIyBSTU5fZGYgPC0gRGF0YV91bmlmX3dpZGVbbWF0Y2gocm1uX29yZGVyX2lkcywgRGF0YV91bmlmX3dpZGUkSUQpLF0gICAgIyBvbmx5IDU3IHN1YmpzIGZvciBSTU4NCiMgDQojIHJpbzo6ZXhwb3J0KFJNTl9kZiwgIlJNTiBvcmRlcmVkIE0yIHdpZGVfZm9ybWF0XzIueGxzeCIpDQpgYGANCg0KDQojIyBSZWFkIE5Ga0INCg0KYGBge3IgcmVhZF9uZmtiLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0NCiN+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+fn5+DQojIFJlYWQsIENsZWFuLCBSZWNvZGUsIFVuaXRlDQojfn5+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+fg0KDQojIyBSZWFkIGZpbGVzDQpmb2xkZXIgPC0gIkM6L1VzZXJzL01paGFpL0Rlc2t0b3AvUiBOb3RlYm9va3Mvbm90ZWJvb2tzL00yLXJlcG9ydCINCmZpbGUgPC0gImxpc3RhX00yIGN1IHJlenVsdGF0ZSBORmtCLnhsc3giDQoNCnNldHdkKGZvbGRlcikNCg0KRGF0YV9uZmtiX1RSIDwtICByZWFkeGw6OnJlYWRfeGxzeChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlID0gIkExOkYzMCIsIHNoZWV0ID0gIk5Ga0IiKQ0KRGF0YV9uZmtiX0NUUkwgPC0gIHJlYWR4bDo6cmVhZF94bHN4KGZpbGUucGF0aChmb2xkZXIsIGZpbGUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5nZSA9ICJIMTpNMzEiLCBzaGVldCA9ICJORmtCIikNCg0KRGF0YV9uZmtiX1RSIDwtIERhdGFfbmZrYl9UUlstMSwgXQ0KY29sbmFtZXMoRGF0YV9uZmtiX1RSKVtjKDEsIDQsIDYpXSA8LSBjKCJJRCIsICJORmtCX1ByZSIsICJORmtCX1Bvc3QiKQ0KRGF0YV9uZmtiX1RSIDwtIA0KICBEYXRhX25ma2JfVFIgJT4lDQogIGRwbHlyOjpyZW5hbWVfYWxsKH5zdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoLiwgIiAiLCAiXyIpKSAlPiUNCiAgZHBseXI6OnNlbGVjdCgtc3RhcnRzX3dpdGgoIklEX1BhcmhvbiIpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShDb25kID0gcmVwKCJUUiIsIG5yb3coRGF0YV9uZmtiX1RSKSkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKElEID0gc3RyaW5ncjo6c3RyX3JlbW92ZShJRCwgIklEIikpICU+JQ0KICBkcGx5cjo6bXV0YXRlKElEID0gc3RyaW5ncjo6c3RyX3JlbW92ZShJRCwgIiAiKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoSUQgPSBzdHJpbmdyOjpzdHJfYyhJRCwgIiBNMiIpKQ0KICANCg0KRGF0YV9uZmtiX0NUUkwgPC0gRGF0YV9uZmtiX0NUUkxbLTEsIF0NCmNvbG5hbWVzKERhdGFfbmZrYl9DVFJMKVtjKDEsIDQsIDYpXSA8LSBjKCJJRCIsICJORmtCX1ByZSIsICJORmtCX1Bvc3QiKQ0KRGF0YV9uZmtiX0NUUkwgPC0gDQogIERhdGFfbmZrYl9DVFJMICU+JQ0KICBkcGx5cjo6cmVuYW1lX2FsbCh+c3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKC4sICIgIiwgIl8iKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLXN0YXJ0c193aXRoKCJJRF9QYXJob24iKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoQ29uZCA9IHJlcCgiQ1RSTCIsIG5yb3coRGF0YV9uZmtiX0NUUkwpKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoSUQgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlKElELCAiSUQiKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoSUQgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlKElELCAiICIpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShJRCA9IHN0cmluZ3I6OnN0cl9jKElELCAiIE0yIikpDQpgYGANCg0KDQojIFVuaXRlIHdpdGggbmZrYg0KYGBge3IgdW5pdGVfZGZfbmZrYn0NCiMgY2hlY2sNCmFsbC5lcXVhbChjb2xuYW1lcyhEYXRhX25ma2JfVFIpLCBjb2xuYW1lcyhEYXRhX25ma2JfQ1RSTCkpDQoNCkRhdGFfdW5pZl93aWRlMiA8LSBkcGx5cjo6bGVmdF9qb2luKERhdGFfdW5pZl93aWRlLCByYmluZChEYXRhX25ma2JfVFIsIERhdGFfbmZrYl9DVFJMKSwgYnkgPSAiSUQiKQ0KDQojIGNoZWNrDQphbGwuZXF1YWwoRGF0YV91bmlmX3dpZGUyJENvbmRfUHJlLCBEYXRhX3VuaWZfd2lkZTIkQ29uZCkNCg0KRGF0YV91bmlmX3dpZGUyIDwtIA0KICBEYXRhX3VuaWZfd2lkZTIgJT4lDQogIGRwbHlyOjpzZWxlY3QoLWMoTnVtZV9zdWJpZWN0LCBDb25kKSkNCmBgYA0KDQoNCiMgTmZLQg0KYGBge3IgbmZrYl90dGVzdH0NCmZ1bmNfdF9ib3goRGF0YV9uZmtiX1RSLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIk5Ga0JfUHJlIiwgcG9zdF92YXIgPSAiTkZrQl9Qb3N0IikNCg0KRGF0YV9uZmtiX1RSICU+JQ0KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSBjKE5Ga0JfUHJlLCBORmtCX1Bvc3QpLCBuYW1lc190byA9ICJQcmVQb3N0IiwgdmFsdWVzX3RvID0gIk5Ga0IiKSAlPiUNCiAgcnN0YXRpeDo6d2lsY294X3Rlc3QoTkZrQiB+IFByZVBvc3QsIHBhaXJlZCA9IFRSVUUpICU+JQ0KICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCkNCg0KZnVuY190X2JveChEYXRhX25ma2JfQ1RSTCwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJORmtCX1ByZSIsIHBvc3RfdmFyID0gIk5Ga0JfUG9zdCIpDQoNCkRhdGFfbmZrYl9DVFJMICU+JQ0KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSBjKE5Ga0JfUHJlLCBORmtCX1Bvc3QpLCBuYW1lc190byA9ICJQcmVQb3N0IiwgdmFsdWVzX3RvID0gIk5Ga0IiKSAlPiUNCiAgcnN0YXRpeDo6d2lsY294X3Rlc3QoTkZrQiB+IFByZVBvc3QsIHBhaXJlZCA9IFRSVUUpICU+JQ0KICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCkNCmBgYA0KDQoNCg0KIyMgTmV3IElkZWFzOiBDb3JyZWxhdGlvbnMgTnVtYmVyIG9mIG1lbW9yaWVzICYgcmVtZW1iZXJpbmcNCg0KYGBge3IgY29yX21lbW9yeSwgZmlnLmhlaWdodD01LCBmaWcuaGVpZ2h0PTZ9DQpjYXQoIlBSRS1QT1NUIENvbXBhcmlzb25zIGJ5IENvbmQ6IFRSIikNCkRhdGFfdW5pZl9sb25nICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lIA0KICByc3RhdGl4Ojp3aWxjb3hfdGVzdChzMS5jb3VudCB+IFByZVBvc3QsIHBhaXJlZCA9IFRSVUUpICU+JQ0KICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCkNCg0KY2F0KCIjIyBQUkUtUE9TVCBDb21wYXJpc29ucyBieSBDb25kOiBDVFJMIikNCkRhdGFfdW5pZl9sb25nICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUgDQogIHJzdGF0aXg6OndpbGNveF90ZXN0KHMxLmNvdW50IH4gUHJlUG9zdCwgcGFpcmVkID0gVFJVRSkgJT4lDQogIHJzdGF0aXg6OmFkZF9zaWduaWZpY2FuY2UoKQ0KDQpjYXQoIiMjIFBPU1QtdmFycyBDb21wYXJpc29ucyBieSBDb25kIikNCkRhdGFfdW5pZl9sb25nICU+JQ0KICBkcGx5cjo6ZmlsdGVyKFByZVBvc3QgPT0gIlBvc3QiKSAlPiUNCiAgcnN0YXRpeDo6d2lsY294X3Rlc3QoczEuY291bnQgfiBDb25kLCBwYWlyZWQgPSBGQUxTRSkgJT4lDQogIHJzdGF0aXg6OmFkZF9zaWduaWZpY2FuY2UoKQ0KDQpEYXRhX3VuaWZfbG9uZyAlPiUNCiAgZHBseXI6OmZpbHRlcihQcmVQb3N0ID09ICJQb3N0IikgJT4lIA0KICAgIHJzdGF0aXg6OnRfdGVzdChzMS5jb3VudCB+IENvbmQsIHBhaXJlZCA9IEZBTFNFKSAlPiUNCiAgICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCkNCg0KRGF0YV91bmlmX2xvbmcgJT4lDQogIGRwbHlyOjpmaWx0ZXIoUHJlUG9zdCA9PSAiUG9zdCIpICU+JQ0KICByc3RhdGl4Ojp3aWxjb3hfdGVzdCh2b2x1bnRhcnkgfiBDb25kLCBwYWlyZWQgPSBGQUxTRSkgJT4lDQogIHJzdGF0aXg6OmFkZF9zaWduaWZpY2FuY2UoKSAgICAgICAgICAgICAgICAgICANCg0KRGF0YV91bmlmX2xvbmcgJT4lDQogIGRwbHlyOjpmaWx0ZXIoUHJlUG9zdCA9PSAiUG9zdCIpICU+JQ0KICAgIHJzdGF0aXg6OnRfdGVzdCh2b2x1bnRhcnkgfiBDb25kLCBwYWlyZWQgPSBGQUxTRSkgJT4lDQogICAgcnN0YXRpeDo6YWRkX3NpZ25pZmljYW5jZSgpDQoNCmNhdCgiIyMgQ29ycmVsYXRpb24gLSB3aG9sZSBzYW1wbGUiKQ0KRGF0YV91bmlmX2xvbmcgJT4lDQogIGRwbHlyOjpmaWx0ZXIoUHJlUG9zdCA9PSAiUG9zdCIpICU+JQ0KICBkcGx5cjo6c2VsZWN0KHMxLmNvdW50LCBzcG9udGFuZW91cywgdm9sdW50YXJ5LCBkcmVhbXMpICU+JSANCiAgUGVyZm9ybWFuY2VBbmFseXRpY3M6OmNoYXJ0LkNvcnJlbGF0aW9uKCkNCg0KY2F0KCIjIyBDb3JyZWxhdGlvbiAtIFRSIikNCkRhdGFfdW5pZl9sb25nICU+JQ0KICBkcGx5cjo6ZmlsdGVyKFByZVBvc3QgPT0gIlBvc3QiKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBkcGx5cjo6c2VsZWN0KHMxLmNvdW50LCBzcG9udGFuZW91cywgdm9sdW50YXJ5LCBkcmVhbXMpICU+JSANCiAgUGVyZm9ybWFuY2VBbmFseXRpY3M6OmNoYXJ0LkNvcnJlbGF0aW9uKCkNCg0KY2F0KCIjIyBDb3JyZWxhdGlvbiAtIENUUkwiKQ0KRGF0YV91bmlmX2xvbmcgJT4lDQogIGRwbHlyOjpmaWx0ZXIoUHJlUG9zdCA9PSAiUG9zdCIpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZHBseXI6OnNlbGVjdChzMS5jb3VudCwgc3BvbnRhbmVvdXMsIHZvbHVudGFyeSwgZHJlYW1zKSAlPiUgDQogIFBlcmZvcm1hbmNlQW5hbHl0aWNzOjpjaGFydC5Db3JyZWxhdGlvbigpDQpgYGANCg0KIyBEYXRhIGluIHdpZGUgZm9ybWF0DQoNCmBgYHtyfQ0KRGF0YV91bmlmX3dpZGUyICU+JQ0KICAgIERUOjpkYXRhdGFibGUoDQogICAgICBleHRlbnNpb25zID0gJ0J1dHRvbnMnLA0KICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLA0KICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWD0nNTAwcHgnLA0KICAgICAgICAgICAgICAgICAgICAgZG9tID0gJ0JmcnRpcCcsDQogICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygnZXhjZWwnLCAiY3N2IikpKQ0KDQpgYGANCg0KDQo8IS0tIFNlc3Npb24gSW5mbyBhbmQgTGljZW5zZSAtLT4NCg0KPGJyPg0KDQojIFNlc3Npb24gSW5mbw0KYGBge3Igc2Vzc2lvbl9pbmZvLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnbWFya3VwJ30NCnNlc3Npb25JbmZvKCkgICAgDQpgYGANCg0KPCEtLSBGb290ZXIgLS0+DQombmJzcDsNCjxociAvPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPkEgd29yayBieSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vQ2xhdWRpdVBhcGFzdGVyaS8iPkNsYXVkaXUgUGFwYXN0ZXJpPC9hPjwvcD4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48c3BhbiBzdHlsZT0iY29sb3I6ICM4MDgwODA7Ij48ZW0+Y2xhdWRpdS5wYXBhc3RlcmlAZ21haWwuY29tPC9lbT48L3NwYW4+PC9wPg0KJm5ic3A7DQo=