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)
}
samplesize_pairedttest <- function(df, pre_var, post_var){
vars <- c(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(Cond = factor(Cond, levels = c(pre_var, post_var)))
cat("## Cohen's d \n")
eff_size_table <-
df_modif %>%
cohens_d(value ~ Cond, paired = TRUE) %>%
print()
eff_size <- as.numeric(eff_size_table$effsize)
cat("## Sample Size estimation \n")
sample_size_table <-
pwr::pwr.t.test(d = eff_size, sig.level = .05, power = .8, type = "paired", alternative = "two.sided")
sample_size_table %>% broom::tidy() %>% print()
plot(sample_size_table)
}
# 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/PA4-report"
file <- "Date_pt_analiza_PA4online.xlsx"
setwd(folder)
# ID df
id_df <- rio::import(file.path(folder, file),
skip = 1, which = "ID-uri atribuite")
id_df <-
id_df %>%
dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) # remove white spaces
all(id_df$ID == toupper(id_df$ID)) # check if all are upper case
firstform_df <- rio::import(file.path(folder, file),
skip = 0, which = "Formular de înscriere și consim")
colnames(firstform_df)[7] <- "e-mail"
baseline_df <- dplyr::left_join(id_df, firstform_df, by = "e-mail")
baseline_df <- baseline_df[, c(4:9, 2, 10:ncol(baseline_df), 1,3)] # move cols from id_df to back so we have matching cols index for baseline_df & firstform_df
all.equal(colnames(baseline_df)[1:72], colnames(firstform_df)[1:72]) # check if colnames match, except ID and name that where added
table(baseline_df$ID) # ID 9C is doubled, completed 2 times
which(baseline_df$ID == "9C") # ID 9C row 27 is partially completed, excuted it
baseline_df <- baseline_df[-27 ,]
## Settings
cutoffPCL <- 32 # literature: 31-33 or 38
algPCL <- data.frame(B = 1, C = 1, D = 2, E = 2)
algPCL_subclin <- data.frame(B = 1, C = 1, D = 1, E = 1)
cutoffMBI_Ex <- 2.20
cutoffMBI_Cy <- 2
##
## Data
Data <- baseline_df
##
# Define column index: index = col index; itemindex = index of item in questionnaire
indexSIG <- 60:67 - 10 # modified in new table by 10
indexMBI <- 68:83 - 10
indexPCL <- 159:178 - 10
itemindexMBI_Ex <- c(1, 3, 5, 11, 14)
itemindexMBI_Cy <- c(2, 7, 8, 13, 15)
itemindexMBI_Pe <- c(4, 6, 9, 10, 12, 16)
# Rename columns
# names(Data)[1:12] <- stringr::str_replace_all(names(Data)[1:12], "[[:blank:]]", "_")
# names(Data)[17] <- "Real_Email"
# names(Data)[18] <- "Real_Tel"
# names(Data)[19] <- "Real_Name"
# names(Data)[50] <- "Real_Age_categ"
names(Data)[40] <- "Age_categ"
names(Data)[41] <- "Sex"
names(Data)[names(Data) %in% names(Data[, indexSIG])] <- c(sprintf("SIG_%01d", seq(1, 8)))
names(Data)[names(Data) %in% names(Data[, indexMBI])] <- c(sprintf("MBI_%01d", seq(1, 16)))
names(Data)[names(Data) %in% names(Data[, indexPCL])] <- c(sprintf("PCL_%01d", seq(1, 20)))
# Data <-
# Data %>%
# dplyr::filter(Response_Status == "completed") # select only complete cases
# Recode
## 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
}
##
# lapply(Data[,indexPCL], unique)
Data[ ,indexPCL][ Data[ ,indexPCL] == "deloc"] <- "0"
Data[ ,indexPCL][ Data[ ,indexPCL] == "puțin"] <- "1"
Data[ ,indexPCL][ Data[ ,indexPCL] == "moderat"] <- "2"
Data[ ,indexPCL][ Data[ ,indexPCL] == "mult"] <- "3"
Data[ ,indexPCL][ Data[ ,indexPCL] == "foarte mult"] <- "4"
Data[ ,indexPCL][ Data[ ,indexPCL] == "Not Answered"] <- NA
Data[ ,indexSIG][ Data[ ,indexSIG] == "NU"] <- "0"
Data[ ,indexSIG][ Data[ ,indexSIG] == "?"] <- "1.5"
Data[ ,indexSIG][ Data[ ,indexSIG] == "DA"] <- "3"
Data[ ,indexSIG][ Data[ ,indexSIG] == "Not Answered"] <- NA
Data[ ,indexMBI] <- data.frame(lapply(Data[ ,indexMBI],
function(x) {gsub(".*Niciodat.*", "0", x)}), stringsAsFactors = FALSE)
Data[ ,indexMBI] <- data.frame(lapply(Data[ ,indexMBI],
function(x) {gsub(".*Zilnic.*", "6", x)}), stringsAsFactors = FALSE)
Data[ ,indexMBI][ Data[ ,indexMBI] == "Not Answered"] <- NA
Data[, indexSIG] <- colstonumeric(Data[, indexSIG])
Data[, indexMBI] <- colstonumeric(Data[, indexMBI])
Data[, indexPCL] <- colstonumeric(Data[, indexPCL])
# Scores
## 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, stat = "sum", natozero = FALSE, 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 = ", "))
}
if(tonumeric) df <- colstonumeric(df)
if(natozero) df[is.na(df)] <- 0 # NAs to 0 can help when stat = "mean" with na.rm = T because it keeps denominator constant
if(stat == "sum"){
df_res <- ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
NA,
rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0))
}
if(stat == "mean"){
df_res <- ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
NA,
rowMeans(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0))
}
return(df_res)
}
##
# Score PCL
Data$PCL_Total <- ScoreLikert(Data[, indexPCL], napercent = .3) # NA if NA threshold is exceeded
Data$PCL_B <- ScoreLikert(Data[, c(sprintf("PCL_%01d", 1:5))], napercent = 1) # do nothing if NA threshold is exceeded
Data$PCL_C <- ScoreLikert(Data[, c(sprintf("PCL_%01d", 6:7))], napercent = 1)
Data$PCL_D <- ScoreLikert(Data[, c(sprintf("PCL_%01d", 8:14))], napercent = 1)
Data$PCL_E <- ScoreLikert(Data[, c(sprintf("PCL_%01d", 15:20))], napercent = 1)
# Score SIG
Data$SIG_Total <- ScoreLikert(Data[, indexSIG], napercent = .3)
# Score MBI
Data$MBI_Total <- ScoreLikert(Data[, indexMBI], napercent = .3, stat = "mean", natozero = TRUE)
Data$MBI_Ex <- ScoreLikert(Data[, c(sprintf("MBI_%01d", itemindexMBI_Ex))], napercent = 1, stat = "mean", natozero = TRUE)
Data$MBI_Cy <- ScoreLikert(Data[, c(sprintf("MBI_%01d", itemindexMBI_Cy))], napercent = 1, stat = "mean", natozero = TRUE)
Data$MBI_Pe <- ScoreLikert(Data[, c(sprintf("MBI_%01d", itemindexMBI_Pe))], napercent = 1, stat = "mean", natozero = TRUE)
# PCL Diagnostic Algorithm
itemsPCL_B <- c(sprintf("PCL_%01d", 1:5))
itemsPCL_C <- c(sprintf("PCL_%01d", 6:7))
itemsPCL_D <- c(sprintf("PCL_%01d", 8:14))
itemsPCL_E <- c(sprintf("PCL_%01d", 15:20))
DataPCLAlg <-
Data %>%
dplyr::select(tidyselect::all_of(indexPCL)) %>%
dplyr::mutate_all(
funs(case_when(
. >=2 ~ 1,
# . <2 ~ 0,
is.na(.) ~ 0,
TRUE ~ 0))) %>%
mutate(PCL_CritB = case_when(rowSums(.[,itemsPCL_B], na.rm = TRUE) >= algPCL$B ~ 1, # algPCL <- data.frame(B = 1, C = 1, D = 2, E = 2)
# rowSums(.[,itemsPCL_B], na.rm = TRUE) <1 ~ 0,
TRUE ~ 0)) %>%
mutate(PCL_CritC = case_when(rowSums(.[,itemsPCL_C], na.rm = TRUE) >= algPCL$C ~ 1,
# rowSums(.[,itemsPCL_C], na.rm = TRUE) <1 ~ 0,
TRUE ~ 0)) %>%
mutate(PCL_CritD = case_when(rowSums(.[,itemsPCL_D], na.rm = TRUE) >= algPCL$D ~ 1,
# rowSums(.[,itemsPCL_D], na.rm = TRUE) <1 ~ 0,
TRUE ~ 0)) %>%
mutate(PCL_CritE = case_when(rowSums(.[,itemsPCL_E], na.rm = TRUE) >= algPCL$E ~ 1,
# rowSums(.[,itemsPCL_E], na.rm = TRUE) <1 ~ 0,
TRUE ~ 0)) %>%
mutate(PCL_Alg = case_when(PCL_CritB == 1 & PCL_CritC == 1 & PCL_CritD == 1 & PCL_CritE == 1 ~ 1,
TRUE ~ 0))
Data$PCLAlg <- DataPCLAlg$PCL_Alg
DataPCLAlg_subclin <-
Data %>%
dplyr::select(tidyselect::all_of(indexPCL)) %>%
dplyr::mutate_all(
funs(case_when(
. >=2 ~ 1,
# . <2 ~ 0,
is.na(.) ~ 0,
TRUE ~ 0))) %>%
mutate(PCL_CritB = case_when(rowSums(.[,itemsPCL_B], na.rm = TRUE) >= algPCL_subclin$B ~ 1,
# rowSums(.[,itemsPCL_B], na.rm = TRUE) <1 ~ 0,
TRUE ~ 0)) %>%
mutate(PCL_CritC = case_when(rowSums(.[,itemsPCL_C], na.rm = TRUE) >= algPCL_subclin$C ~ 1,
# rowSums(.[,itemsPCL_C], na.rm = TRUE) <1 ~ 0,
TRUE ~ 0)) %>%
mutate(PCL_CritD = case_when(rowSums(.[,itemsPCL_D], na.rm = TRUE) >= algPCL_subclin$D ~ 1,
# rowSums(.[,itemsPCL_D], na.rm = TRUE) <1 ~ 0,
TRUE ~ 0)) %>%
mutate(PCL_CritE = case_when(rowSums(.[,itemsPCL_E], na.rm = TRUE) >= algPCL_subclin$E ~ 1,
# rowSums(.[,itemsPCL_E], na.rm = TRUE) <1 ~ 0,
TRUE ~ 0)) %>%
mutate(PCL_Alg_subclin = case_when(PCL_CritB == 1 & PCL_CritC == 1 & PCL_CritD == 1 & PCL_CritE == 1 ~ 1,
TRUE ~ 0))
Data$PCLAlg_subclin <- DataPCLAlg_subclin$PCL_Alg_subclin
Data$MBI_Ex_cut <- ifelse(Data$MBI_Ex >= cutoffMBI_Ex, 1, 0)
Data$MBI_Cy_cut <- ifelse(Data$MBI_Cy >= cutoffMBI_Cy, 1, 0)
# Global Screening & Groups
df_screening <- Data[,c("ID", "nume", "e-mail", "Age_categ", "Sex",
"SIG_Total", "MBI_Ex_cut", "MBI_Cy_cut",
"PCL_Total", "PCL_B", "PCL_C", "PCL_D", "PCL_E", "PCLAlg", "PCLAlg_subclin")]
ids_ptsd <-
df_screening %>%
dplyr::filter(PCLAlg == 1) %>%
dplyr::select(ID) %>%
dplyr::pull()
ids_burn <-
df_screening %>%
dplyr::filter(MBI_Ex_cut == 1, MBI_Cy_cut == 1) %>%
dplyr::select(ID) %>%
dplyr::pull()
ids_old <-
df_screening %>%
dplyr::filter(Age_categ == "peste 65 ani") %>%
dplyr::select(ID) %>%
dplyr::pull()
ids_normal <-
df_screening %>%
dplyr::filter(!(ID %in% c(ids_ptsd, ids_burn, ids_old))) %>%
dplyr::select(ID) %>%
dplyr::pull()
intersect(ids_ptsd, ids_burn) # 8 common
[1] "12B" "5C" "8R" "11R" "6X" "9X" "12X" "19X"
character(0)
character(0)
[1] TRUE
Outcome Measures
Dictator Game
# DG df
dg_df_pre <- rio::import(file.path(folder, file),
skip = 0, which = "DictatorGame pre")
colnames(dg_df_pre)[4] <- "ID"
dg_df_pre <-
dg_df_pre %>%
dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) %>% # remove white spaces
dplyr::mutate(ID = toupper(ID)) # to upper
all(dg_df_pre$ID == toupper(dg_df_pre$ID))
dg_df_post <- rio::import(file.path(folder, file),
skip = 0, which = "DictatorGame post")
colnames(dg_df_post)[4] <- "ID"
dg_df_post <-
dg_df_post %>%
dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) %>% # remove white spaces
dplyr::mutate(ID = toupper(ID)) # to upper
all(dg_df_post$ID == toupper(dg_df_post$ID))
colnames(dg_df_pre)[5:8] <- sprintf("DG_%d", 1:4)
colnames(dg_df_post)[5:8] <- sprintf("DG_%d", 1:4)
dg_df_pre <-
dg_df_pre %>%
dplyr::mutate(`Date Modified` = lubridate::ymd_hms(format(`Date Modified`, "%Y-%m-%d %H:%M:%S", tz = "UTC"))) %>%
mutate_if(is.character, ~na_if(., "Not Answered"))
dg_df_post <-
dg_df_post %>%
dplyr::mutate(`Date Modified` = lubridate::ymd_hms(format(`Date Modified`, "%Y-%m-%d %H:%M:%S", tz = "UTC"))) %>%
mutate_if(is.character, ~dplyr::na_if(., "Not Answered"))
dg_df_pre <-
dg_df_pre %>%
dplyr::mutate_at(vars(starts_with("DG_")), ~stringr::str_extract(., "[0-9]+")) %>% # extracts first number (all games start with Player A, so always first number)
dplyr::mutate_at(vars(starts_with("DG_")), as.numeric) %>%
dplyr::mutate(Time = rep("Pre", nrow(.))) %>%
dplyr::mutate(Cond = ifelse(stringr::str_detect(ID, "X"), "CTRL", "TR")) %>%
select(`Date Modified`, ID, starts_with("DG_"), Time, Cond)
dg_df_post <-
dg_df_post %>%
dplyr::mutate_at(vars(starts_with("DG_")), ~stringr::str_extract(., "[0-9]+")) %>% # extracts first number (all games start with Player A, so always first number)
dplyr::mutate_at(vars(starts_with("DG_")), as.numeric) %>%
dplyr::mutate(Time = rep("Post", nrow(.))) %>%
dplyr::mutate(Cond = ifelse(stringr::str_detect(ID, "X"), "CTRL", "TR")) %>%
select(`Date Modified`, ID, starts_with("DG_"), Time, Cond)
# Transform DG 0-900 egoism to 0-9 altruism
dg_trans_func <- function(x){trans <- 9 - x / 100}
dg_df_pre <-
dg_df_pre %>%
dplyr::mutate_at(vars(starts_with("DG_")), dg_trans_func)
dg_df_post <-
dg_df_post %>%
dplyr::mutate_at(vars(starts_with("DG_")), dg_trans_func)
# Unite DG data - Long Format
dg_united_long <- rbind(dg_df_pre, dg_df_post)
which(table(dg_united_long$ID)> 2 ) # IDs "3B" & "31X" have more than 2 trials
dg_united_long[dg_united_long$ID == "3B",] # two Pres -- keep the first
dg_united_long <- dg_united_long[-73, ]
dg_united_long$DG_Total <- rowSums(dg_united_long[, sprintf("DG_%d", 1:4)], na.rm = TRUE)
# Unite DG data - Wide Format
dg_united_wide <-
dg_united_long %>%
tidyr::pivot_wider(names_from = Time, values_from = c("Date Modified", sprintf("DG_%d", 1:4), "DG_Total"))
# dg_united_wide2 <- dplyr::left_join(dg_united_wide, ids_groups_df, by = "ID") # no need to merge, already have ids for groups stored
–>
T test Dicatator Game
## DG - PTSD TR
#### DG_Total_Pre DG_Total_Post
## DG - PTSD CTRL
#### DG_Total_Pre DG_Total_Post
## DG - Burnout TR
#### DG_Total_Pre DG_Total_Post
## DG - Burnout CTRL
#### DG_Total_Pre DG_Total_Post
## DG - Old TR
#### DG_Total_Pre DG_Total_Post
## DG - Old CTRL
Error in (function (x, cutpoints = c(0.3, 0.6, 0.8, 0.9, 0.95), symbols = if (numeric.x) c(" ", :
argument "x" is missing, with no default
## DG - General Population TR
#### DG_Total_Pre DG_Total_Post
## DG - General Population CTRL
#### DG_Total_Pre DG_Total_Post
DG Normal Sample Size estimation
## DG - General Population TR
## Cohen's d
## Sample Size estimation
## DG - General Population CTRL
Error in samplesize_pairedttest(., ind = "ID", pre_var = "DG_Total_Pre", :
unused argument (ind = "ID")
# Scales df
scale_df_pre <- rio::import(file.path(folder, file),
skip = 0, which = "Set teste zi 1 pre")
scale_df_pre <- scale_df_pre[,-2]
colnames(scale_df_pre)[1] <- "Date"
colnames(scale_df_pre)[2] <- "ID"
scale_df_pre <-
scale_df_pre %>%
dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) %>% # remove white spaces
dplyr::mutate(ID = toupper(ID)) # to upper
all(scale_df_pre$ID == toupper(scale_df_pre$ID))
scale_df_post <- rio::import(file.path(folder, file),
skip = 0, which = "Set teste zi 5 post")
scale_df_post <- scale_df_post[,-2]
colnames(scale_df_post)[1] <- "Date"
colnames(scale_df_post)[2] <- "ID"
scale_df_post <-
scale_df_post %>%
dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) %>% # remove white spaces
dplyr::mutate(ID = toupper(ID)) # to upper
all(scale_df_post$ID == toupper(scale_df_post$ID))
all.equal(colnames(scale_df_post), colnames(scale_df_pre)) # setdiff(colnames(scale_df_post), colnames(scale_df_pre))
# Deal with Not Answer
scale_df_pre <-
scale_df_pre %>%
mutate_if(is.character, ~dplyr::na_if(., "Not Answered"))
scale_df_post <-
scale_df_post %>%
mutate_if(is.character, ~dplyr::na_if(., "Not Answered"))
# Add Condition
scale_df_pre <-
scale_df_pre %>%
dplyr::mutate(Time = rep("Pre", nrow(.))) %>%
dplyr::mutate(Cond = ifelse(stringr::str_detect(ID, "X"), "CTRL", "TR"))
scale_df_post <-
scale_df_post %>%
dplyr::mutate(Time = rep("Post", nrow(.))) %>%
dplyr::mutate(Cond = ifelse(stringr::str_detect(ID, "X"), "CTRL", "TR"))
## PANAS: Positive Affect Score = sum items 1, 3, 5, 9, 10, 12, 14, 16, 17, 19. Negative Affect Score = sum items 2, 4, 6, 7, 8, 11, 13, 15, 18, 20.
index_item_panas <- 3:22
colnames(scale_df_pre)[index_item_panas] <- sprintf("PANAS_%d", 1:20)
colnames(scale_df_post)[index_item_panas] <- sprintf("PANAS_%d", 1:20)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas],
function(x) {gsub(".*în foarte mică măsură.*", "1", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas],
function(x) {gsub(".*în mică măsură.*", "2", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas],
function(x) {gsub(".*într-o oarecare măsură.*", "3", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas],
function(x) {gsub(".*în mare măsură.*", "4", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas],
function(x) {gsub(".*în foarte mare măsură.*", "5", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas],
function(x) {gsub(".*în foarte mică măsură.*", "1", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas],
function(x) {gsub(".*în mică măsură.*", "2", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas],
function(x) {gsub(".*într-o oarecare măsură.*", "3", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas],
function(x) {gsub(".*în mare măsură.*", "4", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas],
function(x) {gsub(".*în foarte mare măsură.*", "5", x)}), stringsAsFactors = FALSE)
# Scoring
scale_df_pre$PA_Total <- ScoreLikert(scale_df_pre[, index_item_panas][c(1, 3, 5, 9, 10, 12, 14, 16, 17, 19)],
tonumeric = TRUE, napercent = .11) # not more than 1 NAs for 10 items
scale_df_pre$NA_Total <- ScoreLikert(scale_df_pre[, index_item_panas][c(2, 4, 6, 7, 8, 11, 13, 15, 18, 20)],
tonumeric = TRUE, napercent = .11) # not more than 1 NAs for 10 items
scale_df_post$PA_Total <- ScoreLikert(scale_df_post[, index_item_panas][c(1, 3, 5, 9, 10, 12, 14, 16, 17, 19)],
tonumeric = TRUE, napercent = .11) # not more than 1 NAs for 10 items
scale_df_post$NA_Total <- ScoreLikert(scale_df_post[, index_item_panas][c(2, 4, 6, 7, 8, 11, 13, 15, 18, 20)],
tonumeric = TRUE, napercent = .11) # not more than 1 NAs for 10 items
## PSS-SF 14 (likert 0-4). Items 4, 5, 6, 7, 9, 10, and 13 are scored in reverse direction.
index_item_pss <- 23:36
index_item_revPSS <- c(4, 5, 6, 7, 9, 10, 13)
colnames(scale_df_pre)[index_item_pss] <- sprintf("PSS_%d", 1:14)
colnames(scale_df_post)[index_item_pss] <- sprintf("PSS_%d", 1:14)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss],
function(x) {gsub(".*niciodată.*", "0", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss],
function(x) {gsub(".*aproape niciodată.*", "1", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss],
function(x) {gsub(".*uneori.*", "2", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss],
function(x) {gsub(".*destul de des.*", "3", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss],
function(x) {gsub(".*foarte des.*", "4", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss],
function(x) {gsub(".*niciodată.*", "0", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss],
function(x) {gsub(".*aproape niciodată.*", "1", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss],
function(x) {gsub(".*uneori.*", "2", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss],
function(x) {gsub(".*destul de des.*", "3", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss],
function(x) {gsub(".*foarte des.*", "4", x)}), stringsAsFactors = FALSE)
# Score
scale_df_pre[, index_item_pss] <- colstonumeric(scale_df_pre[, index_item_pss])
scale_df_post[, index_item_pss] <- colstonumeric(scale_df_post[, index_item_pss])
scale_df_pre[, index_item_pss][index_item_revPSS] <- ReverseCode(scale_df_pre[, index_item_pss][index_item_revPSS], tonumeric = FALSE, min = 0, max = 4)
scale_df_post[, index_item_pss][index_item_revPSS] <- ReverseCode(scale_df_post[, index_item_pss][index_item_revPSS], tonumeric = FALSE, min = 0, max = 4)
scale_df_pre$PSS_Total <- ScoreLikert(scale_df_pre[, index_item_pss], napercent = .11)
scale_df_post$PSS_Total <- ScoreLikert(scale_df_post[, index_item_pss], napercent = .11)
# Unite scale df - Long Format
scale_united_long <- rbind(scale_df_pre, scale_df_post)
scale_united_long %>%
count(ID) %>%
print(n = Inf) # ID "2B" has double record both in pre and post -- keep first in both, second record has NAs
# scale_united_long[scale_united_long$ID == "2B",]
scale_united_long <- scale_united_long[-26,]
scale_united_long <- scale_united_long[-102,]
# Unite DG data - Wide Format
scale_united_wide <-
scale_united_long %>%
dplyr::select(ID, Date, Time, Cond, PA_Total, NA_Total, PSS_Total) %>%
tidyr::pivot_wider(names_from = Time, values_from = c("Date", "PA_Total", "NA_Total", "PSS_Total"))
cat("Mixed ANOVA - PSS whole sample (not by groups)")
# Mixed ANOVA
scale_united_long %>%
group_by(ID) %>%
filter(n() > 1) %>% # keep only complete cases -- here are only complete
ungroup() %>%
tw_mixedANOVA_func(data = ., id_var = ID, cond_var = Cond, time_var = Time, value_var = PSS_Total,
posthoc_sig_interac = TRUE, posthoc_ns_interac = TRUE)
cat("Mixed ANOVA - PA whole sample (not by groups)")
scale_united_long %>%
group_by(ID) %>%
filter(n() > 1) %>% # keep only complete cases -- here are only complete
ungroup() %>%
tw_mixedANOVA_func(data = ., id_var = ID, cond_var = Cond, time_var = Time, value_var = PA_Total,
posthoc_sig_interac = TRUE, posthoc_ns_interac = TRUE)
cat("Mixed ANOVA - NA whole sample (not by groups)")
scale_united_long %>%
group_by(ID) %>%
filter(n() > 1) %>% # keep only complete cases -- here are only complete
ungroup() %>%
tw_mixedANOVA_func(data = ., id_var = ID, cond_var = Cond, time_var = Time, value_var = NA_Total,
posthoc_sig_interac = TRUE, posthoc_ns_interac = TRUE)
–>
T test PSS
## PSS - PTSD TR
#### PSS_Total_Pre PSS_Total_Post
## PSS - PTSD CTRL
#### PSS_Total_Pre PSS_Total_Post
## PSS - Burnout TR
#### PSS_Total_Pre PSS_Total_Post
## PSS - Burnout CTRL
#### PSS_Total_Pre PSS_Total_Post
## PSS - Old TR
#### PSS_Total_Pre PSS_Total_Post
## PSS - Old CTRL
Error in (function (x, cutpoints = c(0.3, 0.6, 0.8, 0.9, 0.95), symbols = if (numeric.x) c(" ", :
argument "x" is missing, with no default
## PSS - General Population TR
#### PSS_Total_Pre PSS_Total_Post
## PSS - General Population CTRL
#### PSS_Total_Pre PSS_Total_Post
PSS Normal Sample Size estimation
## PSS - General Population TR
## Cohen's d
## Sample Size estimation
## PSS - General Population CTRL
## Cohen's d
## Sample Size estimation
T test PA
## PA - PTSD TR
#### PA_Total_Pre PA_Total_Post
## PA - PTSD CTRL
#### PA_Total_Pre PA_Total_Post
## PA - Burnout TR
#### PA_Total_Pre PA_Total_Post
## PA - Burnout CTRL
#### PA_Total_Pre PA_Total_Post
## PA - Old TR
#### PA_Total_Pre PA_Total_Post
## PA - Old CTRL
Error in (function (x, cutpoints = c(0.3, 0.6, 0.8, 0.9, 0.95), symbols = if (numeric.x) c(" ", :
argument "x" is missing, with no default
## PA - General Population TR
#### PA_Total_Pre PA_Total_Post
## PA - General Population CTRL
#### PA_Total_Pre PA_Total_Post
PA Normal Sample Size estimation
## PSS - General Population TR
## Cohen's d
## Sample Size estimation
## PSS - General Population CTRL
## Cohen's d
## Sample Size estimation
T test NA
## NA - PTSD TR
#### NA_Total_Pre NA_Total_Post
## NA - PTSD CTRL
#### NA_Total_Pre NA_Total_Post
## NA - Burnout TR
#### NA_Total_Pre NA_Total_Post
## NA - Burnout CTRL
#### NA_Total_Pre NA_Total_Post
## NA - Old TR
#### NA_Total_Pre NA_Total_Post
## NA - Old CTRL
Error in (function (x, cutpoints = c(0.3, 0.6, 0.8, 0.9, 0.95), symbols = if (numeric.x) c(" ", :
argument "x" is missing, with no default
## NA - General Population TR
#### NA_Total_Pre NA_Total_Post
## NA - General Population CTRL
#### NA_Total_Pre NA_Total_Post
NA Normal Sample Size estimation
## PSS - General Population TR
## Cohen's d
## Sample Size estimation
## PSS - General Population CTRL
## Cohen's d
## Sample Size estimation
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] pwr_1.2-2 rlang_0.4.6 emmeans_1.4.5 rio_0.5.16 scales_1.1.0 ggpubr_0.2.5
[7] magrittr_1.5 tadaatoolbox_0.16.1 summarytools_0.8.8 rstatix_0.5.0 broom_0.5.6 PerformanceAnalytics_1.5.2
[13] xts_0.11-2 zoo_1.8-4 psych_1.9.12.31 forcats_0.5.0 stringr_1.4.0 dplyr_0.8.5
[19] purrr_0.3.3 readr_1.3.1 tidyr_1.0.2 tibble_3.0.0 ggplot2_3.3.0 tidyverse_1.3.0
[25] papaja_0.1.0.9842 pacman_0.5.1
loaded via a namespace (and not attached):
[1] nlme_3.1-140 bitops_1.0-6 matrixStats_0.54.0 fs_1.4.1 lubridate_1.7.4 httr_1.4.1 tools_3.6.1 backports_1.1.6
[9] R6_2.4.1 nortest_1.0-4 DBI_1.0.0 colorspace_1.4-1 withr_2.1.2 tidyselect_1.0.0 gridExtra_2.3 mnormt_1.5-6
[17] pixiedust_0.8.6 curl_4.3 compiler_3.6.1 cli_2.0.2 rvest_0.3.5 expm_0.999-3 xml2_1.3.1 sandwich_2.5-0
[25] labeling_0.3 mvtnorm_1.1-0 quadprog_1.5-5 digest_0.6.25 foreign_0.8-71 pkgconfig_2.0.3 htmltools_0.4.0 dbplyr_1.4.3
[33] readxl_1.3.1 rstudioapi_0.11 pryr_0.1.4 farver_2.0.3 generics_0.0.2 jsonlite_1.6.1 zip_1.0.0 car_3.0-7
[41] RCurl_1.95-4.11 rapportools_1.0 Matrix_1.2-17 Rcpp_1.0.4.6 DescTools_0.99.34 munsell_0.5.0 fansi_0.4.1 abind_1.4-5
[49] viridis_0.5.1 lifecycle_0.2.0 multcomp_1.4-8 stringi_1.4.6 carData_3.0-2 MASS_7.3-51.4 plyr_1.8.6 grid_3.6.1
[57] parallel_3.6.1 crayon_1.3.4 lattice_0.20-38 splines_3.6.1 haven_2.2.0 pander_0.6.3 hms_0.5.3 knitr_1.28
[65] pillar_1.4.3 boot_1.3-22 estimability_1.3 ggsignif_0.4.0 codetools_0.2-16 reprex_0.3.0 glue_1.4.0 data.table_1.12.8
[73] modelr_0.1.6 vctrs_0.2.4 cellranger_1.1.0 gtable_0.3.0 assertthat_0.2.1 xfun_0.13 openxlsx_4.1.0 xtable_1.8-4
[81] coda_0.19-2 survival_2.44-1.1 viridisLite_0.3.0 TH.data_1.0-9 ellipsis_0.3.0
Â
A work by Claudiu Papasteri
claudiu.papasteri@gmail.com
Â
LS0tDQp0aXRsZTogIjxicj4gUEE0IiANCnN1YnRpdGxlOiAiUmVwb3J0Ig0KYXV0aG9yOiAiPGJyPiBDbGF1ZGl1IFBhcGFzdGVyaSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVtICVZJylgIg0Kb3V0cHV0OiANCiAgICBodG1sX25vdGVib29rOg0KICAgICAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgICAgICAgICB0b2M6IHRydWUNCiAgICAgICAgICAgIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICB0aGVtZTogc3BhY2VsYWINCiAgICAgICAgICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbA0KICAgICAgICAgICAgZmlnX3dpZHRoOiAxMA0KICAgICAgICAgICAgZmlnX2hlaWdodDogOQ0KICAgICMgcGRmX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgIyBmb250c2l6ZTogMTFwdA0KICAgICAgICAgICAgIyBnZW9tZXRyeTogbWFyZ2luPTFpbg0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDcNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNg0KICAgICAgICAgICAgIyBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgICMgZ2l0aHViX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBodG1sX3ByZXZpZXc6IGZhbHNlDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNQ0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA1DQogICAgICAgICAgICAjIGRldjoganBlZw0KLS0tDQoNCg0KPCEtLSBTZXR1cCAtLT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVycm9yID0gVFJVRSwNCiAgZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0KIyBHZW5lcmFsIFIgb3B0aW9ucyBhbmQgaW5mbw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQoNCiMgTG9hZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY2thZ2VzIDwtIGMoDQogICJwYXBhamEiLA0KICAidGlkeXZlcnNlIiwgICAgICAgDQogICJwc3ljaCIsICJQZXJmb3JtYW5jZUFuYWx5dGljcyIsICAgICAgICAgIA0KICAiYnJvb20iLCAicnN0YXRpeCIsDQogICJzdW1tYXJ5dG9vbHMiLCAidGFkYWF0b29sYm94IiwgICAgICAgICAgIA0KICAiZ2dwbG90MiIsICJnZ3B1YnIiLCAic2NhbGVzIiwgICAgICAgIA0KICAicmlvIiwNCiAgImdncHViciIsICJyc3RhdGl4IiwgImJyb29tIiwgImVtbWVhbnMiLCAicmxhbmciLA0KICAicHdyIg0KICAjICwgLi4uDQopDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFjbWFuOjpwX2xvYWQoY2hhciA9IHBhY2thZ2VzKQ0KDQojIFRoZW1lcyBmb3IgZ2dwbG90MiBwbG90aW5nIChoZXJlIHVzZWQgQVBBIHN0eWxlKQ0KdGhlbWVfc2V0KHRoZW1lX2FwYSgpKQ0KYGBgDQoNCg0KDQoNCg0KPCEtLSBSZXBvcnQgLS0+DQoNCiMgRGVmaW5lIGZ1bmN0aW9ucw0KDQpgYGB7ciBkZWZfZnVuY30NCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHJlY29kZXMgdG8gbnVtZXJpYywgYnV0IHdhdGNoZXMgb3V0IHRvIGNvZXJjaW9uIHRvIG5vdCBpbnRyb2R1Y2UgTkFzDQpjb2xzdG9udW1lcmljIDwtIGZ1bmN0aW9uKGRmKXsNCiAgdHJ5Q2F0Y2goew0KICAgIGRmX251bSA8LSBhcy5kYXRhLmZyYW1lKA0KICAgICAgbGFwcGx5KGRmLA0KICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHsgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpfSkpIA0KICB9LHdhcm5pbmcgPSBmdW5jdGlvbihzdG9wX29uX3dhcm5pbmcpIHsNCiAgICBtZXNzYWdlKCJTdG9wZWQgdGhlIGV4ZWN1dGlvbiBvZiBudW1lcmljIGNvbnZlcnNpb246ICIsIGNvbmRpdGlvbk1lc3NhZ2Uoc3RvcF9vbl93YXJuaW5nKSkNCiAgfSkgDQp9DQojIw0KIyMgRGVmaW5lIGZ1bmN0aW9uIHRoYXQgcmV2ZXJzZSBjb2RlcyBpdGVtcw0KUmV2ZXJzZUNvZGUgPC0gZnVuY3Rpb24oZGYsIHRvbnVtZXJpYyA9IEZBTFNFLCBtaW4gPSBOVUxMLCBtYXggPSBOVUxMKSB7DQogIGlmKHRvbnVtZXJpYykgZGYgPC0gY29sc3RvbnVtZXJpYyhkZikNCiAgZGYgPC0gKG1heCArIG1pbikgLSBkZg0KfQ0KIyMNCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHNjb3JlcyBvbmx5IHJvd3Mgd2l0aCBsZXNzIHRoYW4gMTAlIE5BcyAocmV0dXJucyBOQSBpZiBhbGwgb3IgYWJvdmUgdGhyZXNob2xkIHBlcmNlbnRhZ2Ugb2Ygcm93cyBhcmUgTkEpOyBjYW4gcmV2ZXJzZSBjb2RlIGlmIHZlY3RvciBvZiBjb2x1bW4gaW5kZXhlcyBhbmQgbWluLCBtYXggYXJlIHByb3ZpZGVkLg0KU2NvcmVMaWtlcnQgPC0gZnVuY3Rpb24oZGYsIG5hcGVyY2VudCA9IC4xLCB0b251bWVyaWMgPSBGQUxTRSwgcmV2ZXJzZWNvbHMgPSBOVUxMLCBtaW4gPSBOVUxMLCBtYXggPSBOVUxMKSB7DQogIHJldmVyc2VfbGlzdCA8LSBsaXN0KHJldmVyc2Vjb2xzID0gcmV2ZXJzZWNvbHMsIG1pbiA9IG1pbiwgbWF4ID0gbWF4KQ0KICByZXZlcnNlX2NoZWNrIDwtICFzYXBwbHkocmV2ZXJzZV9saXN0LCBpcy5udWxsKQ0KICANCiAgIyBSZWNvZGUgdG8gbnVtZXJpYywgYnV0IHdhdGNoIG91dCB0byBjb2VyY2lvbiB0byBub3QgaW50cm9kdWNlIE5Bcw0KICBjb2xzdG9udW1lcmljIDwtIGZ1bmN0aW9uKGRmKXsNCiAgICB0cnlDYXRjaCh7DQogICAgICBkZl9udW0gPC0gYXMuZGF0YS5mcmFtZSgNCiAgICAgICAgbGFwcGx5KGRmLA0KICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgeyBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4KSl9KSkgDQogICAgfSx3YXJuaW5nID0gZnVuY3Rpb24oc3RvcF9vbl93YXJuaW5nKSB7DQogICAgICBtZXNzYWdlKCJTdG9wZWQgdGhlIGV4ZWN1dGlvbiBvZiBudW1lcmljIGNvbnZlcnNpb246ICIsIGNvbmRpdGlvbk1lc3NhZ2Uoc3RvcF9vbl93YXJuaW5nKSkNCiAgICB9KSANCiAgfQ0KICANCiAgaWYodG9udW1lcmljKSBkZiA8LSBjb2xzdG9udW1lcmljKGRmKQ0KICANCiAgaWYoYWxsKHJldmVyc2VfY2hlY2spKXsNCiAgICBkZlsgLHJldmVyc2Vjb2xzXSA8LSAobWF4ICsgbWluKSAtIGRmWyAscmV2ZXJzZWNvbHNdDQogIH1lbHNlIGlmKGFueShyZXZlcnNlX2NoZWNrKSl7DQogICAgc3RvcCgiSW5zdWZpY2llbnQgaW5mbyBmb3IgcmV2ZXJzaW5nLiBQbGVhc2UgcHJvdmlkZTogIiwgcGFzdGUobmFtZXMocmV2ZXJzZV9saXN0KVshcmV2ZXJzZV9jaGVja10sIGNvbGxhcHNlID0gIiwgIikpDQogIH0NCiAgDQogIGlmZWxzZShyb3dTdW1zKGlzLm5hKGRmKSkgPiBuY29sKGRmKSAqIG5hcGVyY2VudCwNCiAgICAgICAgIE5BLA0KICAgICAgICAgcm93U3VtcyhkZiwgbmEucm0gPSBUUlVFKSAqIE5BIF4gKHJvd1N1bXMoIWlzLm5hKGRmKSkgPT0gMCkNCiAgKQ0KfQ0KIyMNCmBgYA0KDQoNCmBgYHtyIGRlZl9mdW5jX3R0ZXN0LCBoaWRlPVRSVUV9DQojIyBGdW5jIHQgdGVzdCBzaSBib3hwbG90IHNpbXBsdQ0KZnVuY190X2JveCA8LSBmdW5jdGlvbihkZiwgaW5kLCBwcmVfdmFyLCBwb3N0X3Zhcil7DQogIHZhcnMgPC0gYyhpbmQsIHByZV92YXIsIHBvc3RfdmFyKSAgICAgICAgICAgICAgICAjIHRvIGF2b2lkIG5ldyB0aWR5dmVyc2UgZXJyb3Igb2YgYW1iaWd1aXR5IGR1ZSB0byBleHRlcm5hbCB2ZWN0b3MNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KHRpZHlzZWxlY3Q6OmFsbF9vZih2YXJzKSkgJT4lIA0KICAgIHRpZHlyOjpkcm9wX25hKCkgJT4lDQogICAgZ2F0aGVyKHRpZHlzZWxlY3Q6OmFsbF9vZihwcmVfdmFyKSwgdGlkeXNlbGVjdDo6YWxsX29mKHBvc3RfdmFyKSwga2V5ID0gIkNvbmQiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JSANCiAgICBtdXRhdGVfYXQodmFycyhjKDEsIDIpKSwgYXMuZmFjdG9yKSAlPiUgDQogICAgbXV0YXRlKENvbmQgPSBmYWN0b3IoQ29uZCwgbGV2ZWxzID0gYyhwcmVfdmFyLCBwb3N0X3ZhcikpKSANCiAgDQogIHN0YXRfY29tcCA8LSBnZ3B1YnI6OmNvbXBhcmVfbWVhbnModmFsdWUgfiBDb25kLCBkYXRhID0gZGZfbW9kaWYsIG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFKQ0KICANCiAgc3RhdF9jb21wMiA8LQ0KICAgIGRmX21vZGlmICU+JSANCiAgICBkbyh0aWR5KHQudGVzdCguJHZhbHVlIH4gLiRDb25kLA0KICAgICAgICAgICAgICAgICAgIHBhaXJlZCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgZGF0YT0uKSkpDQogIA0KICBwbG90IDwtIA0KICAgIGdncHVicjo6Z2dwYWlyZWQoZGZfbW9kaWYsIHggPSAiQ29uZCIsIHkgPSAidmFsdWUiLCBpZCA9IGluZCwgDQogICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJDb25kIiwgbGluZS5jb2xvciA9ICJncmF5IiwgbGluZS5zaXplID0gMC40LA0KICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZSA9IGMoIiMwMEFGQkIiLCAiI0ZDNEUwNyIpLCBsZWdlbmQgPSAibm9uZSIpICsNCiAgICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsICBjb2xvdXIgPSAiZGFya3JlZCIpICsNCiAgICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFLCBsYWJlbC54ID0gYXMubnVtZXJpYyhkZl9tb2RpZiRDb25kKS0wLjQsIGxhYmVsLnkgPSBtYXgoZGZfbW9kaWYkdmFsdWUpKzAuNSkgKyANCiAgICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFLCBsYWJlbCA9ICJwLnNpZ25pZiIsIGNvbXBhcmlzb25zID0gbGlzdChjKHByZV92YXIsIHBvc3RfdmFyKSkpDQogIA0KICBjYXQocGFzdGUwKCIjIyMjICIsIHByZV92YXIsICIgIiwgcG9zdF92YXIsICJcbiIsICJcbiIpKQ0KICBwcmludChzdGF0X2NvbXApDQogIHByaW50KHN0YXRfY29tcDIpDQogIHByaW50KHBsb3QpDQp9DQpgYGANCg0KDQpgYGB7ciBzYW1wbGVzaXplX2lkZXB0dGVzdH0NCnNhbXBsZXNpemVfcGFpcmVkdHRlc3QgPC0gZnVuY3Rpb24oZGYsIHByZV92YXIsIHBvc3RfdmFyKXsNCiAgdmFycyA8LSBjKHByZV92YXIsIHBvc3RfdmFyKSAgICAgICAgICAgICAgICAjIHRvIGF2b2lkIG5ldyB0aWR5dmVyc2UgZXJyb3Igb2YgYW1iaWd1aXR5IGR1ZSB0byBleHRlcm5hbCB2ZWN0b3MNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KHRpZHlzZWxlY3Q6OmFsbF9vZih2YXJzKSkgJT4lIA0KICAgIHRpZHlyOjpkcm9wX25hKCkgJT4lDQogICAgZ2F0aGVyKHRpZHlzZWxlY3Q6OmFsbF9vZihwcmVfdmFyKSwgdGlkeXNlbGVjdDo6YWxsX29mKHBvc3RfdmFyKSwga2V5ID0gIkNvbmQiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JSANCiAgICBtdXRhdGUoQ29uZCA9IGZhY3RvcihDb25kLCBsZXZlbHMgPSBjKHByZV92YXIsIHBvc3RfdmFyKSkpIA0KICANCiAgY2F0KCIjIyBDb2hlbidzIGQgXG4iKQ0KICBlZmZfc2l6ZV90YWJsZSA8LQ0KICAgIGRmX21vZGlmICU+JQ0KICAgIGNvaGVuc19kKHZhbHVlIH4gQ29uZCwgcGFpcmVkID0gVFJVRSkgJT4lDQogICAgcHJpbnQoKQ0KICBlZmZfc2l6ZSA8LSBhcy5udW1lcmljKGVmZl9zaXplX3RhYmxlJGVmZnNpemUpDQoNCiAgY2F0KCIjIyBTYW1wbGUgU2l6ZSBlc3RpbWF0aW9uIFxuIikNCiAgc2FtcGxlX3NpemVfdGFibGUgPC0NCiAgICBwd3I6OnB3ci50LnRlc3QoZCA9IGVmZl9zaXplLCBzaWcubGV2ZWwgPSAuMDUsIHBvd2VyID0gLjgsIHR5cGUgPSAicGFpcmVkIiwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikgDQogIHNhbXBsZV9zaXplX3RhYmxlICU+JSBicm9vbTo6dGlkeSgpICU+JSBwcmludCgpDQoNCiAgcGxvdChzYW1wbGVfc2l6ZV90YWJsZSkNCn0gIA0KYGBgDQoNCg0KYGBge3IgZGVmX2Z1bmNfQU5DT1ZBUG9zdH0NCiMgbGlicmFyeSh0aWR5dmVyc2UpDQojIGxpYnJhcnkoZ2dwdWJyKQ0KIyBsaWJyYXJ5KHJzdGF0aXgpDQojIGxpYnJhcnkoYnJvb20pDQojIGxpYnJhcnkoZW1tZWFucykNCiMgbGlicmFyeShybGFuZykNCg0KDQojIEZ1bmN0aW9uIEFOQ09WQVBvc3QNCiMgVGFrZXMgTG9uZyBEYXRhDQpBTkNPVkFQb3N0X2Z1bmMgPC0gDQogIGZ1bmN0aW9uKGRhdGEsIGlkX3ZhciwgDQogICAgICAgICAgIHRpbWVfdmFyLCBwcmVfbGFiZWwsIHBvc3RfbGFiZWwsDQogICAgICAgICAgIHZhbHVlX3ZhciA9IHNjb3JlcywgY29uZF92YXIsIA0KICAgICAgICAgICBhc3N1bV9jaGVjayA9IFRSVUUsIHBvc3Rob2MgPSBUUlVFLCANCiAgICAgICAgICAgcF9hZGp1c3RfbWV0aG9kID0gImJvbmZlcnJvbmkiKXsNCiAgDQogIGlkX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKGlkX3ZhcikNCiAgaWRfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUoaWRfdmFyX2VucSkgICAgDQogIHRpbWVfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8odGltZV92YXIpDQogIHRpbWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodGltZV92YXJfZW5xKQ0KICBwcmVfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8ocHJlX2xhYmVsKQ0KICBwcmVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUocHJlX3Zhcl9lbnEpICANCiAgcG9zdF92YXJfZW5xIDwtIHJsYW5nOjplbnF1byhwb3N0X2xhYmVsKQ0KICBwb3N0X3Zhcl9uYW1lIDwtIHJsYW5nOjphc19uYW1lKHBvc3RfdmFyX2VucSkNCiAgY29uZF92YXJfZW5xIDwtIHJsYW5nOjplbnF1byhjb25kX3ZhcikNCiAgY29uZF92YXJfbmFtZSA8LSBybGFuZzo6YXNfbmFtZShjb25kX3Zhcl9lbnEpDQogIHZhbHVlX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKHZhbHVlX3ZhcikNCiAgdmFsdWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodmFsdWVfdmFyX2VucSkgDQogIA0KICBkYXRhX3dpZGVyIDwtDQogICAgZGF0YSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KCEhaWRfdmFyX2VucSwgISF0aW1lX3Zhcl9lbnEsICEhY29uZF92YXJfZW5xLCAhIXZhbHVlX3Zhcl9lbnEpICU+JQ0KICAgIHNwcmVhZChrZXkgPSB0aW1lX3Zhcl9uYW1lLCB2YWx1ZSA9IHZhbHVlX3Zhcl9uYW1lKSAjICU+JSAgICAgIyBpZiBuZWVkIHRvIGNvbXB1dGUgY2hhbmdlIHNjb3JlIHN0YXRpc3RpY3MgZ28gZnJvbSBoZXJlDQogICAgIyBtdXRhdGUoZGlmZmVyZW5jZSA9ICEhcG9zdF92YXJfZW5xIC0gISFwcmVfdmFyX2VucSkgIA0KICAgIA0KICAjIEFzc3VtcHRpb25zDQogIGlmKGFzc3VtX2NoZWNrKXsNCiAgY2F0KCJcbiBMaW5lYXJpdHkgYXNzdW1wdGlvbkxpbmVhcml0eSBhc3N1bXB0aW9uIChsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gcHJlLXRlc3QgYW5kIHBvc3QtdGVzdCBmb3IgZWFjaCBncm91cCkgXG4iKQ0KICAjIENyZWF0ZSBhIHNjYXR0ZXIgcGxvdCBiZXR3ZWVuIHRoZSBjb3ZhcmlhdGUgKGkuZS4sIHByZXRlc3QpIGFuZCB0aGUgb3V0Y29tZSB2YXJpYWJsZSAoaS5lLiwgcG9zdHRlc3QpDQogIHNjYXR0ZXJfbGluIDwtICANCiAgICBnZ3NjYXR0ZXIoZGF0YV93aWRlciwgeCA9IHByZV92YXJfbmFtZSwgeSA9IHBvc3RfdmFyX25hbWUsIGNvbG9yID0gY29uZF92YXJfbmFtZSwgDQogICAgICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIHRpdGxlID0gIkxpbmVhcml0eSBhc3N1bXB0aW9uIikgKw0KICAgICAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGFlcyhsYWJlbCA9ICBwYXN0ZSguLmVxLmxhYmVsLi4sIC4ucnIubGFiZWwuLiwgc2VwID0gIn5+fn4iKSwgY29sb3IgPSAhIWNvbmRfdmFyX2VucSkpDQogIA0KICBjYXQoIlxuIEhvbW9nZW5laXR5IG9mIHJlZ3Jlc3Npb24gc2xvcGVzIChpbnRlcmFjdGlvbiB0ZXJtIGlzIG4ucy4pIFxuIikNCiAgZGF0YV93aWRlciAlPiUgDQogICAgYW5vdmFfdGVzdChhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSwgIiAqICIsIHByZV92YXJfbmFtZSkpKSAlPiUgDQogICAgcHJpbnQoKSAgIA0KICANCiAgY2F0KCJcbiBOb3JtYWxpdHkgb2YgcmVzaWR1YWxzIChNb2RlbCBkaWFnbm9zdGljcyAmIFNoYXBpcm8gV2lsaykgXG4iKQ0KICAjIEZpdCB0aGUgbW9kZWwsIHRoZSBjb3ZhcmlhdGUgZ29lcyBmaXJzdA0KICBtb2RlbCA8LSANCiAgICBsbShhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSwgIiArICIsIHByZV92YXJfbmFtZSkpLA0KICAgICAgIGRhdGEgPSBkYXRhX3dpZGVyKQ0KICBjYXQoIlxuIEluc3BlY3QgdGhlIG1vZGVsIGRpYWdub3N0aWMgbWV0cmljcyBcbiIpDQogIG1vZGVsLm1ldHJpY3MgPC0gDQogICAgYXVnbWVudChtb2RlbCkgJT4lDQogICAgZHBseXI6OnNlbGVjdCgtLmhhdCwgLS5zaWdtYSwgLS5maXR0ZWQsIC0uc2UuZml0KSAgJT4lICAgICMgUmVtb3ZlIGRldGFpbHMNCiAgICBwcmludCgpDQogIGNhdCgiXG4gTm9ybWFsaXR5IG9mIHJlc2lkdWFscyAoU2hhcGlybyBXaWxrIHA+LjA1KSBcbiIpDQogIHNoYXBpcm9fdGVzdChtb2RlbC5tZXRyaWNzJC5yZXNpZCkgJT4lIA0KICAgIHByaW50KCkNCiAgDQogIGNhdCgiXG4gSG9tb2dlbmVpdHkgb2YgdmFyaWFuY2VzIChMZXZlbmXigJlzIHRlc3QgcD4uMDUpIFxuIikNCiAgbW9kZWwubWV0cmljcyAlPiUgDQogICAgbGV2ZW5lX3Rlc3QoYXMuZm9ybXVsYShwYXN0ZTAoIi5yZXNpZCIsICIgfiAiLCBjb25kX3Zhcl9uYW1lKSkgKSAlPiUgICAgIA0KICAgIHByaW50KCkNCiAgDQogIGNhdCgiXG4gT3V0bGllcnMgKG5lZWRzIHRvIGJlIDApIFxuIikNCiAgbW9kZWwubWV0cmljcyAlPiUgDQogICAgZmlsdGVyKGFicyguc3RkLnJlc2lkKSA+IDMpICU+JQ0KICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgDQogICAgcHJpbnQoKQ0KICANCiAgfQ0KICANCiAgY2F0KCJcbiBBTkNPVkFQb3N0IFxuIikNCiAgcmVzX2FuY292YSA8LSANCiAgICBkYXRhX3dpZGVyICU+JSANCiAgICBhbm92YV90ZXN0KGFzLmZvcm11bGEocGFzdGUwKHBvc3RfdmFyX25hbWUsICIgfiAiLCAgcHJlX3Zhcl9uYW1lLCAiICsgIiwgY29uZF92YXJfbmFtZSkpKSAgICAgICAjIHRoZSBjb3ZhcmlhdGUgbmVlZHMgdG8gYmUgZmlyc3QgdGVybSANCiAgZ2V0X2Fub3ZhX3RhYmxlKHJlc19hbmNvdmEpICU+JSBwcmludCgpDQogIA0KICBjYXQoIlxuIFBhaXJ3aXNlIGNvbXBhcmlzb25zIFxuIikNCiAgcHdjIDwtIA0KICAgIGRhdGFfd2lkZXIgJT4lIA0KICAgIGVtbWVhbnNfdGVzdChhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpLCAgICAgICANCiAgICAgICAgICAgICAgICAgY292YXJpYXRlID0gISFwcmVfdmFyX2VucSwNCiAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gcF9hZGp1c3RfbWV0aG9kKQ0KICBwd2MgJT4lIHByaW50KCkNCiAgY2F0KCJcbiBEaXNwbGF5IHRoZSBhZGp1c3RlZCBtZWFucyBvZiBlYWNoIGdyb3VwLCBhbHNvIGNhbGxlZCBhcyB0aGUgZXN0aW1hdGVkIG1hcmdpbmFsIG1lYW5zIChlbW1lYW5zKSBcbiIpDQogIGdldF9lbW1lYW5zKHB3YykgJT4lIHByaW50KCkNCiAgDQogICMgVmlzdWFsaXphdGlvbjogbGluZSBwbG90cyB3aXRoIHAtdmFsdWVzDQogIHB3YyA8LSANCiAgICBwd2MgJT4lIA0KICAgIGFkZF94eV9wb3NpdGlvbih4ID0gY29uZF92YXJfbmFtZSwgZnVuID0gIm1lYW5fc2UiKQ0KICANCiAgbGluZV9wbG90IDwtIA0KICAgIGdnbGluZShnZXRfZW1tZWFucyhwd2MpLCB4ID0gY29uZF92YXJfbmFtZSwgeSA9ICJlbW1lYW4iKSArDQogICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gY29uZi5sb3csIHltYXggPSBjb25mLmhpZ2gpLCB3aWR0aCA9IDAuMikgKyANCiAgICAgIHN0YXRfcHZhbHVlX21hbnVhbChwd2MsIGhpZGUubnMgPSBUUlVFLCB0aXAubGVuZ3RoID0gRkFMU0UpICsNCiAgICAgIGxhYnMoc3VidGl0bGUgPSBnZXRfdGVzdF9sYWJlbChyZXNfYW5jb3ZhLCBkZXRhaWxlZCA9IFRSVUUpLA0KICAgICAgICAgICBjYXB0aW9uID0gZ2V0X3B3Y19sYWJlbChwd2MpKQ0KICANCiAgaWYoYXNzdW1fY2hlY2spew0KICAgIGxpc3Qoc2NhdHRlcl9saW4sIGxpbmVfcGxvdCkNCiAgfWVsc2V7DQogICAgbGluZV9wbG90DQogIH0NCiAgDQp9DQoNCiMgZXguDQojIEFOQ09WQVBvc3RfZnVuYyhuZXdfYW54aWV0eSwgdGltZV92YXIgPSB0aW1lLCBwcmVfbGFiZWwgPSBwcmV0ZXN0LCBwb3N0X2xhYmVsID0gcG9zdHRlc3QsDQojICAgICAgICAgICB2YWx1ZV92YXIgPSBzY29yZXMsIGNvbmRfdmFyID0gZ3JvdXAsIGFzc3VtX2NoZWNrID0gVFJVRSwgcF9hZGp1c3RfbWV0aG9kID0gImJvbmZlcnJvbmkiKQ0KYGBgDQoNCg0KYGBge3IgZGVmX2Z1bmNfbWl4ZWRBTk9WQX0NCiMgbGlicmFyeSh0aWR5dmVyc2UpDQojIGxpYnJhcnkoZ2dwdWJyKQ0KIyBsaWJyYXJ5KHJzdGF0aXgpDQojIGxpYnJhcnkocmxhbmcpDQoNCiMgRGVmaW5lIEZ1bmN0aW9uIGZvciBNaXhlZCBBbm92YQ0KdHdfbWl4ZWRBTk9WQV9mdW5jIDwtIA0KICBmdW5jdGlvbihkYXRhLCBpZF92YXIsIGNvbmRfdmFyLCB0aW1lX3ZhciwgdmFsdWVfdmFyLCANCiAgICAgICAgICAgYXNzdW1fY2hlY2sgPSBUUlVFLCBwb3N0aG9jX3NpZ19pbnRlcmFjID0gRkFMU0UsIHBvc3Rob2NfbnNfaW50ZXJhYyA9IEZBTFNFLA0KICAgICAgICAgICBwX2FkanVzdF9tZXRob2QgPSAiYm9uZmVycm9uaSIpew0KICAgIA0KICAgICMgaW5wdXQgZGF0YWZyYW1lIG5lZWRzIHRvIGhhdmUgY29sdW1ucyBuYW1lcyBkaWZmcmVudCBmcm9tICJ2YXJpYWJsZSIgYW5kICJ2YWx1ZSIgYmVjYXVzZSBpdCBjb2xsaWRlcyB3aXRoIHJzdGF0aXg6OnNoYXBpcm9fdGVzdA0KICAgIA0KICAgIGlkX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKGlkX3ZhcikgIA0KICAgIGNvbmRfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8oY29uZF92YXIpDQogICAgY29uZF92YXJfbmFtZSA8LSBybGFuZzo6YXNfbmFtZShjb25kX3Zhcl9lbnEpDQogICAgdGltZV92YXJfZW5xIDwtIHJsYW5nOjplbnF1byh0aW1lX3ZhcikNCiAgICB0aW1lX3Zhcl9uYW1lIDwtIHJsYW5nOjphc19uYW1lKHRpbWVfdmFyX2VucSkNCiAgICB2YWx1ZV92YXJfZW5xIDwtIHJsYW5nOjplbnF1byh2YWx1ZV92YXIpDQogICAgdmFsdWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodmFsdWVfdmFyX2VucSkNCiAgICANCiAgICBkYXRhIDwtICAgICAgICAgICAgICAgICAgIyBuZWVkIHRvIHN1YnNldCBiZWN1YXNlIG9mIHN0cmFuZ2UgY29udHJhc3RzIGVycm9yIGluIGFub3ZhX3Rlc3QoKQ0KICAgICAgZGF0YSAlPiUNCiAgICAgIGRwbHlyOjpzZWxlY3QoISFpZF92YXJfZW5xLCAhIXRpbWVfdmFyX2VucSwgISFjb25kX3Zhcl9lbnEsICEhdmFsdWVfdmFyX2VucSkgDQogICAgDQogICAgIyBBc3N1bXB0aW9ucw0KICAgIGlmKGFzc3VtX2NoZWNrKXsNCiAgICAgIGNhdCgiXG4gT3V0bGllcnMgXG4iKQ0KICAgICAgZGF0YSAlPiUNCiAgICAgICAgZHBseXI6Omdyb3VwX2J5KCEhdGltZV92YXJfZW5xLCAhIWNvbmRfdmFyX2VucSkgJT4lDQogICAgICAgIHJzdGF0aXg6OmlkZW50aWZ5X291dGxpZXJzKCEhdmFsdWVfdmFyX2VucSkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgb3V0bGllcnMgKG5lZWRzIHRvIGJlIDApDQogICAgICAgIHByaW50KCkNCiAgICAgIA0KICAgICAgY2F0KCJcbiBOb3JtYWxpdHkgYXNzdW1wdGlvbiAocD4uMDUpIFxuIikNCiAgICAgIGRhdGEgJT4lDQogICAgICAgIGRwbHlyOjpncm91cF9ieSghIXRpbWVfdmFyX2VucSwgISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICByc3RhdGl4OjpzaGFwaXJvX3Rlc3QoISF2YWx1ZV92YXJfZW5xKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBub3JtYWxpdHkgYXNzdW1wdGlvbiAocD4uMDUpDQogICAgICAgIHByaW50KCkNCiAgICAgIA0KICAgICAgcXFfcGxvdCA8LSANCiAgICAgICAgZ2dwdWJyOjpnZ3FxcGxvdChkYXRhID0gZGF0YSwgdmFsdWVfdmFyX25hbWUsIGdndGhlbWUgPSB0aGVtZV9idygpLCB0aXRsZSA9ICJRUSBQbG90IikgKw0KICAgICAgICBnZ3Bsb3QyOjpmYWNldF9ncmlkKHZhcnMoISF0aW1lX3Zhcl9lbnEpLCB2YXJzKCEhY29uZF92YXJfZW5xKSwgbGFiZWxsZXIgPSAibGFiZWxfYm90aCIpICAgICMgUVEgcGxvdA0KICAgICAgDQogICAgICBjYXQoIlxuIEhvbW9nbmVpdHkgb2YgdmFyaWFuY2UgYXNzdW1wdGlvbiAtIExldmVuZeKAmXMgdGVzdCAocD4uMDUpIFxuIikNCiAgICAgIGRhdGEgJT4lDQogICAgICAgIGdyb3VwX2J5KCEhdGltZV92YXJfZW5xICkgJT4lDQogICAgICAgIGxldmVuZV90ZXN0KGFzLmZvcm11bGEocGFzdGUwKHZhbHVlX3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpKSAlPiUNCiAgICAgICAgcHJpbnQoKQ0KICAgICAgDQogICAgICBjYXQoIlxuIEhvbW9nZW5laXR5IG9mIGNvdmFyaWFuY2VzIGFzc3VtcHRpb24gLSBCb3jigJlzIHRlc3Qgb2YgZXF1YWxpdHkgb2YgY292YXJpYW5jZSBtYXRyaWNlcyAocD4uMDAxKSBcbiIpDQogICAgICBib3hfbShkYXRhID0gZGF0YVssIHZhbHVlX3Zhcl9uYW1lLCBkcm9wID0gRkFMU0VdLCBncm91cCA9IGRhdGFbLCBjb25kX3Zhcl9uYW1lLCBkcm9wID0gVFJVRV0pICU+JQ0KICAgICAgICBwcmludA0KICAgIH0NCiAgICANCiAgICAjIFR3by13YXkgcm1BTk9WQSAtIGNoZWNrIGZvciBpbnRlcmFjdGlvbiAoZXguIEYoMiwgMjIpID0gMzAuNCwgcCA8IDAuMDAwMSkNCiAgICBjYXQoIlxuIFR3by13YXkgcm1BTk9WQSBcbiIpDQogICAgcmVzX2FvdiA8LSANCiAgICAgIGFub3ZhX3Rlc3QoZGF0YSA9IGRhdGEsIGR2ID0gISF2YWx1ZV92YXJfZW5xLCB3aWQgPSAhIWlkX3Zhcl9lbnEsICAgICAgICAgICAgICAgIyBhdXRvbWF0aWNhbGx5IGRvZXMgc3BoZXJpY2l0eSBNYXVjaGx54oCZcyB0ZXN0DQogICAgICAgICAgICAgICAgIHdpdGhpbiA9ICEhdGltZV92YXJfZW5xLCBiZXR3ZWVuID0gISFjb25kX3Zhcl9lbnEpDQogICAgZ2V0X2Fub3ZhX3RhYmxlKHJlc19hb3YpICU+JSAgIyBnZXM6IEdyZWVuaG91c2UtR2Vpc3NlciBzcGhlcmljaXR5IGNvcnJlY3Rpb24gaXMgYXV0b21hdGljYWxseSBhcHBsaWVkIHRvIGZhY3RvcnMgdmlvbGF0aW5nIHRoZSBzcGhlcmljaXR5IGFzc3VtcHRpb24gIA0KICAgICAgcHJpbnQoKQ0KICAgIA0KICAgIA0KICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQogICAgDQogICAgIy0gUHJvY2VkdXJlIGZvciBhIHNpZ25pZmljYW50IHR3by13YXkgaW50ZXJhY3Rpb24gLQ0KICAgIGlmKHBvc3Rob2Nfc2lnX2ludGVyYWMpew0KICAgICAgY2F0KCJcbiBFZmZlY3Qgb2YgZ3JvdXAgYXQgZWFjaCB0aW1lIHBvaW50IC0gT25lLXdheSBBTk9WQVxuIikNCiAgICAgIG9uZV93YXkgPC0gDQogICAgICAgIGRhdGEgJT4lDQogICAgICAgIGdyb3VwX2J5KCEhdGltZV92YXJfZW5xKSAlPiUNCiAgICAgICAgYW5vdmFfdGVzdChkdiA9ICEhdmFsdWVfdmFyX2VucSwgd2lkID0gISFpZF92YXJfZW5xLCBiZXR3ZWVuID0gISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBnZXRfYW5vdmFfdGFibGUoKSAlPiUNCiAgICAgICAgYWRqdXN0X3B2YWx1ZShtZXRob2QgPSBwX2FkanVzdF9tZXRob2QpDQogICAgICBvbmVfd2F5ICU+JSBwcmludCgpDQogICAgICANCiAgICAgIGNhdCgiXG4gUGFpcndpc2UgY29tcGFyaXNvbnMgYmV0d2VlbiBncm91cCBsZXZlbHMgXG4iKQ0KICAgICAgcHdjIDwtIA0KICAgICAgICBkYXRhICU+JQ0KICAgICAgICBncm91cF9ieSghIXRpbWVfdmFyX2VucSkgJT4lDQogICAgICAgIHBhaXJ3aXNlX3RfdGVzdChhcy5mb3JtdWxhKHBhc3RlMCh2YWx1ZV92YXJfbmFtZSwgIiB+ICIsIGNvbmRfdmFyX25hbWUpKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QpDQogICAgICBwd2MgJT4lIHByaW50KCkNCiAgICAgIGNhdCgiXG4gRWZmZWN0IG9mIHRpbWUgYXQgZWFjaCBsZXZlbCBvZiBleGVyY2lzZXMgZ3JvdXAgIC0gT25lLXdheSBBTk9WQSBcbiIpDQogICAgICBvbmVfd2F5MiA8LSANCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgZ3JvdXBfYnkoISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBhbm92YV90ZXN0KGR2ID0gISF2YWx1ZV92YXJfZW5xLCB3aWQgPSAhIWlkX3Zhcl9lbnEsIHdpdGhpbiA9ICEhdGltZV92YXJfZW5xKSAlPiUNCiAgICAgICAgZ2V0X2Fub3ZhX3RhYmxlKCkgJT4lDQogICAgICAgIGFkanVzdF9wdmFsdWUobWV0aG9kID0gcF9hZGp1c3RfbWV0aG9kKQ0KICAgICAgb25lX3dheTIgJT4lIHByaW50KCkNCiAgICAgIA0KICAgICAgY2F0KCJcbiBQYWlyd2lzZSBjb21wYXJpc29ucyBiZXR3ZWVuIHRpbWUgcG9pbnRzIGF0IGVhY2ggZ3JvdXAgbGV2ZWxzICh3ZSBoYXZlIHJlcGVhdGVkIG1lYXN1cmVzIGJ5IHRpbWUpIFxuIikNCiAgICAgIHB3YzIgPC0NCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgZ3JvdXBfYnkoISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBwYWlyd2lzZV90X3Rlc3QoDQogICAgICAgICAgYXMuZm9ybXVsYShwYXN0ZTAodmFsdWVfdmFyX25hbWUsICIgfiAiLCB0aW1lX3Zhcl9uYW1lKSksICAgICAjIHBhc3RlIGZvcm11bGEsIG5vdCBxdW9zdXJlDQogICAgICAgICAgcGFpcmVkID0gVFJVRSwNCiAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QNCiAgICAgICAgKQ0KICAgICAgcHdjMiAgJT4lIHByaW50KCkNCiAgICB9DQogICAgDQogICAgIy0gUHJvY2VkdXJlIGZvciBub24tc2lnbmlmaWNhbnQgdHdvLXdheSBpbnRlcmFjdGlvbi0gDQogICAgIyBJZiB0aGUgaW50ZXJhY3Rpb24gaXMgbm90IHNpZ25pZmljYW50LCB5b3UgbmVlZCB0byBpbnRlcnByZXQgdGhlIG1haW4gZWZmZWN0cyBmb3IgZWFjaCBvZiB0aGUgdHdvIHZhcmlhYmxlczogdHJlYXRtZW50IGFuZCB0aW1lLg0KICAgIGlmKHBvc3Rob2NfbnNfaW50ZXJhYyl7DQogICAgICBjYXQoIlxuIENvbXBhcmlzb25zIGZvciB0cmVhdG1lbnQgdmFyaWFibGUgXG4iKQ0KICAgICAgcHdjX2NvbmQgPC0NCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgcGFpcndpc2VfdF90ZXN0KA0KICAgICAgICAgIGFzLmZvcm11bGEocGFzdGUwKHZhbHVlX3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpLCAgICAgIyBwYXN0ZSBmb3JtdWxhLCBub3QgcXVvc3VyZSAgICAgICAgICAgICANCiAgICAgICAgICBwYWlyZWQgPSBGQUxTRSwNCiAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QNCiAgICAgICAgKQ0KICAgICAgcHdjX2NvbmQgJT4lIHByaW50KCkNCiAgICAgIGNhdCgiXG4gQ29tcGFyaXNvbnMgZm9yIHRpbWUgdmFyaWFibGUgXG4iKQ0KICAgICAgcHdjX3RpbWUgPC0NCiAgICAgICAgZGF0YSAlPiUgDQogICAgICAgIHBhaXJ3aXNlX3RfdGVzdCgNCiAgICAgICAgICBhcy5mb3JtdWxhKHBhc3RlMCh2YWx1ZV92YXJfbmFtZSwgIiB+ICIsIHRpbWVfdmFyX25hbWUpKSwgICAgICMgcGFzdGUgZm9ybXVsYSwgbm90IHF1b3N1cmUNCiAgICAgICAgICBwYWlyZWQgPSBUUlVFLA0KICAgICAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9IHBfYWRqdXN0X21ldGhvZA0KICAgICAgICApDQogICAgICBwd2NfdGltZSAlPiUgcHJpbnQoKQ0KICAgIH0NCiAgICANCiAgICAjIFZpc3VhbGl6YXRpb24NCiAgICBieF9wbG90IDwtIA0KICAgICAgZ2dib3hwbG90KGRhdGEsIHggPSB0aW1lX3Zhcl9uYW1lLCB5ID0gdmFsdWVfdmFyX25hbWUsDQogICAgICAgICAgICAgICAgY29sb3IgPSBjb25kX3Zhcl9uYW1lLCBwYWxldHRlID0gImpjbyIpDQogICAgcHdjIDwtIA0KICAgICAgcHdjICU+JSANCiAgICAgIGFkZF94eV9wb3NpdGlvbih4ID0gdGltZV92YXJfbmFtZSkNCiAgICBieF9wbG90IDwtIA0KICAgICAgYnhfcGxvdCArIA0KICAgICAgc3RhdF9wdmFsdWVfbWFudWFsKHB3YywgdGlwLmxlbmd0aCA9IDAsIGhpZGUubnMgPSBUUlVFKSArDQogICAgICBsYWJzKA0KICAgICAgICBzdWJ0aXRsZSA9IGdldF90ZXN0X2xhYmVsKHJlc19hb3YsIGRldGFpbGVkID0gVFJVRSksDQogICAgICAgIGNhcHRpb24gPSBnZXRfcHdjX2xhYmVsKHB3YykNCiAgICAgICkNCiAgICANCiAgICBpZihhc3N1bV9jaGVjayl7IA0KICAgICAgbGlzdChxcV9wbG90LCBieF9wbG90KQ0KICAgIH1lbHNlew0KICAgICAgYnhfcGxvdA0KICAgIH0gDQogICAgDQogIH0NCg0KIyBleC4gLSBydW4gb24gbG9uZyBmb3JtYXQNCiMgdHdfbWl4ZWRBTk9WQV9mdW5jKGRhdGEgPSBhbnhpZXR5LCBpZF92YXIgPSBpZCwgY29uZF92YXIgPSBncm91cCwgdGltZV92YXIgPSB0aW1lLCB2YWx1ZV92YXIgPSBzY29yZSwNCiMgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KDQpgYGANCg0KDQoNCiMgUmVhZCwgQ2xlYW4sIFJlY29kZQ0KDQpgYGB7ciByZWRfY2xlYW5fcmVjb2RlX21lcmdlLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0NCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+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+fg0KDQojIyBSZWFkIGZpbGVzDQpmb2xkZXIgPC0gIkM6L1VzZXJzL01paGFpL0Rlc2t0b3AvUiBOb3RlYm9va3Mvbm90ZWJvb2tzL1BBNC1yZXBvcnQiDQpmaWxlIDwtICJEYXRlX3B0X2FuYWxpemFfUEE0b25saW5lLnhsc3giDQoNCnNldHdkKGZvbGRlcikNCg0KIyBJRCBkZg0KaWRfZGYgPC0gcmlvOjppbXBvcnQoZmlsZS5wYXRoKGZvbGRlciwgZmlsZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDEsIHdoaWNoID0gIklELXVyaSBhdHJpYnVpdGUiKSAgIA0KaWRfZGYgPC0gDQogIGlkX2RmICU+JQ0KICBkcGx5cjo6bXV0YXRlKElEID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKElELCBmaXhlZCgiICIpLCAiIikpICAgICAjIHJlbW92ZSB3aGl0ZSBzcGFjZXMNCmFsbChpZF9kZiRJRCA9PSB0b3VwcGVyKGlkX2RmJElEKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjaGVjayBpZiBhbGwgYXJlIHVwcGVyIGNhc2UNCg0KZmlyc3Rmb3JtX2RmIDwtIHJpbzo6aW1wb3J0KGZpbGUucGF0aChmb2xkZXIsIGZpbGUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAwLCB3aGljaCA9ICJGb3JtdWxhciBkZSDDrm5zY3JpZXJlIMiZaSBjb25zaW0iKSANCmNvbG5hbWVzKGZpcnN0Zm9ybV9kZilbN10gPC0gImUtbWFpbCINCg0KYmFzZWxpbmVfZGYgPC0gZHBseXI6OmxlZnRfam9pbihpZF9kZiwgZmlyc3Rmb3JtX2RmLCBieSA9ICJlLW1haWwiKQ0KYmFzZWxpbmVfZGYgPC0gYmFzZWxpbmVfZGZbLCBjKDQ6OSwgMiwgMTA6bmNvbChiYXNlbGluZV9kZiksIDEsMyldICAgICAgICMgbW92ZSBjb2xzIGZyb20gaWRfZGYgdG8gYmFjayBzbyB3ZSBoYXZlIG1hdGNoaW5nIGNvbHMgaW5kZXggZm9yIGJhc2VsaW5lX2RmICYgZmlyc3Rmb3JtX2RmDQphbGwuZXF1YWwoY29sbmFtZXMoYmFzZWxpbmVfZGYpWzE6NzJdLCBjb2xuYW1lcyhmaXJzdGZvcm1fZGYpWzE6NzJdKSAgICAgICAgICAgICAjIGNoZWNrIGlmIGNvbG5hbWVzIG1hdGNoLCBleGNlcHQgSUQgYW5kIG5hbWUgdGhhdCB3aGVyZSBhZGRlZA0KDQp0YWJsZShiYXNlbGluZV9kZiRJRCkgIyBJRCA5QyBpcyBkb3VibGVkLCBjb21wbGV0ZWQgMiB0aW1lcw0Kd2hpY2goYmFzZWxpbmVfZGYkSUQgPT0gIjlDIikgICMgSUQgOUMgcm93IDI3IGlzIHBhcnRpYWxseSBjb21wbGV0ZWQsIGV4Y3V0ZWQgaXQNCmJhc2VsaW5lX2RmIDwtIGJhc2VsaW5lX2RmWy0yNyAsXQ0KYGBgDQoNCg0KYGBge3IgZGFzZH0NCiMjIFNldHRpbmdzDQpjdXRvZmZQQ0wgPC0gMzIgICAjIGxpdGVyYXR1cmU6IDMxLTMzIG9yIDM4IA0KYWxnUENMIDwtIGRhdGEuZnJhbWUoQiA9IDEsIEMgPSAxLCBEID0gMiwgRSA9IDIpDQphbGdQQ0xfc3ViY2xpbiA8LSBkYXRhLmZyYW1lKEIgPSAxLCBDID0gMSwgRCA9IDEsIEUgPSAxKQ0KDQpjdXRvZmZNQklfRXggPC0gMi4yMCAgDQpjdXRvZmZNQklfQ3kgPC0gMg0KIyMNCg0KIyMgRGF0YQ0KRGF0YSA8LSBiYXNlbGluZV9kZg0KIyMNCg0KIyBEZWZpbmUgY29sdW1uIGluZGV4OiAgaW5kZXggPSBjb2wgaW5kZXg7IGl0ZW1pbmRleCA9IGluZGV4IG9mIGl0ZW0gaW4gcXVlc3Rpb25uYWlyZQ0KaW5kZXhTSUcgPC0gNjA6NjcgLSAxMCAgICAjIG1vZGlmaWVkIGluIG5ldyB0YWJsZSBieSAxMA0KaW5kZXhNQkkgPC0gNjg6ODMgLSAxMA0KaW5kZXhQQ0wgPC0gMTU5OjE3OCAtIDEwDQppdGVtaW5kZXhNQklfRXggPC0gYygxLCAzLCA1LCAxMSwgMTQpDQppdGVtaW5kZXhNQklfQ3kgPC0gYygyLCA3LCA4LCAxMywgMTUpDQppdGVtaW5kZXhNQklfUGUgPC0gYyg0LCA2LCA5LCAxMCwgMTIsIDE2KQ0KDQojIFJlbmFtZSBjb2x1bW5zDQojIG5hbWVzKERhdGEpWzE6MTJdIDwtIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChuYW1lcyhEYXRhKVsxOjEyXSwgIltbOmJsYW5rOl1dIiwgIl8iKQ0KIyBuYW1lcyhEYXRhKVsxN10gPC0gIlJlYWxfRW1haWwiDQojIG5hbWVzKERhdGEpWzE4XSA8LSAiUmVhbF9UZWwiDQojIG5hbWVzKERhdGEpWzE5XSA8LSAiUmVhbF9OYW1lIg0KIyBuYW1lcyhEYXRhKVs1MF0gPC0gIlJlYWxfQWdlX2NhdGVnIg0KDQpuYW1lcyhEYXRhKVs0MF0gPC0gIkFnZV9jYXRlZyINCm5hbWVzKERhdGEpWzQxXSA8LSAiU2V4Ig0KDQpuYW1lcyhEYXRhKVtuYW1lcyhEYXRhKSAlaW4lIG5hbWVzKERhdGFbLCBpbmRleFNJR10pXSAgPC0gYyhzcHJpbnRmKCJTSUdfJTAxZCIsIHNlcSgxLCA4KSkpDQpuYW1lcyhEYXRhKVtuYW1lcyhEYXRhKSAlaW4lIG5hbWVzKERhdGFbLCBpbmRleE1CSV0pXSAgPC0gYyhzcHJpbnRmKCJNQklfJTAxZCIsIHNlcSgxLCAxNikpKQ0KbmFtZXMoRGF0YSlbbmFtZXMoRGF0YSkgJWluJSBuYW1lcyhEYXRhWywgaW5kZXhQQ0xdKV0gIDwtIGMoc3ByaW50ZigiUENMXyUwMWQiLCBzZXEoMSwgMjApKSkNCg0KDQojIERhdGEgPC0NCiMgICBEYXRhICU+JQ0KIyAgIGRwbHlyOjpmaWx0ZXIoUmVzcG9uc2VfU3RhdHVzID09ICJjb21wbGV0ZWQiKSAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzZWxlY3Qgb25seSBjb21wbGV0ZSBjYXNlcw0KIA0KDQojIFJlY29kZSANCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHJlY29kZXMgdG8gbnVtZXJpYywgYnV0IHdhdGNoZXMgb3V0IHRvIGNvZXJjaW9uIHRvIG5vdCBpbnRyb2R1Y2UgTkFzDQpjb2xzdG9udW1lcmljIDwtIGZ1bmN0aW9uKGRmKXsNCiAgdHJ5Q2F0Y2goew0KICAgIGRmX251bSA8LSBhcy5kYXRhLmZyYW1lKA0KICAgICAgbGFwcGx5KGRmLA0KICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHsgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpfSkpIA0KICB9LHdhcm5pbmcgPSBmdW5jdGlvbihzdG9wX29uX3dhcm5pbmcpIHsNCiAgICBtZXNzYWdlKCJTdG9wZWQgdGhlIGV4ZWN1dGlvbiBvZiBudW1lcmljIGNvbnZlcnNpb246ICIsIGNvbmRpdGlvbk1lc3NhZ2Uoc3RvcF9vbl93YXJuaW5nKSkNCiAgfSkgDQp9DQojIw0KIyMgRGVmaW5lIGZ1bmN0aW9uIHRoYXQgcmV2ZXJzZSBjb2RlcyBpdGVtcw0KUmV2ZXJzZUNvZGUgPC0gZnVuY3Rpb24oZGYsIHRvbnVtZXJpYyA9IEZBTFNFLCBtaW4gPSBOVUxMLCBtYXggPSBOVUxMKSB7DQogIGlmKHRvbnVtZXJpYykgZGYgPC0gY29sc3RvbnVtZXJpYyhkZikNCiAgZGYgPC0gKG1heCArIG1pbikgLSBkZg0KfQ0KIyMNCg0KIyBsYXBwbHkoRGF0YVssaW5kZXhQQ0xdLCB1bmlxdWUpDQpEYXRhWyAsaW5kZXhQQ0xdWyBEYXRhWyAsaW5kZXhQQ0xdID09ICJkZWxvYyJdIDwtICIwIg0KRGF0YVsgLGluZGV4UENMXVsgRGF0YVsgLGluZGV4UENMXSA9PSAicHXIm2luIl0gPC0gIjEiDQpEYXRhWyAsaW5kZXhQQ0xdWyBEYXRhWyAsaW5kZXhQQ0xdID09ICJtb2RlcmF0Il0gPC0gIjIiDQpEYXRhWyAsaW5kZXhQQ0xdWyBEYXRhWyAsaW5kZXhQQ0xdID09ICJtdWx0Il0gPC0gIjMiDQpEYXRhWyAsaW5kZXhQQ0xdWyBEYXRhWyAsaW5kZXhQQ0xdID09ICJmb2FydGUgbXVsdCJdIDwtICI0Ig0KRGF0YVsgLGluZGV4UENMXVsgRGF0YVsgLGluZGV4UENMXSA9PSAiTm90IEFuc3dlcmVkIl0gPC0gTkENCg0KRGF0YVsgLGluZGV4U0lHXVsgRGF0YVsgLGluZGV4U0lHXSA9PSAiTlUiXSA8LSAiMCINCkRhdGFbICxpbmRleFNJR11bIERhdGFbICxpbmRleFNJR10gPT0gIj8iXSA8LSAiMS41Ig0KRGF0YVsgLGluZGV4U0lHXVsgRGF0YVsgLGluZGV4U0lHXSA9PSAiREEiXSA8LSAiMyINCkRhdGFbICxpbmRleFNJR11bIERhdGFbICxpbmRleFNJR10gPT0gIk5vdCBBbnN3ZXJlZCJdIDwtIE5BDQoNCkRhdGFbICxpbmRleE1CSV0gPC0gZGF0YS5mcmFtZShsYXBwbHkoRGF0YVsgLGluZGV4TUJJXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKk5pY2lvZGF0LioiLCAiMCIsIHgpfSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCkRhdGFbICxpbmRleE1CSV0gPC0gZGF0YS5mcmFtZShsYXBwbHkoRGF0YVsgLGluZGV4TUJJXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKlppbG5pYy4qIiwgIjYiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpEYXRhWyAsaW5kZXhNQkldWyBEYXRhWyAsaW5kZXhNQkldID09ICJOb3QgQW5zd2VyZWQiXSA8LSBOQQ0KDQoNCkRhdGFbLCBpbmRleFNJR10gPC0gY29sc3RvbnVtZXJpYyhEYXRhWywgaW5kZXhTSUddKQ0KRGF0YVssIGluZGV4TUJJXSA8LSBjb2xzdG9udW1lcmljKERhdGFbLCBpbmRleE1CSV0pDQpEYXRhWywgaW5kZXhQQ0xdIDwtIGNvbHN0b251bWVyaWMoRGF0YVssIGluZGV4UENMXSkNCg0KDQoNCiMgU2NvcmVzDQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCBzY29yZXMgb25seSByb3dzIHdpdGggbGVzcyB0aGFuIDEwJSBOQXMgKHJldHVybnMgTkEgaWYgYWxsIG9yIGFib3ZlIHRocmVzaG9sZCBwZXJjZW50YWdlIG9mIHJvd3MgYXJlIE5BKTsgY2FuIHJldmVyc2UgY29kZSBpZiB2ZWN0b3Igb2YgY29sdW1uIGluZGV4ZXMgYW5kIG1pbiwgbWF4IGFyZSBwcm92aWRlZC4NClNjb3JlTGlrZXJ0IDwtIGZ1bmN0aW9uKGRmLCBzdGF0ID0gInN1bSIsIG5hdG96ZXJvID0gRkFMU0UsIG5hcGVyY2VudCA9IC4xLCB0b251bWVyaWMgPSBGQUxTRSwgcmV2ZXJzZWNvbHMgPSBOVUxMLCBtaW4gPSBOVUxMLCBtYXggPSBOVUxMKSB7DQogIHJldmVyc2VfbGlzdCA8LSBsaXN0KHJldmVyc2Vjb2xzID0gcmV2ZXJzZWNvbHMsIG1pbiA9IG1pbiwgbWF4ID0gbWF4KQ0KICByZXZlcnNlX2NoZWNrIDwtICFzYXBwbHkocmV2ZXJzZV9saXN0LCBpcy5udWxsKQ0KICANCiAgIyBSZWNvZGUgdG8gbnVtZXJpYywgYnV0IHdhdGNoIG91dCB0byBjb2VyY2lvbiB0byBub3QgaW50cm9kdWNlIE5Bcw0KICBjb2xzdG9udW1lcmljIDwtIGZ1bmN0aW9uKGRmKXsNCiAgICB0cnlDYXRjaCh7DQogICAgICBkZl9udW0gPC0gYXMuZGF0YS5mcmFtZSgNCiAgICAgICAgbGFwcGx5KGRmLA0KICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgeyBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4KSl9KSkgDQogICAgfSx3YXJuaW5nID0gZnVuY3Rpb24oc3RvcF9vbl93YXJuaW5nKSB7DQogICAgICBtZXNzYWdlKCJTdG9wZWQgdGhlIGV4ZWN1dGlvbiBvZiBudW1lcmljIGNvbnZlcnNpb246ICIsIGNvbmRpdGlvbk1lc3NhZ2Uoc3RvcF9vbl93YXJuaW5nKSkNCiAgICB9KSANCiAgfQ0KICANCiAgaWYodG9udW1lcmljKSBkZiA8LSBjb2xzdG9udW1lcmljKGRmKQ0KICANCiAgaWYoYWxsKHJldmVyc2VfY2hlY2spKXsNCiAgICBkZlsgLHJldmVyc2Vjb2xzXSA8LSAobWF4ICsgbWluKSAtIGRmWyAscmV2ZXJzZWNvbHNdDQogIH1lbHNlIGlmKGFueShyZXZlcnNlX2NoZWNrKSl7DQogICAgc3RvcCgiSW5zdWZpY2llbnQgaW5mbyBmb3IgcmV2ZXJzaW5nLiBQbGVhc2UgcHJvdmlkZTogIiwgcGFzdGUobmFtZXMocmV2ZXJzZV9saXN0KVshcmV2ZXJzZV9jaGVja10sIGNvbGxhcHNlID0gIiwgIikpDQogIH0NCiAgDQogIGlmKHRvbnVtZXJpYykgZGYgPC0gY29sc3RvbnVtZXJpYyhkZikgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgDQogIGlmKG5hdG96ZXJvKSBkZltpcy5uYShkZildIDwtIDAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE5BcyB0byAwIGNhbiBoZWxwIHdoZW4gc3RhdCA9ICJtZWFuIiB3aXRoIG5hLnJtID0gVCBiZWNhdXNlIGl0IGtlZXBzIGRlbm9taW5hdG9yIGNvbnN0YW50DQogIA0KICBpZihzdGF0ID09ICJzdW0iKXsNCiAgZGZfcmVzIDwtIGlmZWxzZShyb3dTdW1zKGlzLm5hKGRmKSkgPiBuY29sKGRmKSAqIG5hcGVyY2VudCwNCiAgICAgICAgICAgICAgICAgICBOQSwNCiAgICAgICAgICAgICAgICAgICByb3dTdW1zKGRmLCBuYS5ybSA9IFRSVUUpICogTkEgXiAocm93U3VtcyghaXMubmEoZGYpKSA9PSAwKSkNCiAgfQ0KICBpZihzdGF0ID09ICJtZWFuIil7DQogICAgZGZfcmVzIDwtIGlmZWxzZShyb3dTdW1zKGlzLm5hKGRmKSkgPiBuY29sKGRmKSAqIG5hcGVyY2VudCwNCiAgICAgICAgICAgICAgICAgICAgIE5BLA0KICAgICAgICAgICAgICAgICAgICAgcm93TWVhbnMoZGYsIG5hLnJtID0gVFJVRSkgKiBOQSBeIChyb3dTdW1zKCFpcy5uYShkZikpID09IDApKQ0KICB9DQogIHJldHVybihkZl9yZXMpDQp9DQojIw0KDQoNCiMgU2NvcmUgUENMDQpEYXRhJFBDTF9Ub3RhbCA8LSBTY29yZUxpa2VydChEYXRhWywgaW5kZXhQQ0xdLCBuYXBlcmNlbnQgPSAuMykgICAgICAgICAgICAgICAjIE5BIGlmIE5BIHRocmVzaG9sZCBpcyBleGNlZWRlZCANCkRhdGEkUENMX0IgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGMoc3ByaW50ZigiUENMXyUwMWQiLCAxOjUpKV0sIG5hcGVyY2VudCA9IDEpICAgICMgZG8gbm90aGluZyBpZiBOQSB0aHJlc2hvbGQgaXMgZXhjZWVkZWQNCkRhdGEkUENMX0MgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGMoc3ByaW50ZigiUENMXyUwMWQiLCA2OjcpKV0sIG5hcGVyY2VudCA9IDEpIA0KRGF0YSRQQ0xfRCA8LSBTY29yZUxpa2VydChEYXRhWywgYyhzcHJpbnRmKCJQQ0xfJTAxZCIsIDg6MTQpKV0sIG5hcGVyY2VudCA9IDEpICANCkRhdGEkUENMX0UgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGMoc3ByaW50ZigiUENMXyUwMWQiLCAxNToyMCkpXSwgbmFwZXJjZW50ID0gMSkNCg0KIyBTY29yZSBTSUcNCkRhdGEkU0lHX1RvdGFsIDwtIFNjb3JlTGlrZXJ0KERhdGFbLCBpbmRleFNJR10sIG5hcGVyY2VudCA9IC4zKQ0KDQojIFNjb3JlIE1CSQ0KRGF0YSRNQklfVG90YWwgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGluZGV4TUJJXSwgbmFwZXJjZW50ID0gLjMsIHN0YXQgPSAibWVhbiIsIG5hdG96ZXJvID0gVFJVRSkNCkRhdGEkTUJJX0V4IDwtIFNjb3JlTGlrZXJ0KERhdGFbLCBjKHNwcmludGYoIk1CSV8lMDFkIiwgaXRlbWluZGV4TUJJX0V4KSldLCBuYXBlcmNlbnQgPSAxLCBzdGF0ID0gIm1lYW4iLCBuYXRvemVybyA9IFRSVUUpDQpEYXRhJE1CSV9DeSA8LSBTY29yZUxpa2VydChEYXRhWywgYyhzcHJpbnRmKCJNQklfJTAxZCIsIGl0ZW1pbmRleE1CSV9DeSkpXSwgbmFwZXJjZW50ID0gMSwgc3RhdCA9ICJtZWFuIiwgbmF0b3plcm8gPSBUUlVFKQ0KRGF0YSRNQklfUGUgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGMoc3ByaW50ZigiTUJJXyUwMWQiLCBpdGVtaW5kZXhNQklfUGUpKV0sIG5hcGVyY2VudCA9IDEsIHN0YXQgPSAibWVhbiIsIG5hdG96ZXJvID0gVFJVRSkNCg0KDQojIFBDTCBEaWFnbm9zdGljIEFsZ29yaXRobQ0KaXRlbXNQQ0xfQiA8LSBjKHNwcmludGYoIlBDTF8lMDFkIiwgMTo1KSkNCml0ZW1zUENMX0MgPC0gYyhzcHJpbnRmKCJQQ0xfJTAxZCIsIDY6NykpDQppdGVtc1BDTF9EIDwtIGMoc3ByaW50ZigiUENMXyUwMWQiLCA4OjE0KSkNCml0ZW1zUENMX0UgPC0gYyhzcHJpbnRmKCJQQ0xfJTAxZCIsIDE1OjIwKSkNCg0KRGF0YVBDTEFsZyA8LSAgDQogIERhdGEgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHRpZHlzZWxlY3Q6OmFsbF9vZihpbmRleFBDTCkpICU+JSANCiAgZHBseXI6Om11dGF0ZV9hbGwoDQogICAgZnVucyhjYXNlX3doZW4oDQogICAgICAuID49MiB+IDEsDQogICAgICAjIC4gPDIgfiAwLA0KICAgICAgaXMubmEoLikgfiAwLA0KICAgICAgVFJVRSAgfiAgMCkpKSAlPiUgDQogIA0KICBtdXRhdGUoUENMX0NyaXRCID0gY2FzZV93aGVuKHJvd1N1bXMoLlssaXRlbXNQQ0xfQl0sIG5hLnJtID0gVFJVRSkgPj0gYWxnUENMJEIgfiAxLCAgICAgICMgYWxnUENMIDwtIGRhdGEuZnJhbWUoQiA9IDEsIEMgPSAxLCBEID0gMiwgRSA9IDIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByb3dTdW1zKC5bLGl0ZW1zUENMX0JdLCBuYS5ybSA9IFRSVUUpIDwxIH4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFICB+ICAwKSkgJT4lIA0KICBtdXRhdGUoUENMX0NyaXRDID0gY2FzZV93aGVuKHJvd1N1bXMoLlssaXRlbXNQQ0xfQ10sIG5hLnJtID0gVFJVRSkgPj0gYWxnUENMJEMgfiAxLCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJvd1N1bXMoLlssaXRlbXNQQ0xfQ10sIG5hLnJtID0gVFJVRSkgPDEgfiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDApKSAlPiUgDQogIG11dGF0ZShQQ0xfQ3JpdEQgPSBjYXNlX3doZW4ocm93U3VtcyguWyxpdGVtc1BDTF9EXSwgbmEucm0gPSBUUlVFKSA+PSBhbGdQQ0wkRCB+IDEsICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByb3dTdW1zKC5bLGl0ZW1zUENMX0RdLCBuYS5ybSA9IFRSVUUpIDwxIH4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFICB+ICAwKSkgJT4lIA0KICBtdXRhdGUoUENMX0NyaXRFID0gY2FzZV93aGVuKHJvd1N1bXMoLlssaXRlbXNQQ0xfRV0sIG5hLnJtID0gVFJVRSkgPj0gYWxnUENMJEUgfiAxLCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJvd1N1bXMoLlssaXRlbXNQQ0xfRV0sIG5hLnJtID0gVFJVRSkgPDEgfiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDApKSAlPiUgDQogIG11dGF0ZShQQ0xfQWxnID0gY2FzZV93aGVuKFBDTF9Dcml0QiA9PSAxICYgUENMX0NyaXRDID09IDEgJiBQQ0xfQ3JpdEQgPT0gMSAmIFBDTF9Dcml0RSA9PSAxIH4gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSAgfiAgMCkpIA0KDQpEYXRhJFBDTEFsZyA8LSBEYXRhUENMQWxnJFBDTF9BbGcNCg0KRGF0YVBDTEFsZ19zdWJjbGluIDwtICANCiAgRGF0YSAlPiUgDQogIGRwbHlyOjpzZWxlY3QodGlkeXNlbGVjdDo6YWxsX29mKGluZGV4UENMKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlX2FsbCgNCiAgICBmdW5zKGNhc2Vfd2hlbigNCiAgICAgIC4gPj0yIH4gMSwNCiAgICAgICMgLiA8MiB+IDAsDQogICAgICBpcy5uYSguKSB+IDAsDQogICAgICBUUlVFICB+ICAwKSkpICU+JSANCiAgDQogIG11dGF0ZShQQ0xfQ3JpdEIgPSBjYXNlX3doZW4ocm93U3VtcyguWyxpdGVtc1BDTF9CXSwgbmEucm0gPSBUUlVFKSA+PSBhbGdQQ0xfc3ViY2xpbiRCIH4gMSwgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcm93U3VtcyguWyxpdGVtc1BDTF9CXSwgbmEucm0gPSBUUlVFKSA8MSB+IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSAgfiAgMCkpICU+JSANCiAgbXV0YXRlKFBDTF9Dcml0QyA9IGNhc2Vfd2hlbihyb3dTdW1zKC5bLGl0ZW1zUENMX0NdLCBuYS5ybSA9IFRSVUUpID49IGFsZ1BDTF9zdWJjbGluJEMgfiAxLCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJvd1N1bXMoLlssaXRlbXNQQ0xfQ10sIG5hLnJtID0gVFJVRSkgPDEgfiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDApKSAlPiUgDQogIG11dGF0ZShQQ0xfQ3JpdEQgPSBjYXNlX3doZW4ocm93U3VtcyguWyxpdGVtc1BDTF9EXSwgbmEucm0gPSBUUlVFKSA+PSBhbGdQQ0xfc3ViY2xpbiREIH4gMSwgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJvd1N1bXMoLlssaXRlbXNQQ0xfRF0sIG5hLnJtID0gVFJVRSkgPDEgfiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDApKSAlPiUgDQogIG11dGF0ZShQQ0xfQ3JpdEUgPSBjYXNlX3doZW4ocm93U3VtcyguWyxpdGVtc1BDTF9FXSwgbmEucm0gPSBUUlVFKSA+PSBhbGdQQ0xfc3ViY2xpbiRFIH4gMSwgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByb3dTdW1zKC5bLGl0ZW1zUENMX0VdLCBuYS5ybSA9IFRSVUUpIDwxIH4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFICB+ICAwKSkgJT4lIA0KICBtdXRhdGUoUENMX0FsZ19zdWJjbGluID0gY2FzZV93aGVuKFBDTF9Dcml0QiA9PSAxICYgUENMX0NyaXRDID09IDEgJiBQQ0xfQ3JpdEQgPT0gMSAmIFBDTF9Dcml0RSA9PSAxIH4gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFICB+ICAwKSkgDQoNCkRhdGEkUENMQWxnX3N1YmNsaW4gPC0gRGF0YVBDTEFsZ19zdWJjbGluJFBDTF9BbGdfc3ViY2xpbg0KDQpEYXRhJE1CSV9FeF9jdXQgPC0gaWZlbHNlKERhdGEkTUJJX0V4ID49IGN1dG9mZk1CSV9FeCwgMSwgMCkNCkRhdGEkTUJJX0N5X2N1dCA8LSBpZmVsc2UoRGF0YSRNQklfQ3kgPj0gY3V0b2ZmTUJJX0N5LCAxLCAwKQ0KDQoNCiMgR2xvYmFsIFNjcmVlbmluZyAmIEdyb3Vwcw0KZGZfc2NyZWVuaW5nIDwtIERhdGFbLGMoIklEIiwgIm51bWUiLCAiZS1tYWlsIiwgIkFnZV9jYXRlZyIsICJTZXgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIlNJR19Ub3RhbCIsICJNQklfRXhfY3V0IiwgIk1CSV9DeV9jdXQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIlBDTF9Ub3RhbCIsICJQQ0xfQiIsICJQQ0xfQyIsICJQQ0xfRCIsICJQQ0xfRSIsICJQQ0xBbGciLCAiUENMQWxnX3N1YmNsaW4iKV0NCmlkc19wdHNkIDwtDQogIGRmX3NjcmVlbmluZyAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyKFBDTEFsZyA9PSAxKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElEKSAlPiUNCiAgICBkcGx5cjo6cHVsbCgpDQoNCmlkc19idXJuIDwtDQogIGRmX3NjcmVlbmluZyAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyKE1CSV9FeF9jdXQgPT0gMSwgTUJJX0N5X2N1dCA9PSAxKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElEKSAlPiUNCiAgICBkcGx5cjo6cHVsbCgpDQoNCmlkc19vbGQgPC0NCiAgZGZfc2NyZWVuaW5nICU+JQ0KICAgIGRwbHlyOjpmaWx0ZXIoQWdlX2NhdGVnID09ICJwZXN0ZSA2NSBhbmkiKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElEKSAlPiUNCiAgICBkcGx5cjo6cHVsbCgpDQoNCmlkc19ub3JtYWwgPC0NCiAgIGRmX3NjcmVlbmluZyAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyKCEoSUQgJWluJSBjKGlkc19wdHNkLCBpZHNfYnVybiwgaWRzX29sZCkpKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElEKSAlPiUNCiAgICBkcGx5cjo6cHVsbCgpDQoNCmludGVyc2VjdChpZHNfcHRzZCwgaWRzX2J1cm4pICAgIyA4IGNvbW1vbg0KaW50ZXJzZWN0KGlkc19wdHNkLCBpZHNfb2xkKSAgICAjIG5vIG9sZCB3aXRoIFBUU0QNCmludGVyc2VjdChpZHNfcHRzZCwgaWRzX29sZCkgICAgIyBubyBvbGQgd2l0aCBCdXJuIE91dA0KbGVuZ3RoKHVuaXF1ZShjKGlkc19wdHNkLCBpZHNfYnVybiwgaWRzX29sZCwgaWRzX25vcm1hbCkpKSA9PSA3NiAgIyBhbGwgZ29vZA0KDQoNCmlkc19ncm91cHNfZGY8LSANCiAgRGF0YSAlPiUNCiAgZHBseXI6OnNlbGVjdCgxNzMsIDE3NToxODgpDQpgYGANCg0KDQoNCg0KIyBPdXRjb21lIE1lYXN1cmVzDQoNCiMgRGljdGF0b3IgR2FtZQ0KDQpgYGB7ciBkZ19zY29yaW5nLCByZXN1bHRzPSdoaWRlJ30NCiMgREcgZGYNCmRnX2RmX3ByZSA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDAsIHdoaWNoID0gIkRpY3RhdG9yR2FtZSBwcmUiKQ0KY29sbmFtZXMoZGdfZGZfcHJlKVs0XSA8LSAiSUQiDQpkZ19kZl9wcmUgPC0gDQogIGRnX2RmX3ByZSAlPiUNCiAgZHBseXI6Om11dGF0ZShJRCA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChJRCwgZml4ZWQoIiAiKSwgIiIpKSAlPiUgICAgIyByZW1vdmUgd2hpdGUgc3BhY2VzDQogIGRwbHlyOjptdXRhdGUoSUQgPSB0b3VwcGVyKElEKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdG8gdXBwZXINCmFsbChkZ19kZl9wcmUkSUQgPT0gdG91cHBlcihkZ19kZl9wcmUkSUQpKSANCg0KZGdfZGZfcG9zdCA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDAsIHdoaWNoID0gIkRpY3RhdG9yR2FtZSBwb3N0IikNCmNvbG5hbWVzKGRnX2RmX3Bvc3QpWzRdIDwtICJJRCINCmRnX2RmX3Bvc3QgPC0gDQogIGRnX2RmX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGUoSUQgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoSUQsIGZpeGVkKCIgIiksICIiKSkgJT4lICAgICMgcmVtb3ZlIHdoaXRlIHNwYWNlcw0KICBkcGx5cjo6bXV0YXRlKElEID0gdG91cHBlcihJRCkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRvIHVwcGVyDQphbGwoZGdfZGZfcG9zdCRJRCA9PSB0b3VwcGVyKGRnX2RmX3Bvc3QkSUQpKSANCg0KY29sbmFtZXMoZGdfZGZfcHJlKVs1OjhdIDwtIHNwcmludGYoIkRHXyVkIiwgMTo0KQ0KY29sbmFtZXMoZGdfZGZfcG9zdClbNTo4XSA8LSBzcHJpbnRmKCJER18lZCIsIDE6NCkNCg0KDQpkZ19kZl9wcmUgPC0NCiAgZGdfZGZfcHJlICU+JQ0KICBkcGx5cjo6bXV0YXRlKGBEYXRlIE1vZGlmaWVkYCA9IGx1YnJpZGF0ZTo6eW1kX2htcyhmb3JtYXQoYERhdGUgTW9kaWZpZWRgLCAiJVktJW0tJWQgJUg6JU06JVMiLCB0eiA9ICJVVEMiKSkpICU+JQ0KICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCB+bmFfaWYoLiwgIk5vdCBBbnN3ZXJlZCIpKQ0KDQpkZ19kZl9wb3N0IDwtDQogIGRnX2RmX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGUoYERhdGUgTW9kaWZpZWRgID0gbHVicmlkYXRlOjp5bWRfaG1zKGZvcm1hdChgRGF0ZSBNb2RpZmllZGAsICIlWS0lbS0lZCAlSDolTTolUyIsIHR6ID0gIlVUQyIpKSkgJT4lDQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIH5kcGx5cjo6bmFfaWYoLiwgIk5vdCBBbnN3ZXJlZCIpKQ0KDQpkZ19kZl9wcmUgPC0NCiAgZGdfZGZfcHJlICU+JQ0KICBkcGx5cjo6bXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoIkRHXyIpKSwgfnN0cmluZ3I6OnN0cl9leHRyYWN0KC4sICJbMC05XSsiKSkgJT4lICAgIyBleHRyYWN0cyBmaXJzdCBudW1iZXIgKGFsbCBnYW1lcyBzdGFydCB3aXRoIFBsYXllciBBLCBzbyBhbHdheXMgZmlyc3QgbnVtYmVyKQ0KICBkcGx5cjo6bXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoIkRHXyIpKSwgYXMubnVtZXJpYykgJT4lDQogIGRwbHlyOjptdXRhdGUoVGltZSA9IHJlcCgiUHJlIiwgbnJvdyguKSkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKENvbmQgPSBpZmVsc2Uoc3RyaW5ncjo6c3RyX2RldGVjdChJRCwgIlgiKSwgIkNUUkwiLCAiVFIiKSkgJT4lDQogIHNlbGVjdChgRGF0ZSBNb2RpZmllZGAsIElELCBzdGFydHNfd2l0aCgiREdfIiksIFRpbWUsIENvbmQpDQoNCmRnX2RmX3Bvc3QgPC0NCiAgZGdfZGZfcG9zdCAlPiUNCiAgZHBseXI6Om11dGF0ZV9hdCh2YXJzKHN0YXJ0c193aXRoKCJER18iKSksIH5zdHJpbmdyOjpzdHJfZXh0cmFjdCguLCAiWzAtOV0rIikpICU+JSAgICMgZXh0cmFjdHMgZmlyc3QgbnVtYmVyIChhbGwgZ2FtZXMgc3RhcnQgd2l0aCBQbGF5ZXIgQSwgc28gYWx3YXlzIGZpcnN0IG51bWJlcikNCiAgZHBseXI6Om11dGF0ZV9hdCh2YXJzKHN0YXJ0c193aXRoKCJER18iKSksIGFzLm51bWVyaWMpICU+JQ0KICBkcGx5cjo6bXV0YXRlKFRpbWUgPSByZXAoIlBvc3QiLCBucm93KC4pKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoQ29uZCA9IGlmZWxzZShzdHJpbmdyOjpzdHJfZGV0ZWN0KElELCAiWCIpLCAiQ1RSTCIsICJUUiIpKSAlPiUNCiAgc2VsZWN0KGBEYXRlIE1vZGlmaWVkYCwgSUQsIHN0YXJ0c193aXRoKCJER18iKSwgVGltZSwgQ29uZCkNCg0KIyBUcmFuc2Zvcm0gREcgMC05MDAgZWdvaXNtIHRvIDAtOSBhbHRydWlzbQ0KZGdfdHJhbnNfZnVuYyA8LSBmdW5jdGlvbih4KXt0cmFucyA8LSA5IC0geCAvIDEwMH0NCg0KZGdfZGZfcHJlIDwtDQogIGRnX2RmX3ByZSAlPiUNCiAgZHBseXI6Om11dGF0ZV9hdCh2YXJzKHN0YXJ0c193aXRoKCJER18iKSksIGRnX3RyYW5zX2Z1bmMpIA0KDQpkZ19kZl9wb3N0IDwtDQogIGRnX2RmX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGVfYXQodmFycyhzdGFydHNfd2l0aCgiREdfIikpLCBkZ190cmFuc19mdW5jKSANCg0KIyBVbml0ZSBERyBkYXRhIC0gTG9uZyBGb3JtYXQNCmRnX3VuaXRlZF9sb25nIDwtIHJiaW5kKGRnX2RmX3ByZSwgZGdfZGZfcG9zdCkNCndoaWNoKHRhYmxlKGRnX3VuaXRlZF9sb25nJElEKT4gMiApICAgICAjIElEcyAiM0IiICYgIjMxWCIgaGF2ZSBtb3JlIHRoYW4gMiB0cmlhbHMNCmRnX3VuaXRlZF9sb25nW2RnX3VuaXRlZF9sb25nJElEID09ICIzQiIsXSAgIyB0d28gUHJlcyAtLSBrZWVwIHRoZSBmaXJzdA0KZGdfdW5pdGVkX2xvbmcgPC0gZGdfdW5pdGVkX2xvbmdbLTU1LCBdDQpkZ191bml0ZWRfbG9uZ1tkZ191bml0ZWRfbG9uZyRJRCA9PSAiMzFYIixdICMgdHdvIFByZXMgLS0ga2VlcCB0aGUgZmlyc3QNCmRnX3VuaXRlZF9sb25nIDwtIGRnX3VuaXRlZF9sb25nWy03MywgXQ0KDQpkZ191bml0ZWRfbG9uZyRER19Ub3RhbCA8LSByb3dTdW1zKGRnX3VuaXRlZF9sb25nWywgc3ByaW50ZigiREdfJWQiLCAxOjQpXSwgbmEucm0gPSBUUlVFKSANCg0KIyBVbml0ZSBERyBkYXRhIC0gV2lkZSBGb3JtYXQNCmRnX3VuaXRlZF93aWRlIDwtDQogIGRnX3VuaXRlZF9sb25nICU+JQ0KICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFRpbWUsIHZhbHVlc19mcm9tID0gYygiRGF0ZSBNb2RpZmllZCIsIHNwcmludGYoIkRHXyVkIiwgMTo0KSwgIkRHX1RvdGFsIikpDQojIGRnX3VuaXRlZF93aWRlMiA8LSBkcGx5cjo6bGVmdF9qb2luKGRnX3VuaXRlZF93aWRlLCBpZHNfZ3JvdXBzX2RmLCBieSA9ICJJRCIpICAgICAjIG5vIG5lZWQgdG8gbWVyZ2UsIGFscmVhZHkgaGF2ZSBpZHMgZm9yIGdyb3VwcyBzdG9yZWQNCg0KYGBgDQoNCjwhLS0NCmBgYHtyIG1peGVkYW5vdmFfZGd9DQpjYXQoIk1peGVkIEFOT1ZBIC0gREcgd2hvbGUgc2FtcGxlIChub3QgYnkgZ3JvdXBzKSIpDQojIE1peGVkIEFOT1ZBDQpkZ191bml0ZWRfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoSUQpICU+JQ0KICBmaWx0ZXIobigpID4gMSkgJT4lICAgICAjIGtlZXAgb25seSBjb21wbGV0ZSBjYXNlcw0KICB1bmdyb3VwKCkgJT4lIA0KICB0d19taXhlZEFOT1ZBX2Z1bmMoZGF0YSA9IC4sIGlkX3ZhciA9IElELCBjb25kX3ZhciA9IENvbmQsIHRpbWVfdmFyID0gVGltZSwgdmFsdWVfdmFyID0gREdfVG90YWwsDQogICAgICAgICAgICAgICAgICBwb3N0aG9jX3NpZ19pbnRlcmFjID0gVFJVRSwgcG9zdGhvY19uc19pbnRlcmFjID0gVFJVRSkNCmBgYA0KLS0+DQoNCiMgVCB0ZXN0IERpY2F0YXRvciBHYW1lDQoNCmBgYHtyIHR0ZXN0X2J5Z3JvdXBfZGd9DQojIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBjKGlkc19wdHNkLCBpZHNfYnVybiwgaWRzX29sZCwgaWRzX25vcm1hbCkpICU+JQ0KDQpjYXQoIiMjIERHIC0gUFRTRCBUUiIpDQpkZ191bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19wdHNkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiREdfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiREdfVG90YWxfUG9zdCIpDQpjYXQoIiMjIERHIC0gUFRTRCBDVFJMIikNCmRnX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX3B0c2QpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIkRHX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIkRHX1RvdGFsX1Bvc3QiKQ0KDQoNCmNhdCgiIyMgREcgLSBCdXJub3V0IFRSIikNCmRnX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX2J1cm4pICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJER19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJER19Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgREcgLSBCdXJub3V0IENUUkwiKQ0KZGdfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfYnVybikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiREdfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiREdfVG90YWxfUG9zdCIpDQoNCg0KY2F0KCIjIyBERyAtIE9sZCBUUiIpDQpkZ191bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19vbGQpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJER19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJER19Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgREcgLSBPbGQgQ1RSTCIpDQpkZ191bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19vbGQpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIkRHX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIkRHX1RvdGFsX1Bvc3QiKQ0KDQpjYXQoIiMjIERHIC0gR2VuZXJhbCBQb3B1bGF0aW9uIFRSIikNCmRnX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIkRHX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIkRHX1RvdGFsX1Bvc3QiKQ0KY2F0KCIjIyBERyAtIEdlbmVyYWwgUG9wdWxhdGlvbiBDVFJMIikNCmRnX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiREdfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiREdfVG90YWxfUG9zdCIpDQpgYGANCg0KIyMgREcgTm9ybWFsIFNhbXBsZSBTaXplIGVzdGltYXRpb24NCg0KYGBge3IgZGdfc2FtcGxlc2l6ZX0NCmNhdCgiIyMgREcgLSBHZW5lcmFsIFBvcHVsYXRpb24gVFIiKQ0KZGdfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBzYW1wbGVzaXplX3BhaXJlZHR0ZXN0KC4sIHByZV92YXIgPSAiREdfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiREdfVG90YWxfUG9zdCIpDQpjYXQoIiMjIERHIC0gR2VuZXJhbCBQb3B1bGF0aW9uIENUUkwiKQ0KZGdfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIHNhbXBsZXNpemVfcGFpcmVkdHRlc3QoLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJER19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJER19Ub3RhbF9Qb3N0IikNCmBgYA0KDQoNCmBgYHtyIHNjYWxlX3Njb3JpbmcsIHJlc3VsdHM9J2hpZGUnfQ0KIyBTY2FsZXMgZGYNCnNjYWxlX2RmX3ByZSA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAwLCB3aGljaCA9ICJTZXQgdGVzdGUgemkgMSBwcmUiKQ0Kc2NhbGVfZGZfcHJlIDwtIHNjYWxlX2RmX3ByZVssLTJdDQpjb2xuYW1lcyhzY2FsZV9kZl9wcmUpWzFdIDwtICJEYXRlIg0KY29sbmFtZXMoc2NhbGVfZGZfcHJlKVsyXSA8LSAiSUQiDQpzY2FsZV9kZl9wcmUgPC0gDQogIHNjYWxlX2RmX3ByZSAlPiUNCiAgZHBseXI6Om11dGF0ZShJRCA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChJRCwgZml4ZWQoIiAiKSwgIiIpKSAlPiUgICAgIyByZW1vdmUgd2hpdGUgc3BhY2VzDQogIGRwbHlyOjptdXRhdGUoSUQgPSB0b3VwcGVyKElEKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdG8gdXBwZXINCmFsbChzY2FsZV9kZl9wcmUkSUQgPT0gdG91cHBlcihzY2FsZV9kZl9wcmUkSUQpKSANCg0Kc2NhbGVfZGZfcG9zdCA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2lwID0gMCwgd2hpY2ggPSAiU2V0IHRlc3RlIHppIDUgcG9zdCIpDQpzY2FsZV9kZl9wb3N0IDwtIHNjYWxlX2RmX3Bvc3RbLC0yXQ0KY29sbmFtZXMoc2NhbGVfZGZfcG9zdClbMV0gPC0gIkRhdGUiDQpjb2xuYW1lcyhzY2FsZV9kZl9wb3N0KVsyXSA8LSAiSUQiDQpzY2FsZV9kZl9wb3N0IDwtIA0KICBzY2FsZV9kZl9wb3N0ICU+JQ0KICBkcGx5cjo6bXV0YXRlKElEID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKElELCBmaXhlZCgiICIpLCAiIikpICU+JSAgICAjIHJlbW92ZSB3aGl0ZSBzcGFjZXMNCiAgZHBseXI6Om11dGF0ZShJRCA9IHRvdXBwZXIoSUQpKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0byB1cHBlcg0KYWxsKHNjYWxlX2RmX3Bvc3QkSUQgPT0gdG91cHBlcihzY2FsZV9kZl9wb3N0JElEKSkNCg0KYWxsLmVxdWFsKGNvbG5hbWVzKHNjYWxlX2RmX3Bvc3QpLCBjb2xuYW1lcyhzY2FsZV9kZl9wcmUpKSAgICMgc2V0ZGlmZihjb2xuYW1lcyhzY2FsZV9kZl9wb3N0KSwgY29sbmFtZXMoc2NhbGVfZGZfcHJlKSkNCg0KIyBEZWFsIHdpdGggTm90IEFuc3dlcg0Kc2NhbGVfZGZfcHJlIDwtDQogIHNjYWxlX2RmX3ByZSAlPiUNCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgfmRwbHlyOjpuYV9pZiguLCAiTm90IEFuc3dlcmVkIikpDQoNCnNjYWxlX2RmX3Bvc3QgPC0NCiAgc2NhbGVfZGZfcG9zdCAlPiUNCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgfmRwbHlyOjpuYV9pZiguLCAiTm90IEFuc3dlcmVkIikpDQoNCiMgQWRkIENvbmRpdGlvbg0Kc2NhbGVfZGZfcHJlIDwtDQogIHNjYWxlX2RmX3ByZSAlPiUNCiAgZHBseXI6Om11dGF0ZShUaW1lID0gcmVwKCJQcmUiLCBucm93KC4pKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoQ29uZCA9IGlmZWxzZShzdHJpbmdyOjpzdHJfZGV0ZWN0KElELCAiWCIpLCAiQ1RSTCIsICJUUiIpKQ0KDQpzY2FsZV9kZl9wb3N0IDwtDQogIHNjYWxlX2RmX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGUoVGltZSA9IHJlcCgiUG9zdCIsIG5yb3coLikpKSAlPiUNCiAgICBkcGx5cjo6bXV0YXRlKENvbmQgPSBpZmVsc2Uoc3RyaW5ncjo6c3RyX2RldGVjdChJRCwgIlgiKSwgIkNUUkwiLCAiVFIiKSkNCg0KDQojIyBQQU5BUzogUG9zaXRpdmUgQWZmZWN0IFNjb3JlID0gc3VtIGl0ZW1zIDEsIDMsIDUsIDksIDEwLCAxMiwgMTQsIDE2LCAxNywgMTkuIE5lZ2F0aXZlIEFmZmVjdCBTY29yZSA9IHN1bSBpdGVtcyAyLCA0LCA2LCA3LCA4LCAxMSwgMTMsIDE1LCAxOCwgMjAuICANCmluZGV4X2l0ZW1fcGFuYXMgPC0gMzoyMg0KY29sbmFtZXMoc2NhbGVfZGZfcHJlKVtpbmRleF9pdGVtX3BhbmFzXSA8LSBzcHJpbnRmKCJQQU5BU18lZCIsIDE6MjApDQpjb2xuYW1lcyhzY2FsZV9kZl9wb3N0KVtpbmRleF9pdGVtX3BhbmFzXSA8LSBzcHJpbnRmKCJQQU5BU18lZCIsIDE6MjApDQoNCnNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcGFuYXNdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcGFuYXNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qw65uIGZvYXJ0ZSBtaWPEgyBtxINzdXLEgy4qIiwgIjEiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubiBtaWPEgyBtxINzdXLEgy4qIiwgIjIiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubnRyLW8gb2FyZWNhcmUgbcSDc3VyxIMuKiIsICIzIiwgeCl9KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wYW5hc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wYW5hc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLirDrm4gbWFyZSBtxINzdXLEgy4qIiwgIjQiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubiBmb2FydGUgbWFyZSBtxINzdXLEgy4qIiwgIjUiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCnNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3BhbmFzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wYW5hc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qw65uIGZvYXJ0ZSBtaWPEgyBtxINzdXLEgy4qIiwgIjEiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wYW5hc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubiBtaWPEgyBtxINzdXLEgy4qIiwgIjIiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wYW5hc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubnRyLW8gb2FyZWNhcmUgbcSDc3VyxIMuKiIsICIzIiwgeCl9KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3BhbmFzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLirDrm4gbWFyZSBtxINzdXLEgy4qIiwgIjQiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wYW5hc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubiBmb2FydGUgbWFyZSBtxINzdXLEgy4qIiwgIjUiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQojIFNjb3JpbmcNCnNjYWxlX2RmX3ByZSRQQV9Ub3RhbCA8LSBTY29yZUxpa2VydChzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXVtjKDEsIDMsIDUsIDksIDEwLCAxMiwgMTQsIDE2LCAxNywgMTkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b251bWVyaWMgPSBUUlVFLCBuYXBlcmNlbnQgPSAuMTEpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBub3QgbW9yZSB0aGFuIDEgTkFzIGZvciAxMCBpdGVtcw0Kc2NhbGVfZGZfcHJlJE5BX1RvdGFsIDwtIFNjb3JlTGlrZXJ0KHNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcGFuYXNdW2MoMiwgNCwgNiwgNywgOCwgMTEsIDEzLCAxNSwgMTgsIDIwKV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b251bWVyaWMgPSBUUlVFLCBuYXBlcmNlbnQgPSAuMTEpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBub3QgbW9yZSB0aGFuIDEgTkFzIGZvciAxMCBpdGVtcw0KDQpzY2FsZV9kZl9wb3N0JFBBX1RvdGFsIDwtIFNjb3JlTGlrZXJ0KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3BhbmFzXVtjKDEsIDMsIDUsIDksIDEwLCAxMiwgMTQsIDE2LCAxNywgMTkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9udW1lcmljID0gVFJVRSwgbmFwZXJjZW50ID0gLjExKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbm90IG1vcmUgdGhhbiAxIE5BcyBmb3IgMTAgaXRlbXMNCnNjYWxlX2RmX3Bvc3QkTkFfVG90YWwgPC0gU2NvcmVMaWtlcnQoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdW2MoMiwgNCwgNiwgNywgOCwgMTEsIDEzLCAxNSwgMTgsIDIwKV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9udW1lcmljID0gVFJVRSwgbmFwZXJjZW50ID0gLjExKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbm90IG1vcmUgdGhhbiAxIE5BcyBmb3IgMTAgaXRlbXMNCg0KDQojIyBQU1MtU0YgMTQgKGxpa2VydCAwLTQpLiBJdGVtcyA0LCA1LCA2LCA3LCA5LCAxMCwgYW5kIDEzIGFyZSBzY29yZWQgaW4gcmV2ZXJzZSBkaXJlY3Rpb24uDQppbmRleF9pdGVtX3BzcyA8LSAyMzozNg0KaW5kZXhfaXRlbV9yZXZQU1MgPC0gYyg0LCA1LCA2LCA3LCA5LCAxMCwgMTMpDQpjb2xuYW1lcyhzY2FsZV9kZl9wcmUpW2luZGV4X2l0ZW1fcHNzXSA8LSBzcHJpbnRmKCJQU1NfJWQiLCAxOjE0KQ0KY29sbmFtZXMoc2NhbGVfZGZfcG9zdClbaW5kZXhfaXRlbV9wc3NdIDwtIHNwcmludGYoIlBTU18lZCIsIDE6MTQpDQoNCnNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcHNzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLipuaWNpb2RhdMSDLioiLCAiMCIsIHgpfSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCnNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcHNzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLiphcHJvYXBlIG5pY2lvZGF0xIMuKiIsICIxIiwgeCl9KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcHNzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKnVuZW9yaS4qIiwgIjIiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3Bzc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qZGVzdHVsIGRlIGRlcy4qIiwgIjMiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3Bzc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qZm9hcnRlIGRlcy4qIiwgIjQiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCnNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcHNzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qbmljaW9kYXTEgy4qIiwgIjAiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKmFwcm9hcGUgbmljaW9kYXTEgy4qIiwgIjEiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKnVuZW9yaS4qIiwgIjIiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKmRlc3R1bCBkZSBkZXMuKiIsICIzIiwgeCl9KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcHNzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLipmb2FydGUgZGVzLioiLCAiNCIsIHgpfSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCg0KIyBTY29yZQ0Kc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdIDwtIGNvbHN0b251bWVyaWMoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdKQ0Kc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcHNzXSA8LSBjb2xzdG9udW1lcmljKHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10pDQoNCnNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcHNzXVtpbmRleF9pdGVtX3JldlBTU10gPC0gUmV2ZXJzZUNvZGUoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdW2luZGV4X2l0ZW1fcmV2UFNTXSwgdG9udW1lcmljID0gRkFMU0UsIG1pbiA9IDAsIG1heCA9IDQpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdW2luZGV4X2l0ZW1fcmV2UFNTXSA8LSBSZXZlcnNlQ29kZShzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdW2luZGV4X2l0ZW1fcmV2UFNTXSwgdG9udW1lcmljID0gRkFMU0UsIG1pbiA9IDAsIG1heCA9IDQpDQoNCnNjYWxlX2RmX3ByZSRQU1NfVG90YWwgPC0gU2NvcmVMaWtlcnQoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdLCBuYXBlcmNlbnQgPSAuMTEpDQpzY2FsZV9kZl9wb3N0JFBTU19Ub3RhbCA8LSBTY29yZUxpa2VydChzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdLCBuYXBlcmNlbnQgPSAuMTEpDQoNCg0KIyBVbml0ZSBzY2FsZSBkZiAtIExvbmcgRm9ybWF0DQpzY2FsZV91bml0ZWRfbG9uZyA8LSByYmluZChzY2FsZV9kZl9wcmUsIHNjYWxlX2RmX3Bvc3QpDQoNCnNjYWxlX3VuaXRlZF9sb25nICU+JQ0KICBjb3VudChJRCkgJT4lDQogIHByaW50KG4gPSBJbmYpICAjIElEICIyQiIgaGFzIGRvdWJsZSByZWNvcmQgYm90aCBpbiBwcmUgYW5kIHBvc3QgLS0ga2VlcCBmaXJzdCBpbiBib3RoLCBzZWNvbmQgcmVjb3JkIGhhcyBOQXMNCg0KIyBzY2FsZV91bml0ZWRfbG9uZ1tzY2FsZV91bml0ZWRfbG9uZyRJRCA9PSAiMkIiLF0NCnNjYWxlX3VuaXRlZF9sb25nIDwtIHNjYWxlX3VuaXRlZF9sb25nWy0yNixdDQpzY2FsZV91bml0ZWRfbG9uZyA8LSBzY2FsZV91bml0ZWRfbG9uZ1stMTAyLF0NCg0KDQojIFVuaXRlIERHIGRhdGEgLSBXaWRlIEZvcm1hdA0Kc2NhbGVfdW5pdGVkX3dpZGUgPC0NCiAgc2NhbGVfdW5pdGVkX2xvbmcgJT4lDQogIGRwbHlyOjpzZWxlY3QoSUQsIERhdGUsIFRpbWUsIENvbmQsIFBBX1RvdGFsLCBOQV9Ub3RhbCwgUFNTX1RvdGFsKSAlPiUNCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBUaW1lLCB2YWx1ZXNfZnJvbSA9IGMoIkRhdGUiLCAiUEFfVG90YWwiLCAiTkFfVG90YWwiLCAiUFNTX1RvdGFsIikpDQoNCmBgYA0KDQoNCjwhLS0NCmBgYHtyIG1peGVkYW5vdmFfc2NhbGVzfQ0KY2F0KCJNaXhlZCBBTk9WQSAtIFBTUyB3aG9sZSBzYW1wbGUgKG5vdCBieSBncm91cHMpIikNCiMgTWl4ZWQgQU5PVkENCnNjYWxlX3VuaXRlZF9sb25nICU+JQ0KICBncm91cF9ieShJRCkgJT4lDQogIGZpbHRlcihuKCkgPiAxKSAlPiUgICAgICMga2VlcCBvbmx5IGNvbXBsZXRlIGNhc2VzIC0tIGhlcmUgYXJlIG9ubHkgY29tcGxldGUNCiAgdW5ncm91cCgpICU+JSANCiAgdHdfbWl4ZWRBTk9WQV9mdW5jKGRhdGEgPSAuLCBpZF92YXIgPSBJRCwgY29uZF92YXIgPSBDb25kLCB0aW1lX3ZhciA9IFRpbWUsIHZhbHVlX3ZhciA9IFBTU19Ub3RhbCwNCiAgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KDQpjYXQoIk1peGVkIEFOT1ZBIC0gUEEgd2hvbGUgc2FtcGxlIChub3QgYnkgZ3JvdXBzKSIpDQpzY2FsZV91bml0ZWRfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoSUQpICU+JQ0KICBmaWx0ZXIobigpID4gMSkgJT4lICAgICAjIGtlZXAgb25seSBjb21wbGV0ZSBjYXNlcyAtLSBoZXJlIGFyZSBvbmx5IGNvbXBsZXRlDQogIHVuZ3JvdXAoKSAlPiUgDQogIHR3X21peGVkQU5PVkFfZnVuYyhkYXRhID0gLiwgaWRfdmFyID0gSUQsIGNvbmRfdmFyID0gQ29uZCwgdGltZV92YXIgPSBUaW1lLCB2YWx1ZV92YXIgPSBQQV9Ub3RhbCwNCiAgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KDQpjYXQoIk1peGVkIEFOT1ZBIC0gTkEgd2hvbGUgc2FtcGxlIChub3QgYnkgZ3JvdXBzKSIpDQpzY2FsZV91bml0ZWRfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoSUQpICU+JQ0KICBmaWx0ZXIobigpID4gMSkgJT4lICAgICAjIGtlZXAgb25seSBjb21wbGV0ZSBjYXNlcyAtLSBoZXJlIGFyZSBvbmx5IGNvbXBsZXRlDQogIHVuZ3JvdXAoKSAlPiUgDQogIHR3X21peGVkQU5PVkFfZnVuYyhkYXRhID0gLiwgaWRfdmFyID0gSUQsIGNvbmRfdmFyID0gQ29uZCwgdGltZV92YXIgPSBUaW1lLCB2YWx1ZV92YXIgPSBOQV9Ub3RhbCwNCiAgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KYGBgDQotLT4NCg0KIyBUIHRlc3QgUFNTDQoNCmBgYHtyIHR0ZXN0X2J5Z3JvdXBfcHNzfQ0KIyBkcGx5cjo6ZmlsdGVyKElEICVpbiUgYyhpZHNfcHRzZCwgaWRzX2J1cm4sIGlkc19vbGQsIGlkc19ub3JtYWwpKSAlPiUNCg0KY2F0KCIjIyBQU1MgLSBQVFNEIFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX3B0c2QpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQU1NfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUFNTX1RvdGFsX1Bvc3QiKQ0KY2F0KCIjIyBQU1MgLSBQVFNEIENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfcHRzZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUFNTX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBTU19Ub3RhbF9Qb3N0IikNCg0KDQpjYXQoIiMjIFBTUyAtIEJ1cm5vdXQgVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfYnVybikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBTU19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQU1NfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBTUyAtIEJ1cm5vdXQgQ1RSTCIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19idXJuKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQU1NfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUFNTX1RvdGFsX1Bvc3QiKQ0KDQoNCmNhdCgiIyMgUFNTIC0gT2xkIFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX29sZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBTU19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQU1NfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBTUyAtIE9sZCBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX29sZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUFNTX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBTU19Ub3RhbF9Qb3N0IikNCg0KY2F0KCIjIyBQU1MgLSBHZW5lcmFsIFBvcHVsYXRpb24gVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUFNTX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBTU19Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgUFNTIC0gR2VuZXJhbCBQb3B1bGF0aW9uIENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQU1NfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUFNTX1RvdGFsX1Bvc3QiKQ0KYGBgDQoNCiMjIFBTUyBOb3JtYWwgU2FtcGxlIFNpemUgZXN0aW1hdGlvbg0KDQpgYGB7ciBzYW1wbGVzaXplX3Bzc30NCmNhdCgiIyMgUFNTIC0gR2VuZXJhbCBQb3B1bGF0aW9uIFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgc2FtcGxlc2l6ZV9wYWlyZWR0dGVzdCguLCBwcmVfdmFyID0gIlBTU19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQU1NfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBTUyAtIEdlbmVyYWwgUG9wdWxhdGlvbiBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBzYW1wbGVzaXplX3BhaXJlZHR0ZXN0KC4sIHByZV92YXIgPSAiUFNTX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBTU19Ub3RhbF9Qb3N0IikNCmBgYA0KDQoNCiMgVCB0ZXN0IFBBDQoNCmBgYHtyIHR0ZXN0X2J5Z3JvdXBfcGF9DQpjYXQoIiMjIFBBIC0gUFRTRCBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19wdHNkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBBIC0gUFRTRCBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX3B0c2QpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBBX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBBX1RvdGFsX1Bvc3QiKQ0KDQoNCmNhdCgiIyMgUEEgLSBCdXJub3V0IFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX2J1cm4pICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQQV9Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgUEEgLSBCdXJub3V0IENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfYnVybikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQoNCg0KY2F0KCIjIyBQQSAtIE9sZCBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19vbGQpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQQV9Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgUEEgLSBPbGQgQ1RSTCIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19vbGQpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBBX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBBX1RvdGFsX1Bvc3QiKQ0KDQpjYXQoIiMjIFBBIC0gR2VuZXJhbCBQb3B1bGF0aW9uIFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBBX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBBX1RvdGFsX1Bvc3QiKQ0KY2F0KCIjIyBQQSAtIEdlbmVyYWwgUG9wdWxhdGlvbiBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQoNCmBgYA0KDQojIyBQQSBOb3JtYWwgU2FtcGxlIFNpemUgZXN0aW1hdGlvbg0KDQpgYGB7ciBzYW1wbGVzaXplX3BhfQ0KY2F0KCIjIyBQU1MgLSBHZW5lcmFsIFBvcHVsYXRpb24gVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBzYW1wbGVzaXplX3BhaXJlZHR0ZXN0KC4sIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBTUyAtIEdlbmVyYWwgUG9wdWxhdGlvbiBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBzYW1wbGVzaXplX3BhaXJlZHR0ZXN0KC4sIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQpgYGANCg0KDQojIFQgdGVzdCBOQQ0KDQpgYGB7ciB0dGVzdF9ieWdyb3VwX25hfQ0KY2F0KCIjIyBOQSAtIFBUU0QgVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfcHRzZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIk5BX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIk5BX1RvdGFsX1Bvc3QiKQ0KY2F0KCIjIyBOQSAtIFBUU0QgQ1RSTCIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19wdHNkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCg0KDQpjYXQoIiMjIE5BIC0gQnVybm91dCBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19idXJuKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiTkFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiTkFfVG90YWxfUG9zdCIpDQpjYXQoIiMjIE5BIC0gQnVybm91dCBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX2J1cm4pICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIk5BX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIk5BX1RvdGFsX1Bvc3QiKQ0KDQoNCmNhdCgiIyMgTkEgLSBPbGQgVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfb2xkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiTkFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiTkFfVG90YWxfUG9zdCIpDQpjYXQoIiMjIE5BIC0gT2xkIENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfb2xkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCg0KY2F0KCIjIyBOQSAtIEdlbmVyYWwgUG9wdWxhdGlvbiBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19ub3JtYWwpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgTkEgLSBHZW5lcmFsIFBvcHVsYXRpb24gQ1RSTCIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19ub3JtYWwpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIk5BX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIk5BX1RvdGFsX1Bvc3QiKQ0KYGBgDQoNCiMjIE5BIE5vcm1hbCBTYW1wbGUgU2l6ZSBlc3RpbWF0aW9uDQoNCmBgYHtyIHNhbXBsZXNpemVfbmF9DQpjYXQoIiMjIFBTUyAtIEdlbmVyYWwgUG9wdWxhdGlvbiBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19ub3JtYWwpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIHNhbXBsZXNpemVfcGFpcmVkdHRlc3QoLiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgUFNTIC0gR2VuZXJhbCBQb3B1bGF0aW9uIENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIHNhbXBsZXNpemVfcGFpcmVkdHRlc3QoLiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCmBgYA0KDQoNCg0KDQo8IS0tIFNlc3Npb24gSW5mbyBhbmQgTGljZW5zZSAtLT4NCg0KPGJyPg0KDQojIFNlc3Npb24gSW5mbw0KYGBge3Igc2Vzc2lvbl9pbmZvLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnbWFya3VwJ30NCnNlc3Npb25JbmZvKCkgICAgDQpgYGANCg0KPCEtLSBGb290ZXIgLS0+DQombmJzcDsNCjxociAvPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPkEgd29yayBieSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vQ2xhdWRpdVBhcGFzdGVyaS8iPkNsYXVkaXUgUGFwYXN0ZXJpPC9hPjwvcD4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48c3BhbiBzdHlsZT0iY29sb3I6ICM4MDgwODA7Ij48ZW0+Y2xhdWRpdS5wYXBhc3RlcmlAZ21haWwuY29tPC9lbT48L3NwYW4+PC9wPg0KJm5ic3A7DQo=