library(dplyr)
library(ggplot2)
devtools::load_all(reset = FALSE)
ℹ Loading gutzilla
library(patchwork)
load("agp_metadata_enterotypes_num.rda")
enterotypes = readr::read_csv2("enterotypes_prediction_outliers.csv")[,-1]
ℹ Using "','" as decimal and "'.'" as grouping mark. Use `read_delim()` for more control.
New names:Rows: 17600 Columns: 5── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ";"
chr (2): sample_name, set
dbl (3): ...1, Enterotypes_id, value
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
metadata=read.csv2(system.file("data-raw/Metadata_10317_20191022-112414_curatedv4_VSv1.csv", package = "gutzilla"), stringsAsFactors = FALSE) %>% mutate_all(na_if,"")
shannon_path = system.file("data-raw/qiime/generated-files-20190512/alpha/shannon.qza", package = "gutzilla")
shannon = qiime2R::read_qza(shannon_path)$data %>% as.data.frame
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_date()) %>%
group_by(HOST_SUBJECT_ID) %>%
summarise(n=n()) %>%
filter(n>1) %>%
pull(n) %>% table
.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 19 20 21 26 27 28 29 30 34 38 44 277
747 138 140 30 29 16 5 2 9 5 1 2 1 2 2 2 3 1 2 2 1 1 1 4 1 1 1 1
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_date()) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
mutate(sample_order=rank(days)) %>%
ggplot() + geom_line(aes(x=days,y=sample_order, group=HOST_SUBJECT_ID)) + scale_y_log10()

NA
NA
NA
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_date()) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
mutate(sample_order=rank(days)) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
mutate(sample_order=rank(days)) %>%
xtabs(~ branches + HOST_SUBJECT_ID, data=.) %>%
as.data.frame %>%
filter(Freq!=0)
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_date()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
filter(any(days==0)) %>%
filter(sample_order>1 & days <25) %>%
ggplot() + geom_tile(aes(x=sample_order,y=HOST_SUBJECT_ID, fill=branches)) +
theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank()) + facet_wrap(~days_0, scales="free_y")

NA
NA
NA
NA
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_date()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
ggplot() + geom_point(aes(x=days +1,y=HOST_SUBJECT_ID, col=branches), shape=15) +
theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank()) + facet_wrap(~days_0, scales="free_y") + scale_x_log10()

metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_date()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
filter(days > 0, days<365) %>%
ungroup() %>%
select(days_0,branches) %>%
xtabs(~days_0+branches, data=.) %>% prop.table(1)
branches
days_0 Akkermansia DMM types Bacteroides DMM types Clostridiales DMM types Prevotella DMM types
Akkermansia DMM types 0.24137931 0.65517241 0.10344828 0.00000000
Bacteroides DMM types 0.06568627 0.81470588 0.09509804 0.02450980
Clostridiales DMM types 0.05381166 0.38565022 0.47982063 0.08071749
Prevotella DMM types 0.01312336 0.18635171 0.33858268 0.46194226
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_date()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(HOST_SUBJECT_ID, days, sample_order, branches) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"), branches_before=lag(branches), days_delta= days - lag(days)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
ggplot() + geom_boxplot(aes(x=branches_pairs, y=days_delta+1)) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))+
scale_y_log10() + facet_wrap(~branches_before, scales = "free", nrow=1)

NA
NA
NA
NA
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM partitions",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM partitions",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM partitions",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM partitions",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(HOST_SUBJECT_ID, days, sample_order, branches) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"), branches_before=lag(branches), days_delta= days - lag(days)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(-1,60*60*24*7,120*24*60*60,365*60*60*24,10000*60*60*24))) %>%
ggplot() + geom_bar(aes(x=days_delta_bins, fill=branches), position="fill") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
scale_y_continuous(labels = scales::percent) + scale_fill_brewer("branches after", type="qual") +
facet_wrap(~branches_before) + xlab("time range between two samples") + ylab("Samples %") + scale_x_discrete(labels=c("< 1 week","1 week to 4 months", "4 to 12 months", "> 12 months")) -> figS9A
figS9A
ggsave("figures/FigS9A_branche_before_after.pdf")
Saving 7.29 x 4.5 in image

compute prevotella bacteroides ratio within days
genus_path = system.file("data-raw/qiime/generated-files-20190512/taxa/genus.qza", package = "gutzilla")
genus = qiime2R::read_qza(genus_path)$data %>% as.data.frame %>% tibble::rownames_to_column("taxa") %>% as_tibble()
genus %>%
filter(taxa %in% c("k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Bacteroidaceae;g__Bacteroides",
"k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Prevotellaceae;g__Prevotella")) %>%
tibble::column_to_rownames("taxa") %>%
t() %>%
as.data.frame() -> TS_agp_genus_P_B
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME,days, COLLECTION_TIMESTAMP) -> host_sample_days
host_sample_days %>%
merge(host_sample_days, by="HOST_SUBJECT_ID") %>%
filter(!(SAMPLE_NAME.x==SAMPLE_NAME.y)) %>%
filter(days.y>days.x) %>%
mutate(days_delta = days.y-days.x) %>%
filter(days_delta <= 60*60*24) -> host_sample_pairs_within_days
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME,Enterotypes_id,branches,COLLECTION_TIMESTAMP) -> host_sample_enterotypes_branches
host_sample_pairs_within_days %>%
merge(host_sample_enterotypes_branches, by.x=c("HOST_SUBJECT_ID","SAMPLE_NAME.x", "COLLECTION_TIMESTAMP.x"), by.y=c("HOST_SUBJECT_ID","SAMPLE_NAME","COLLECTION_TIMESTAMP")) %>%
merge(host_sample_enterotypes_branches, by.x=c("HOST_SUBJECT_ID","SAMPLE_NAME.y", "COLLECTION_TIMESTAMP.y"), by.y=c("HOST_SUBJECT_ID","SAMPLE_NAME","COLLECTION_TIMESTAMP")) %>%
merge(TS_agp_genus_P_B, by.x="SAMPLE_NAME.x", by.y="row.names") %>%
merge(TS_agp_genus_P_B, by.x="SAMPLE_NAME.y", by.y="row.names") %>%
dplyr::rename(Bacteroides1 = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Bacteroidaceae;g__Bacteroides.x",
Prevotella1 = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Prevotellaceae;g__Prevotella.x",
Bacteroides2 = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Bacteroidaceae;g__Bacteroides.y",
Prevotella2 = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Prevotellaceae;g__Prevotella.y") %>%
mutate(PB_ratio_1 = log2((Prevotella1+1)/(Bacteroides1+1)), PB_ratio_2 = log2((Prevotella2+1)/(Bacteroides2+1))) %>%
mutate(delta = PB_ratio_2-PB_ratio_1) -> host_sample_enterotypes_branches_P_B_ratio
host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
ggplot() + geom_bar(aes(x=paste(branches.x), fill=branches.y)) + coord_flip()

host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
ggplot() + geom_boxplot(aes(y=delta, branches.x, fill=branches.y))

host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
ggplot() +
geom_point(aes(x=PB_ratio_1, y=PB_ratio_2, color=paste(branches.x,"->",branches.y), size=days_delta < 1*60*60)) +
geom_abline(slope=1,intercept = 0) +
geom_abline(slope=1,intercept = -2.5, linetype=2) +
geom_abline(slope=1,intercept = 2.5, linetype=2) +
xlab("P/B ratio 1st sample") + ylab("P/B ratio 2nd sample") +
scale_size_discrete("less than\n60 minutes") +
scale_colour_discrete("") +
cowplot::theme_cowplot() -> figS9B
Avis : Using size for a discrete variable is not advised.
figS9B

host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
filter(branches.x %in% "Prevotella DMM types") %>%
mutate(less_than_one_hour = days_delta < 1*60*60) %>%
xtabs(~branches.y + less_than_one_hour, data=.) #%>% chisq.test()
less_than_one_hour
branches.y FALSE TRUE
Bacteroides DMM types 19 1
Prevotella DMM types 21 11
host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
filter(branches.x %in% "Bacteroides DMM types") %>%
mutate(less_than_one_hour = days_delta < 1*60*60) %>%
xtabs(~branches.y + less_than_one_hour, data=.) #%>% chisq.test()
less_than_one_hour
branches.y FALSE TRUE
Bacteroides DMM types 157 13
Prevotella DMM types 7 1
check stool collet daily time
host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
ggplot() +
geom_point(aes(x=PB_ratio_1, y=PB_ratio_2, color=paste(branches.x,"->",branches.y), size=days_delta < 1*60*60)) +
geom_abline(slope=1,intercept = 0) +
geom_abline(slope=1,intercept = -2.5, linetype=2) +
geom_abline(slope=1,intercept = 2.5, linetype=2) +
xlab("P/B ratio 1st sample") + ylab("P/B ratio 2nd sample") +
scale_size_discrete("less than\n60 minutes") +
scale_colour_discrete("")
Avis : Using size for a discrete variable is not advised.

host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
mutate(hours.x=COLLECTION_TIMESTAMP.x %>% lubridate::hour(), hours.y=COLLECTION_TIMESTAMP.y %>% lubridate::hour()) %>%
mutate(daytime = ifelse(hours.x < 12 & hours.y < 12, "both morning", ifelse(hours.x >= 12 & hours.y >= 12, "both afternoon", "no"))) %>%
ggplot() +
geom_point(aes(x=PB_ratio_1, y=PB_ratio_2, color=daytime)) +
geom_abline(slope=1,intercept = 0) +
geom_abline(slope=1,intercept = -2.5, linetype=2) +
geom_abline(slope=1,intercept = 2.5, linetype=2) +
xlab("P/B ratio 1st sample") + ylab("P/B ratio 2nd sample") +
scale_size_discrete("less than\n60 minutes") +
scale_colour_discrete("")
Avis : Using size for a discrete variable is not advised.

host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
mutate(hours.x=COLLECTION_TIMESTAMP.x %>% lubridate::hour(), hours.y=COLLECTION_TIMESTAMP.y %>% lubridate::hour()) %>%
mutate(daytime = ifelse(hours.x < 12 & hours.y < 12, "both morning", ifelse(hours.x >= 12 & hours.y >= 12, "both afternoon", "no"))) %>%
filter(branches.x=="Prevotella DMM types"|branches.y=="Prevotella DMM types") %>%
ggplot() +
geom_boxplot(aes(fill=paste(branches.x,"->",branches.y),y=(PB_ratio_1+PB_ratio_2)/2,x=daytime)) +
coord_flip()

host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
mutate(hours.x=COLLECTION_TIMESTAMP.x %>% lubridate::hour(), hours.y=COLLECTION_TIMESTAMP.y %>% lubridate::hour()) %>%
mutate(daytime = ifelse(hours.x < 12 & hours.y < 12, "both morning", ifelse(hours.x >= 12 & hours.y >= 12, "both afternoon", "no"))) %>%
filter(branches.x=="Prevotella DMM types"|branches.y=="Prevotella DMM types") %>%
ggplot() +
geom_bar(aes(x=paste(branches.x,"->",branches.y), fill=daytime), position="fill" ) + xlab("") + coord_flip()

host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
mutate(hours.x=COLLECTION_TIMESTAMP.x %>% lubridate::hour(), hours.y=COLLECTION_TIMESTAMP.y %>% lubridate::hour()) %>%
mutate(daytime = ifelse(hours.x < 12 & hours.y < 12, "both", ifelse(hours.x >= 12 & hours.y >= 12, "both", "no"))) %>%
filter(branches.x=="Prevotella DMM types"|branches.y=="Prevotella DMM types") %>%
ggplot() +
geom_bar(aes(x=paste(branches.x,"->",branches.y), fill=daytime), position="fill" ) + xlab("") + coord_flip()

host_sample_enterotypes_branches_P_B_ratio %>%
filter(branches.x %in% c("Bacteroides DMM types","Prevotella DMM types"),
branches.y %in% c("Bacteroides DMM types","Prevotella DMM types")) %>%
mutate(hours.x=COLLECTION_TIMESTAMP.x %>% lubridate::hour(), hours.y=COLLECTION_TIMESTAMP.y %>% lubridate::hour()) %>%
mutate(daytime = ifelse(hours.x < 12 & hours.y < 12, "both", ifelse(hours.x >= 12 & hours.y >= 12, "both", "no"))) %>%
filter(branches.x=="Prevotella DMM types"|branches.y=="Prevotella DMM types") %>%
xtabs(~ paste(branches.x,"->",branches.y) + daytime, data=.) %>%
chisq.test()
Avis : L’approximation du Chi-2 est peut-être incorrecte
Pearson's Chi-squared test
data: .
X-squared = 6.9017, df = 2, p-value = 0.03172
figure supp 9
figS9A + figS9B + plot_annotation(tag_levels = "A")

ggsave("figures/figS9.pdf")
Saving 16 x 5 in image
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_date()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"), branches_before=lag(branches), days_delta= days - lag(days)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(0,7,30,120,365,10000))) %>%
ungroup() %>%
filter(is.na(days_delta_bins))
NA
NA
NA
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches, COLLECTION_TIMESTAMP)
NA
NA
stability by partition
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, Enterotypes_id, days, sample_order, branches, COLLECTION_TIMESTAMP) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(delta_days = days-lag(days), enterotypes_before = lag(Enterotypes_id)) %>%
mutate(stable=ifelse(enterotypes_before==Enterotypes_id,"stable","switch")) %>%
na.omit() %>%
filter(delta_days>24*60*60) %>%
ggplot() +
geom_boxplot(aes(y=(delta_days)/(24*60*60), x=paste0("M",enterotypes_before), fill=stable)) +
scale_y_log10("days") + xlab("") + cowplot::theme_cowplot() -> p_partition_stability
p_partition_stability

p_partition_stability$data %>%
filter(stable=="stable") %>%
#group_by(enterotypes_before) %>%
with(.,pairwise.wilcox.test(delta_days,enterotypes_before, data=.)) %>% broom::tidy()
Avis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequos
p_partition_stability$data %>%
#filter(stable=="stable") %>%
#group_by(enterotypes_before) %>%
with(.,pairwise.wilcox.test(delta_days,stable, data=.)) %>% broom::tidy()
p_partition_stability$data %>%
group_by(stable) %>%
summarise(m=median(delta_days/(24*60*60)),
q25=quantile(delta_days/(24*60*60), 0.25),
q75=quantile(delta_days/(24*60*60), 0.75))
p_partition_stability$data %>%
ggplot() +
geom_boxplot(aes(y=(delta_days)/(24*60*60), fill=stable)) +
scale_y_log10("days") + xlab("") + cowplot::theme_cowplot()

metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(-1,60*60*24,120*24*60*60,365*60*60*24,10000*60*60*24))) %>%
filter(branches_before == "Bacteroides DMM types", branches == "Bacteroides DMM types") %>%
select(shannon_before,shannon,Enterotypes_id,Enterotypes_id_before) %>%
ungroup() %>%
group_by(Enterotypes_id,Enterotypes_id_before) %>%
summarise(shannon=median(shannon), shannon_before=median(shannon_before), n_p=n()) %>%
ungroup() %>%
group_by(Enterotypes_id_before) %>%
mutate(prop_n_p = n_p/sum(n_p)) %>%
group_by(Enterotypes_id_before) %>%
arrange(Enterotypes_id_before, desc(prop_n_p)) %>%
mutate(Enterotypes_id = Enterotypes_id %>% factor(level=c("2","4","3","10","8","6","15","11")),
Enterotypes_id_before = Enterotypes_id_before %>% factor(level=c("2","4","3","10","8","6","15","11"))) %>%
mutate(shannon_sens = shannon_before> shannon, enterotype_sens = as.numeric(Enterotypes_id_before) > as.numeric(Enterotypes_id)) -> Bacteroides_enterotypes_shannon_pairs
Adding missing grouping variables: `HOST_SUBJECT_ID``summarise()` has grouped output by 'Enterotypes_id'. You can override using the `.groups` argument.
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(-1,60*60*24,120*24*60*60,365*60*60*24,10000*60*60*24))) %>%
filter(branches_before == "Prevotella DMM types", branches == "Prevotella DMM types") %>%
select(shannon_before,shannon,Enterotypes_id,Enterotypes_id_before) %>%
ungroup() %>%
group_by(Enterotypes_id,Enterotypes_id_before) %>%
summarise(shannon=median(shannon), shannon_before=median(shannon_before), n_p=n()) %>%
ungroup() %>%
group_by(Enterotypes_id_before) %>%
mutate(prop_n_p = n_p/sum(n_p)) %>%
group_by(Enterotypes_id_before) %>%
arrange(Enterotypes_id_before, desc(prop_n_p)) %>%
mutate(Enterotypes_id = Enterotypes_id %>% factor(level=c("7","17","16","14","18")),
Enterotypes_id_before = Enterotypes_id_before %>% factor(level=c("7","17","16","14","18"))) %>%
mutate(shannon_sens = shannon_before> shannon, enterotype_sens = as.numeric(Enterotypes_id_before) > as.numeric(Enterotypes_id)) -> Prevotella_enterotypes_shannon_pairs
Adding missing grouping variables: `HOST_SUBJECT_ID``summarise()` has grouped output by 'Enterotypes_id'. You can override using the `.groups` argument.
cowplot::plot_grid(
Bacteroides_enterotypes_shannon_pairs %>%
ungroup() %>%
filter(!(Enterotypes_id==Enterotypes_id_before)) %>%
group_by(Enterotypes_id_before) %>%
arrange(Enterotypes_id_before, desc(n_p)) %>%
dplyr::slice(1:2) %>%
ggplot() +
geom_segment(aes(y=shannon_before,
yend=shannon,
x=Enterotypes_id_before %>% factor(level=c("2","4","3","10","8","6","15","11")),
xend=Enterotypes_id %>% factor(level=c("2","4","3","10","8","6","15","11")),
color=enterotype_sens),
arrow = arrow(length = unit(0.1,"cm"))) +
ggrepel::geom_text_repel(aes(x=Enterotypes_id_before %>% factor(level=c("2","4","3","10","8","6","15","11")),
y=shannon_before,
label=round(prop_n_p,2) %>% scales::percent(accuracy=1))) +
xlab("Bacteroides branch partition\nordered by PHATE centroid position") +
ylab("alpha-diversity\n(Shannon)") +
scale_color_discrete("", labels=c("toward branch-tip", "toward branch-root")),
Bacteroides_enterotypes_shannon_pairs %>%
ungroup() %>%
filter((Enterotypes_id==Enterotypes_id_before)) %>%
ggplot() +
geom_bar(aes(x=Enterotypes_id_before,y=prop_n_p, fill=shannon), stat="identity") +
scale_y_continuous(labels = scales::percent) +
xlab("Bacteroides branch partition\nordered by PHATE centroid position") +
ylab("stable participant sample-paired\nproportions"),
Prevotella_enterotypes_shannon_pairs %>%
ungroup() %>%
filter(!(Enterotypes_id==Enterotypes_id_before)) %>%
group_by(Enterotypes_id_before) %>%
arrange(Enterotypes_id_before, desc(n_p)) %>%
dplyr::slice(1:2) %>%
ggplot() +
geom_segment(aes(y=shannon_before,
yend=shannon,
x=Enterotypes_id_before %>% factor(level=c("7","17","16","14","18")),
xend=Enterotypes_id %>% factor(level=c("7","17","16","14","18")),
color=enterotype_sens),
arrow = arrow(length = unit(0.1,"cm"))) +
ggrepel::geom_text_repel(aes(x=Enterotypes_id_before %>% factor(level=c("7","17","16","14","18")),
y=shannon_before,
label=round(prop_n_p,2) %>% scales::percent(accuracy=1))) +
xlab("Prevotella branch partition\nordered by PHATE centroid position") +
ylab("alpha-diversity\n(Shannon)") +
scale_color_discrete("", labels=c("toward branch-tip", "toward branch-root")),
Prevotella_enterotypes_shannon_pairs %>%
ungroup() %>%
filter((Enterotypes_id==Enterotypes_id_before)) %>%
ggplot() +
geom_bar(aes(x=Enterotypes_id_before,y=prop_n_p, fill=shannon), stat="identity") +
scale_y_continuous(labels = scales::percent) +
xlab("Prevotella branch partition\nordered by PHATE centroid position") +
ylab("stable participant sample-paired\nproportions"), nrow = 2, rel_widths = c(2,1))

NA
NA
NA
NA
NA
gut microbiota partitions networks based on times series
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(-1,60*60*24*7,120*24*60*60,365*60*60*24,10000*60*60*24))) %>%
ungroup() -> enterotypes_time_series_network_raw
#filter(days_delta_bins %in% c("(-1,8.64e+04]","(8.64e+04,1.04e+07]")) %>%
enterotypes_time_series_network_raw %>%
group_by(Enterotypes_id_before,Enterotypes_id) %>%
summarise(n=n()) %>%
ungroup() %>%
arrange(Enterotypes_id_before,desc(n)) %>%
group_by(Enterotypes_id_before) %>%
mutate(p=n/sum(n))-> enterotypes_time_series_network
`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.
#dplyr::slice(1:3)
figure stability vs random
enterotypes_time_series_network %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(branches_before = case_when(Enterotypes_id_before %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id_before %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id_before %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id_before %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(group = ifelse(Enterotypes_id_before == Enterotypes_id, "within Partition", ifelse(branches_before==branches, "within Branches", "between Branches") )) %>%
ggplot() + geom_bar(aes(x=Enterotypes_id_before, y=p, fill=group), stat="identity", position="fill") +
facet_wrap(~branches_before, scales = "free", nrow=1)

enterotypes_time_series_network_raw %>%
select(Enterotypes_id,Enterotypes_id_before) %>%
mutate(Enterotypes_id = sample(Enterotypes_id)) %>%
group_by(Enterotypes_id_before,Enterotypes_id) %>%
summarise(n=n()) %>%
ungroup() %>%
arrange(Enterotypes_id_before,desc(n)) %>%
group_by(Enterotypes_id_before) %>%
mutate(p=n/sum(n)) -> tmp
`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.
tmp %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(branches_before = case_when(Enterotypes_id_before %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id_before %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id_before %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id_before %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
# mutate(group = ifelse(Enterotypes_id_before == Enterotypes_id, "within Partition", ifelse(branches_before==branches, "within Branches", "between Branches") )) %>%
mutate(group = ifelse(branches_before==branches,"within Branches" ,"between Branches")) %>%
ggplot() + geom_bar(aes(x=Enterotypes_id_before, y=p, fill=group), stat="identity") +
facet_wrap(~branches_before, scales = "free", nrow=1)

enterotypes_time_series_network_random=NULL
for (i in 1:100) {
enterotypes_time_series_network_raw %>%
select(Enterotypes_id,Enterotypes_id_before) %>%
mutate(Enterotypes_id = sample(Enterotypes_id)) %>%
group_by(Enterotypes_id_before,Enterotypes_id) %>%
summarise(n=n()) %>%
ungroup() %>%
arrange(Enterotypes_id_before,desc(n)) %>%
group_by(Enterotypes_id_before) %>%
mutate(p=n/sum(n), iteration=i) -> tmp
enterotypes_time_series_network_random =
rbind(enterotypes_time_series_network_random,tmp)
}
`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before'. You can override using the `.groups` argument.
enterotypes_time_series_network_random %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(branches_before = case_when(Enterotypes_id_before %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id_before %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id_before %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id_before %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(group = ifelse(Enterotypes_id_before == Enterotypes_id, "within Partition", ifelse(branches_before==branches, "within Branches", "between Branches") )) %>%
#mutate(group = ifelse(branches_before==branches,"within Branches" ,"between Branches")) %>%
group_by(Enterotypes_id_before,group,iteration) %>%
summarise(p=sum(p)) %>%
ggplot() + geom_boxplot(aes(x=Enterotypes_id_before, y=p, fill=group))
`summarise()` has grouped output by 'Enterotypes_id_before', 'group'. You can override using the `.groups` argument.

enterotypes_time_series_network_random %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella\nDMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides\nDMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales\nDMM types",
Enterotypes_id %in% c(13) ~ "Akk.",
TRUE ~ "outliers")
) %>%
mutate(branches_before = case_when(Enterotypes_id_before %in% c(18,14,16,17,7) ~ "Prevotella\nDMM types",
Enterotypes_id_before %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides\nDMM types",
Enterotypes_id_before %in% c(12,1,5,9) ~ "Clostridiales\nDMM types",
Enterotypes_id_before %in% c(13) ~ "Akk.",
TRUE ~ "outliers")
) %>%
mutate(group = ifelse(Enterotypes_id_before == Enterotypes_id, "within Partition", ifelse(branches_before==branches, "within Branch\nbetween Partitions", "between Branches") )) %>%
#mutate(group = ifelse(branches_before==branches,"within Branches" ,"between Branches")) %>%
group_by(Enterotypes_id_before,group,branches_before,iteration) %>%
summarise(p=sum(p)) %>%
ungroup() %>%
select(-iteration) %>%
group_by(Enterotypes_id_before,branches_before,group) %>%
summarise(p95=quantile(p,0.95),p05=quantile(p,0.05)) %>%
mutate(p=ifelse(group!="within Partition", p05,p95)) %>%
select(-p95, -p05) %>%
mutate(dataset="Randomized CI 95%") %>%
rbind(
enterotypes_time_series_network %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella\nDMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides\nDMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales\nDMM types",
Enterotypes_id %in% c(13) ~ "Akk.",
TRUE ~ "outliers")
) %>%
mutate(branches_before = case_when(Enterotypes_id_before %in% c(18,14,16,17,7) ~ "Prevotella\nDMM types",
Enterotypes_id_before %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides\nDMM types",
Enterotypes_id_before %in% c(12,1,5,9) ~ "Clostridiales\nDMM types",
Enterotypes_id_before %in% c(13) ~ "Akk.",
TRUE ~ "outliers")
) %>%
mutate(group = ifelse(Enterotypes_id_before == Enterotypes_id, "within Partition", ifelse(branches_before==branches, "within Branch\nbetween Partitions", "between Branches") )) %>%
group_by(Enterotypes_id_before,branches_before,group) %>%
summarise(p=sum(p)) %>%
mutate(dataset="Observed")
) %>%
filter(group != "within Branch\nbetween Partitions") %>%
mutate(group = group %>% forcats::fct_relevel("within Partition","between Branches")) %>%
ggplot() + geom_bar(aes(x=paste0("M",Enterotypes_id_before),y=p,fill=dataset),stat="identity", position = "dodge") +
facet_grid(group~branches_before, scales = "free", space = "free") +
cowplot::theme_cowplot() +
xlab("Gut microbiome partitions") +
ylab("Proportions") +
theme(axis.text.x=element_text(angle=90,hjust=1, vjust=0.5)) +
theme(legend.position="bottom") -> fig5M_stability
`summarise()` has grouped output by 'Enterotypes_id_before', 'group', 'branches_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before', 'branches_before'. You can override using the `.groups` argument.`summarise()` has grouped output by 'Enterotypes_id_before', 'branches_before'. You can override using the `.groups` argument.
fig5M_stability

NA
NA
enterotypes_time_series_network
enterotypes_time_series_network %>%
dplyr::slice(1) %>%
pull(n) %>% sum
[1] 881
enterotypes_time_series_network %>%
dplyr::slice(2:20) %>%
pull(n) %>% sum
[1] 1180
enterotypes_time_series_network %>%
pull(n) %>% sum
[1] 2061
enterotypes_time_series_network %>%
#ungroup() %>%
filter(p>0.05) -> enterotypes_time_series_network
enterotypes_time_series_network %>%
dplyr::slice(1) %>%
pull(n) %>% sum
[1] 881
enterotypes_time_series_network %>%
dplyr::slice(2:20) %>%
pull(n) %>% sum
[1] 775
enterotypes_time_series_network %>%
pull(n) %>% sum
[1] 1656
enterotypes_time_series_network %>% write.table(file="enterotypes_time_series_network.txt", sep = "\t")
enterotypes_time_series_network %>%
group_by(Enterotypes_id_before) %>%
summarise(p=sum(p)) %>% pull(p) %>% summary() # if you select the top 2 switches + stability (=>66% average)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.6454 0.7680 0.8132 0.8121 0.8784 0.9247
enterotypes_time_series_network %>%
filter(Enterotypes_id_before==Enterotypes_id) %>%
select(Enterotypes_id_before,p) %>%
dplyr::rename(stability=p, Enterotypes_id=Enterotypes_id_before)-> enterotypes_time_series_stability
enterotypes_time_series_network %>%
filter(!(Enterotypes_id_before==Enterotypes_id)) %>%
select(Enterotypes_id_before,Enterotypes_id, p) -> enterotypes_time_series_switch
# enterotypes_time_series_network %>%
# filter(!(Enterotypes_id_before==Enterotypes_id)) %>%
# select(Enterotypes_id_before,Enterotypes_id, n, p) %>%
# filter(n>5) %>% select(Enterotypes_id_before,Enterotypes_id, p) -> enterotypes_time_series_switch
enterotypes_time_series_stability %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")) -> enterotypes_time_series_stability
library(igraph)
library(ggraph)
#igraph::graph.data.frame(enterotypes_time_series_switch)
graph <- igraph::graph_from_data_frame(enterotypes_time_series_switch)
V(graph)
+ 18/18 vertices, named, from 1ed0fdb:
[1] 1 10 11 12 13 14 15 16 17 18 2 3 4 5 6 7 8 9
enterotypes_time_series_stability =
enterotypes_time_series_stability %>% .[match(names(V(graph)), enterotypes_time_series_stability$Enterotypes_id),]
V(graph)$stability <- enterotypes_time_series_stability$stability
V(graph)$branches <- enterotypes_time_series_stability$branches
V(graph)$partition_names <- enterotypes_time_series_stability$Enterotypes_id
ggraph(graph, weights=p, layout="stress") +
geom_edge_fan(aes(alpha = p, color=p), arrow=arrow(angle = 20, length = unit(4, "mm")), end_cap = circle(3, 'mm')) +
#scale_alpha_ordinal("participants proportion") +
#geom_node_point(aes(color=branches,size=stability*2)) +
#geom_node_point(aes(color=branches,size=stability)) +
geom_node_label(aes(label=partition_names, fill=branches %>% gsub("DMM types","",.), size=stability), shape=15) +
#geom_node_text(aes(label=partition_names), repel=TRUE) +
scale_color_brewer(type="qual") +
scale_fill_brewer("DMM types", type="qual") +
scale_alpha_continuous("participants proportion") +
scale_edge_alpha("ind. proportion (switch)") +
scale_edge_color_continuous("ind. proportion (switch)", low = "grey", high ="red", guide = FALSE) +
scale_size_continuous("ind. proportion (stable)", trans="log10", limits = c(0.1,0.9), breaks = c(0.3,0.6,0.9)) +
theme_void() -> fig5A
Avis : Ignoring unknown parameters: shape
fig5A

enterotypes_time_series_stability %>%
#filter(branches=="Bacteroides DMM types"| Enterotypes_id %in% c(1,5)) %>%
#mutate(Enterotypes_id=Enterotypes_id %>% as.character %>% factor(levels=c("1","5","2","4","3","8","10","6","15","11"))) %>%
ggplot() + geom_bar(aes(x=Enterotypes_id, y=stability), stat="identity") +
xlab("Bacteroides branch partitions\nordered by PHATE centroid position") +
ylab("stability") +
cowplot::theme_cowplot()

NA
NA
to put network in BW
ggraph(graph, weights=p, layout="stress") +
geom_edge_fan(aes(alpha = p, color=p), arrow=arrow(angle = 20, length = unit(4, "mm")), end_cap = circle(3, 'mm')) +
#scale_alpha_ordinal("participants proportion") +
#geom_node_point(aes(color=branches,size=stability*2)) +
#geom_node_point(aes(color=branches,size=stability)) +
geom_node_label(aes(label=paste0(partition_names,branches %>% stringr::str_sub(start=1, end=1)),
fill=paste0(branches %>% gsub("DMM types","",.)," (",branches %>% stringr::str_sub(start=1, end=1),")"), size=stability)) +
#geom_node_text(aes(label=partition_names), repel=TRUE) +
#scale_color_grey() +
scale_fill_grey("main taxa DMM partitions") +
scale_alpha_continuous("participants proportion") +
scale_edge_alpha("ind. proportion (switch)") +
scale_edge_color_continuous("ind. proportion (switch)", low = "grey", high ="black", guide = FALSE) +
scale_size_continuous("ind. proportion (stable)", trans="log10", limits = c(0.1,0.9), breaks = c(0.3,0.6,0.9)) +
theme_void()

metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME,HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(-1,60*60*24*7,120*24*60*60,365*60*60*24,10000*60*60*24))) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
select(SAMPLE_NAME,Enterotypes_id.x,Enterotypes_id_before,value) %>%
mutate(stability=ifelse(Enterotypes_id.x==Enterotypes_id_before, "stable","unstable")) %>%
#with(.,wilcox.test(data=., value~stability))
#ggplot() + ggforce::geom_sina(aes(x=stability,y=value)) #+ facet_wrap(~Enterotypes_id_before)
ggplot() + geom_bar(aes(x=stability,fill=value>0.8), position="fill") #+ facet_wrap(~Enterotypes_id.x)

#ggplot() + geom_density(aes(x=value, fill=stability), alpha=0.5)
main switches and keystone species
main switches occurred between #6 and #2, #3 and #5
M6 M2
#compute fprau/bacteroides ratio and merge
f_GG = "k__Bacteria;p__Firmicutes;c__Clostridia;o__Clostridiales;f__Ruminococcaceae;g__Faecalibacterium"
b_GG = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Bacteroidaceae;g__Bacteroides"
genus %>%
filter(taxa %in% c(f_GG,b_GG)) %>%
tibble::column_to_rownames("taxa") %>%
t %>%
as.data.frame() %>%
dplyr::rename(Feacalibacterium=2,Bacteroides=1) %>%
mutate(ratio=Feacalibacterium/Bacteroides) -> f_b_ratio
# metadata %>%
# filter(SAMPLE_TYPE == "Stool") %>%
# select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
# mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
# merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
# merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
# filter(set != "outliers") %>%
# filter(Enterotypes_id != 19) %>%
# group_by(HOST_SUBJECT_ID) %>%
# mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
# filter(n>1) %>%
#
# mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
# group_by(HOST_SUBJECT_ID) %>%
# arrange(HOST_SUBJECT_ID, days) %>%
# mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
# filter(Enterotypes_id %in% c(2,6)) %>%
# ggplot() + geom_line(aes(x=days,y=shannon,group=HOST_SUBJECT_ID, col=as.character(Enterotypes_id)))
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon, ratio) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon),
ratio_before = lag(ratio)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
filter(Enterotypes_id %in% c(2,6), Enterotypes_id_before %in% c(2,6)) %>%
ungroup() %>%
select(SAMPLE_NAME,Enterotypes_id,shannon,ratio, Enterotypes_id_before,shannon_before, ratio_before) %>%
mutate(switch=paste(Enterotypes_id,Enterotypes_id_before)) -> df
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
ggplot() + geom_boxplot(aes(x=switch,y=delta_ratio)) +
ylab("Faecalibacterium/Bacteroides\nratio variation") +
xlab("") + cowplot::theme_cowplot() +
scale_x_discrete(label=c("within\npartition M2","between\nfrom M2 to M6","between\nfrom M6 to M2","within\npartition M6")) -> fig5B
fig5B

df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
with(.,pairwise.wilcox.test(delta_ratio,switch, data=.))
Pairwise comparisons using Wilcoxon rank sum test with continuity correction
data: delta_ratio and switch
2 2 2 6 6 2
2 6 2.5e-09 - -
6 2 3.1e-05 0.20 -
6 6 0.74 5.7e-09 5.1e-05
P value adjustment method: holm
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("2 2","6 6"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("2 2","2 6"), "M2","M6") ) %>%
#arrange(switch) %>%
ggplot() + geom_line(aes(x=ratio,y=SAMPLE_NAME, group=SAMPLE_NAME, col=stable)) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2") +
#facet_wrap(~switch, ncol=1, scale="free_y") +
cowplot::theme_cowplot() +
ylab("AGP participants") + xlab("Faecalibacterium/\nBacteroides ratio") +
scale_color_manual("", values=c("black","red"), label=c("stable","unstable")) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank()) +
facet_grid(start_partition~., scales = "free_y")

rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(shannon)) %>%
mutate(stable = ifelse(switch %in% c("2 2","6 6"), "stable","unstable") ) %>%
#filter(stable == "stable") %>%
ggplot() +
geom_point(aes(x=ratio,y=shannon,col=switch))+
geom_line(aes(x=ratio,y=shannon,group=SAMPLE_NAME ,col=switch)) +
scale_x_continuous(trans = "log2") + facet_wrap(~stable) -> fig5J_ellispse
fig5J_ellispse

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
ggplot() + geom_density(aes(x=ratio, fill=switch), alpha=0.5) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2")

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
ggplot() +
#geom_density(aes(x=ratio), alpha=0.5) +
geom_density(aes(x=ratio, color=switch), alpha=0.5) +
cowplot::theme_cowplot() +
theme(axis.text.y = element_blank()) +
scale_x_continuous(trans = "log2")

# df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
# filter(switch %in% c("2 2", "2 6")) %>%
# merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
# reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
# ggplot() + geom_boxplot(aes(x=switch, y=value)) + facet_wrap(~variable, scale="free")
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("2 2", "2 6")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr")) %>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_22vs26.csv")
Avis : The `.drop` argument of `unnest()` is deprecated as of tidyr 1.0.0.
All list-columns are now preserved.
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("6 6", "6 2")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr"))%>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_66vs62.csv")
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
ggplot() + geom_point(aes(x=log2(ratio_before) - log2(ratio),y=log2(shannon_before/shannon), color=switch)) +
xlim(-4,4) + ylim(-0.5, 0.5) + cowplot::theme_cowplot() + scale_color_brewer("", type="qual", palette = 2) +
xlab("Feacalibacterium/Bacteroides variation") + ylab("alpha-diversity variation") -> figS10A
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("2 2","6 6"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("2 2","2 6"), "M2","M6") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
#arrange(switch) %>%
ggplot() + geom_line(aes(x=ratio,y=SAMPLE_NAME, group=SAMPLE_NAME, col=stable)) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2") +
#facet_wrap(~switch, ncol=1, scale="free_y") +
cowplot::theme_cowplot() +
ylab("AGP participants") + xlab("Faecalibacterium/\nBacteroides ratio") +
scale_color_manual("", values=c("black","red"), label=c("stable","unstable")) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank()) +
facet_grid(start_partition~., scales = "free_y") -> fig5B_full
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
mutate(stable = ifelse(switch %in% c("2 2","6 6"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("2 2","2 6"), "M2","M6") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
ggplot() + geom_boxplot(aes(x=start_partition,y=delta_ratio, col=stable)) +
ylab("Faecalibacterium/Bacteroides\nratio variation") +
#scale_y_continuous(trans="log2") +
xlab("") + cowplot::theme_cowplot() + scale_color_manual("",values=c("black","red")) -> fig5Binset
fig5B = fig5B_full + inset_element(fig5Binset+ylab("variation")+guides(color=FALSE), 0.65,-0.1,1,0.3, ignore_tag = TRUE)
Avis : `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
fig5B

rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("2 2","6 6"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("2 2","2 6"), "M2","M6") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
#with(.,wilcox.test(data=., value~stable))
ggplot() + ggforce::geom_sina (aes(x=stable,y=value,color=Enterotypes_id.x))

rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("2 2","6 6"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("2 2","2 6"), "M2","M6") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
group_by(switch) %>%
summarise(q05 = quantile(ratio, 0.05),
q25 = quantile(ratio, 0.25),
q50=median(ratio),
q75 = quantile(ratio, 0.75),
q95 = quantile(ratio, 0.95))
NA
NA
pca analysis
rbind(
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("2 2", "2 6")) %>%
mutate(switch= switch %>% factor(levels = c("2 2", "2 6"))) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(cor_test=purrr::map(data,~cor.test(.x$value,.x$switch %>% as.factor %>% as.numeric(), method="spearman")),
tidy=purrr::map(cor_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
mutate(switch=c("2->6")) %>%
select(variable,estimate,p.value,switch) %>% mutate(q.value=p.adjust(p.value,"fdr")),
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("6 6", "6 2")) %>%
mutate(switch= switch %>% factor(levels = c("6 6", "6 2"))) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(cor_test=purrr::map(data,~cor.test(.x$value,.x$switch %>% as.factor %>% as.numeric(), method="spearman")),
tidy=purrr::map(cor_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
mutate(switch=c("6->2")) %>%
select(variable,estimate,p.value,switch) %>% mutate(q.value=p.adjust(p.value,"fdr"))) %>%
filter(q.value<0.05) %>%
ggplot() + geom_bar(aes(x=variable,y=estimate,fill=switch), position = "dodge", stat = "identity") + coord_flip() + cowplot::theme_cowplot() -> fig5D
Avis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : l'écart type est nulAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequosAvis : Impossible de calculer la p-value exacte avec des ex-aequos
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
select(SAMPLE_NAME,Enterotypes_id, shannon, switch) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch","shannon","shannon_before","ratio","ratio_before"))
Error: id variables not found in data: shannon_before, ratio, ratio_before
library(caret)
set.seed(666)
train.control <- trainControl(method = "repeatedcv",
summaryFunction=twoClassSummary,
number = 10, repeats = 5, classProbs=T, savePredictions = T)
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("2 2", "2 6")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>% select(-SAMPLE_NAME,-Enterotypes_id) %>% mutate(switch = paste0("p",switch) %>% gsub("\\ ","",.) %>% as.factor) -> df_22_26
# Train the model
suppressWarnings(model <- train(switch ~., data = df_22_26, method = "rf",
trControl = train.control))
# Summarize the results
print(model)
library(pROC)
# Select a parameter setting
selectedIndices <- model$pred$mtry == 2
#selectedIndices <- model$pred$ncomp == 1
# Plot:
plot.roc(model$pred$obs[selectedIndices],
model$pred$p26[selectedIndices])
M5 M3
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon, ratio) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon),
ratio_before = lag(ratio)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
filter(Enterotypes_id %in% c(3,5), Enterotypes_id_before %in% c(3,5)) %>%
ungroup() %>%
select(SAMPLE_NAME,Enterotypes_id,shannon,ratio, Enterotypes_id_before,shannon_before, ratio_before) %>%
mutate(switch=paste(Enterotypes_id,Enterotypes_id_before)) -> df
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
ggplot() + geom_boxplot(aes(x=switch,y=delta_ratio)) +
ylab("Faecalibacterium/Bacteroides\nratio variation") +
xlab("") + cowplot::theme_cowplot() +
scale_x_discrete(label=c("within\npartition M3","between\nfrom M3 to M5","between\nfrom M5 to M3","within\npartition M5")) -> fig5C
fig5C

df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
with(.,pairwise.wilcox.test(delta_ratio,switch, data=.))
Pairwise comparisons using Wilcoxon rank sum test with continuity correction
data: delta_ratio and switch
3 3 3 5 5 3
3 5 9.2e-05 - -
5 3 0.00027 0.72083 -
5 5 0.91811 2.7e-06 8.0e-06
P value adjustment method: holm
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
arrange(switch) %>%
ggplot() + geom_line(aes(x=ratio,y=SAMPLE_NAME, group=SAMPLE_NAME, col=switch)) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2") + facet_wrap(~switch, ncol=1, scale="free_y")

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
ggplot() + geom_density(aes(x=ratio, fill=switch), alpha=0.5) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2")

rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(shannon)) %>%
mutate(stable = ifelse(switch %in% c("3 3","5 5"), "stable","unstable") ) %>%
#filter(stable == "stable") %>%
ggplot() +
geom_point(aes(x=ratio,y=shannon,col=switch))+
geom_line(aes(x=ratio,y=shannon,group=SAMPLE_NAME ,col=switch)) +
scale_x_continuous(trans = "log2") + facet_wrap(~stable) -> fig5K_ellispse
fig5K_ellispse

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("5 5", "5 3")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
ggplot() + geom_boxplot(aes(x=switch, y=value)) + facet_wrap(~variable, scale="free")

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("5 5", "3 3")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
ggplot() + geom_boxplot(aes(x=switch, y=value)) + facet_wrap(~variable, scale="free")

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("5 5", "5 3")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr")) %>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_55vs53.csv")
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("3 3", "3 5")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr")) %>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_33vs35.csv")
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("3 3", "5 5")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr")) %>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_33vs55.csv")
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
ggplot() + geom_point(aes(x=log2(ratio_before) - log2(ratio),y=log2(shannon_before/shannon), color=switch)) +
xlim(-4,4) + ylim(-0.5, 0.5) + cowplot::theme_cowplot() + scale_color_brewer("", type="qual", palette = 2) +
xlab("Feacalibacterium/Bacteroides variation") + ylab("alpha-diversity variation") -> figS10B
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("5 5","3 3"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("5 5","5 3"), "M5","M3") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
#arrange(switch) %>%
ggplot() + geom_line(aes(x=ratio,y=SAMPLE_NAME, group=SAMPLE_NAME, col=stable)) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2") +
#facet_wrap(~switch, ncol=1, scale="free_y") +
cowplot::theme_cowplot() +
ylab("AGP participants") + xlab("Faecalibacterium/\nBacteroides ratio") +
scale_color_manual("", values=c("black","red"), label=c("stable","unstable")) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank()) +
facet_grid(start_partition~., scales = "free_y") -> fig5C_full
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
mutate(stable = ifelse(switch %in% c("5 5","3 3"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("5 5","5 3"), "M5","M3") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
ggplot() + geom_boxplot(aes(x=start_partition,y=delta_ratio, col=stable)) +
ylab("Faecalibacterium/Bacteroides\nratio variation") +
#scale_y_continuous(trans="log2") +
xlab("") + cowplot::theme_cowplot() + scale_color_manual("",values=c("black","red")) -> fig5Cinset
fig5C = fig5C_full + inset_element(fig5Cinset+ylab("variation")+guides(color=FALSE), 0.6,-0.1,1,0.3, ignore_tag = TRUE) + plot_annotation(tag_levels = "A")
Avis : `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
mutate(stable = ifelse(switch %in% c("5 5","3 3"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("5 5","5 3"), "M5","M3") ) %>%
#filter(stable!="stable") %>%
ggplot() + geom_histogram(aes(x=ratio), alpha=0.5) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2")

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
mutate(stable = ifelse(switch %in% c("5 5","3 3"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("5 5","5 3"), "M5","M3") ) %>%
#filter(stable!="stable") %>%
pull(ratio) %>%
log(.,2) %>% diptest::dip.test()
Hartigans' dip test for unimodality / multimodality
data: .
D = 0.019567, p-value = 0.7794
alternative hypothesis: non-unimodal, i.e., at least bimodal
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("5 5","3 3"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("5 5","5 3"), "M5","M3") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
#with(.,wilcox.test(data=., value~stable))
#ggplot() + ggforce::geom_sina (aes(x=stable,y=value,color=Enterotypes_id.x))
ggplot() + geom_bar(aes(x=stable,fill=value>0.9), position="fill")

rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("5 5","3 3"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("5 5","5 3"), "M5","M3") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(value>quantile(value,2/3)|value<quantile(value,1/3)) %>%
mutate(value=value>quantile(value,0.5)) %>%
with(., chisq.test(stable,value))
Pearson's Chi-squared test with Yates' continuity correction
data: stable and value
X-squared = 11.655, df = 1, p-value = 0.0006402
#ggplot() + geom_bar(aes(x=stable,fill=value>quantile(value,0.5)), position="fill") + scale_fill_brewer("")
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("5 5","3 3"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("5 5","5 3"), "M5","M3") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
filter(value>0.99, stable==stable) %>%
pull(ratio) %>% diptest::dip.test()
Hartigans' dip test for unimodality / multimodality
data: .
D = 0.039694, p-value = 0.7702
alternative hypothesis: non-unimodal, i.e., at least bimodal
#ggplot() + geom_density(aes(x=ratio)) + scale_x_continuous(trans="log2")
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("2 2","6 6"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("2 2","2 6"), "M2","M6") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
group_by(switch) %>%
summarise(q05 = quantile(ratio, 0.05), q25 = quantile(ratio, 0.25), q50=median(ratio), q75 = quantile(ratio, 0.75), q95 = quantile(ratio, 0.95))
NA
pca

Figure 5 - Time series
library(patchwork)
#(fig5A | (fig5B/fig5C)|(fig5D/fig5E)) + plot_layout(widths = c(2,1,1.5)) +plot_annotation(tag_levels = "A")
# patch_plot = ((fig5A + plot_annotation(tag_levels = "A")) |
#
# ((fig5B_full + plot_annotation(tag_levels = "B") +
# inset_element(fig5Binset +
# ylab("variation")+
# guides(color=FALSE), 0.6,-0.1,1,0.3, ignore_tag = FALSE))/
#
# (fig5C_full + plot_annotation(tag_levels = "C") +
# inset_element(fig5Cinset+
# ylab("variation")+
# guides(color=FALSE), 0.6,-0.1,1,0.3, ignore_tag = FALSE)))) +
# plot_annotation(tag_levels = "A") + plot_layout(widths = c(2,1.5))
#
# patch_plot[[2]][[1]] + plot_annotation(tag_levels = "A")
((fig5A) | (fig5B_full/fig5C_full)) + plot_annotation(tag_levels = "a") + plot_layout(widths = c(2,1.5))

ggsave("figures/figure5_bis.pdf")
Saving 12 x 6 in image
genus %>%
filter(taxa %in% c(f_GG,b_GG)) %>%
tibble::column_to_rownames("taxa") %>%
t %>%
as.data.frame() %>%
dplyr::rename(Feacalibacterium=2,Bacteroides=1) %>%
mutate(ratio=Feacalibacterium/Bacteroides) -> f_b_ratio
# metadata %>%
# filter(SAMPLE_TYPE == "Stool") %>%
# select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
# mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
# merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
# merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
# filter(set != "outliers") %>%
# filter(Enterotypes_id != 19) %>%
# group_by(HOST_SUBJECT_ID) %>%
# mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
# filter(n>1) %>%
#
# mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
# group_by(HOST_SUBJECT_ID) %>%
# arrange(HOST_SUBJECT_ID, days) %>%
# mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
# filter(Enterotypes_id %in% c(2,6)) %>%
# ggplot() + geom_line(aes(x=days,y=shannon,group=HOST_SUBJECT_ID, col=as.character(Enterotypes_id)))
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
#filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon, ratio) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon),
ratio_before = lag(ratio)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
#filter(Enterotypes_id %in% c(2,6), Enterotypes_id_before %in% c(2,6)) %>%
ungroup() %>%
select(SAMPLE_NAME,Enterotypes_id,shannon,ratio, Enterotypes_id_before,shannon_before, ratio_before) %>%
mutate(switch=paste(Enterotypes_id,Enterotypes_id_before)) -> df
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
filter(Enterotypes_id %in% c(11,15,6,8,10,3,4,2,5,1)) %>%
ggplot() + geom_boxplot(aes(x=log2(ratio), y=as.character(Enterotypes_id)))

NA
NA
NA
fig supp
figS10A + figS10B + patchwork::plot_annotation(tag_level = "a")

ggsave("figS10.pdf")
Saving 10 x 5 in image
descriptive stat
genus %>%
filter(taxa %in% c(f_GG,b_GG)) %>%
tibble::column_to_rownames("taxa") %>%
t %>%
as.data.frame() %>%
dplyr::rename(Feacalibacterium=2,Bacteroides=1) %>%
mutate(ratio=Feacalibacterium/Bacteroides) -> f_b_ratio
# metadata %>%
# filter(SAMPLE_TYPE == "Stool") %>%
# select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
# mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
# merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
# merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
# filter(set != "outliers") %>%
# filter(Enterotypes_id != 19) %>%
# group_by(HOST_SUBJECT_ID) %>%
# mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
# filter(n>1) %>%
#
# mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
# group_by(HOST_SUBJECT_ID) %>%
# arrange(HOST_SUBJECT_ID, days) %>%
# mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
# filter(Enterotypes_id %in% c(2,6)) %>%
# ggplot() + geom_line(aes(x=days,y=shannon,group=HOST_SUBJECT_ID, col=as.character(Enterotypes_id)))
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
#filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon, ratio) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon),
ratio_before = lag(ratio)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
#filter(Enterotypes_id %in% c(2,6), Enterotypes_id_before %in% c(2,6)) %>%
ungroup() -> metadata_time_tmp
metadata_time_tmp$HOST_SUBJECT_ID %>% length()
[1] 2061
metadata_time_tmp$HOST_SUBJECT_ID %>% unique %>% length()
[1] 745
median(metadata_time_tmp$days_delta) / (60*60*24)
[1] 12.57292
quantile(metadata_time_tmp$days_delta, c(0.25,0.75)) / (60*60*24)
25% 75%
1.114583 73.041667
metadata_time_tmp %>%
filter(Enterotypes_id_before == Enterotypes_id) %>% dim
[1] 880 15
metadata_time_tmp %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(-1,60*60*24*7,120*24*60*60,365*60*60*24,10000*60*60*24))) %>%
ggplot() + geom_histogram(aes(x=days_delta/(24*60*60), fill=c(Enterotypes_id_before == Enterotypes_id)), position = "fill", breaks = c(-1,7,30,365,1000))

metadata_time_tmp %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(-1,60*60*24*7,120*24*60*60,365*60*60*24,10000*60*60*24))) %>%
ggplot() + geom_bar(aes(x=days_delta_bins, fill=c(Enterotypes_id_before == Enterotypes_id)), position="fill") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
scale_y_continuous(labels = scales::percent) + scale_fill_brewer("same partitions", type="qual") +
facet_wrap(~branches_before) + xlab("time range between two samples") + ylab("Samples %") + scale_x_discrete(labels=c("week","4 months", "4 to 12 months", "> 12 months"))

metadata_time_tmp %>%
mutate(days_delta_bins = cut(days_delta, breaks = c(-1,60*60*24*7,120*24*60*60,365*60*60*24,10000*60*60*24))) %>%
ggplot() + geom_bar(aes(x=days_delta_bins, fill=c(Enterotypes_id_before == Enterotypes_id)), position="fill") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
scale_y_continuous(labels = scales::percent) + scale_fill_brewer("same partitions", type="qual") +
xlab("time range between two samples") + ylab("Samples %") + scale_x_discrete(labels=c("week","4 months", "4 to 12 months", "> 12 months")) +
cowplot::theme_cowplot()

NA
NA
NA
NA
F B ratio
genus %>%
filter(taxa %in% c(f_GG,b_GG)) %>%
tibble::column_to_rownames("taxa") %>%
t %>%
as.data.frame() %>%
dplyr::rename(Feacalibacterium=2,Bacteroides=1) %>%
mutate(ratio=Feacalibacterium/Bacteroides) -> f_b_ratio
# metadata %>%
# filter(SAMPLE_TYPE == "Stool") %>%
# select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
# mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
# merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
# merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
# filter(set != "outliers") %>%
# filter(Enterotypes_id != 19) %>%
# group_by(HOST_SUBJECT_ID) %>%
# mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
# filter(n>1) %>%
#
# mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
# group_by(HOST_SUBJECT_ID) %>%
# arrange(HOST_SUBJECT_ID, days) %>%
# mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
# filter(Enterotypes_id %in% c(2,6)) %>%
# ggplot() + geom_line(aes(x=days,y=shannon,group=HOST_SUBJECT_ID, col=as.character(Enterotypes_id)))
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
merge(f_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
#filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon, ratio) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon),
ratio_before = lag(ratio)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
#filter(Enterotypes_id %in% c(2,6), Enterotypes_id_before %in% c(2,6)) %>%
ungroup() %>%
select(SAMPLE_NAME,Enterotypes_id,shannon,ratio, Enterotypes_id_before,shannon_before, ratio_before, branches) %>%
mutate(switch=paste(Enterotypes_id,Enterotypes_id_before)) -> df
df %>%
filter(branches=="Bacteroides DMM types") %>%
ggplot() +
geom_density(aes(x=ratio)) + scale_x_continuous(trans="log2") +
geom_vline(xintercept = 1/4)

genus %>%
filter(taxa %in% c(f_GG,b_GG)) %>%
tibble::column_to_rownames("taxa") %>%
t %>%
as.data.frame() %>%
dplyr::rename(Feacalibacterium=2,Bacteroides=1) %>%
mutate(ratio=(Feacalibacterium+1)/(Bacteroides+1)) -> f_b_ratio
frac_fun=function(x) 1/x
# f_b_ratio %>%
# merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
# filter(set != "outliers") %>%
# filter(value>0.80) %>%
# mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
# Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
# Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
# Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
# TRUE ~ "outliers")
# ) %>%
# filter(branches=="Bacteroides DMM types") %>%
# ggplot() +
# geom_density(aes(x=ratio)) + scale_x_continuous(trans="log2") +
# geom_vline(xintercept = 1/4)
f_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Bacteroides DMM types") %>%
#pull(ratio) %>% log2() %>% microbiome::bimodality(method = "Sarle.finite.sample", bs.iter=100, verbose=TRUE)
ggplot() + geom_density(aes(x=ratio)) +
scale_x_continuous(trans="log2", labels=scales::trans_format("frac_fun",scales::label_math(expr = 1/.x, format = force))) +
#geom_vline(xintercept = 1/5) +
cowplot::theme_cowplot() +
xlab("Faecalibacterium Bacteroides ratio\nwithin Bacteroides enriched branch") -> p_fprau_density
f_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Bacteroides DMM types") %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character) %>%
merge(enterotypes_time_series_stability, by="Enterotypes_id") %>%
mutate(Enterotypes_id = Enterotypes_id %>% forcats::fct_reorder(stability)) %>%
group_by(Enterotypes_id) %>%
mutate(stability = median(stability)) %>%
#pull(ratio) %>% log2() %>% microbiome::bimodality(method = "Sarle.finite.sample", bs.iter=100, verbose=TRUE)
ggplot() + geom_boxplot(aes(x=ratio,y=Enterotypes_id, fill=stability)) +
scale_x_continuous(trans="log2", labels=scales::trans_format("frac_fun",scales::label_math(expr = 1/.x, format = force))) +
scale_fill_continuous(type="viridis") +
#geom_vline(xintercept = 1/5) +
cowplot::theme_cowplot() +
ylab("Bacteroides DMM types") +
xlab("Faecalibacterium Bacteroides ratio") -> p_fprau_partition
p_fprau_density/p_fprau_partition

f_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Bacteroides DMM types") %>%
pull(ratio) %>% median
[1] 0.2050085
Fprau Bacteroides in BW
f_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Bacteroides DMM types") %>%
#pull(ratio) %>% log2() %>% microbiome::bimodality(method = "Sarle.finite.sample", bs.iter=100, verbose=TRUE)
ggplot() + geom_density(aes(x=ratio)) +
scale_x_continuous(trans="log2", labels=scales::trans_format("frac_fun",scales::label_math(expr = 1/.x, format = force))) +
#geom_vline(xintercept = 1/5) +
cowplot::theme_cowplot() +
xlab("Faecalibacterium Bacteroides ratio\nwithin Bacteroides enriched branch") -> p_fprau_density
f_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Bacteroides DMM types") %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character) %>%
merge(enterotypes_time_series_stability, by="Enterotypes_id") %>%
mutate(Enterotypes_id = Enterotypes_id %>% forcats::fct_reorder(stability)) %>%
group_by(Enterotypes_id) %>%
mutate(stability = median(stability)) %>%
#pull(ratio) %>% log2() %>% microbiome::bimodality(method = "Sarle.finite.sample", bs.iter=100, verbose=TRUE)
ggplot() + geom_boxplot(aes(x=ratio,y=Enterotypes_id, fill=stability)) +
scale_x_continuous(trans="log2", labels=scales::trans_format("frac_fun",scales::label_math(expr = 1/.x, format = force))) +
scale_fill_gradient(low="white",high="black") +
#geom_vline(xintercept = 1/5) +
cowplot::theme_cowplot() +
ylab("Bacteroides DMM partitions") +
xlab("Faecalibacterium Bacteroides ratio") -> p_fprau_partition
p_fprau_density/p_fprau_partition

NA
NA
f_b_ratio vs alpha
frac_fun=function(x) 1/x
f_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Bacteroides DMM types") %>%
merge(shannon, by.x="sample_name", by.y="row.names") %>%
mutate(substates = "High (m2, m4, m8)") %>%
mutate(substates = ifelse(Enterotypes_id %in% c("11","6","10","3"), "Medium (m3, m6, m10, m11)",substates)) %>%
mutate(substates = ifelse(Enterotypes_id %in% c("15"), "Low (m15)",substates)) %>%
mutate(substates = substates %>% forcats::fct_relevel("High (m2, m4, m8)",after=2 )) %>%
ggplot() +
geom_point(aes(x=ratio,y=shannon, col=substates), alpha=0.5) +
scale_x_continuous("Faecalibacterium:Bacteroides ratio\n from samples classified in\nBacteroides enriched branch",trans="log2", labels=scales::trans_format("frac_fun",scales::label_math(expr = 1/.x, format = force))) +
geom_vline(xintercept = 1/4, col="red") +
geom_vline(xintercept = 1/64, col="red") +
scale_color_brewer("Microbiota DMM Partitions\nclassified thank to\nFaecalibacterium:Bacteroides ratio", palette = 8, type="div") +
theme_classic()

NA
NA
NA
NA
f_b_ratio vs alpha in BW
frac_fun=function(x) 1/x
f_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Bacteroides DMM types") %>%
merge(shannon, by.x="sample_name", by.y="row.names") %>%
mutate(substates = "High (m2, m4, m8)") %>%
mutate(substates = ifelse(Enterotypes_id %in% c("11","6","10","3"), "Medium (m3, m6, m10, m11)",substates)) %>%
mutate(substates = ifelse(Enterotypes_id %in% c("15"), "Low (m15)",substates)) %>%
mutate(substates = substates %>% forcats::fct_relevel("High (m2, m4, m8)",after=2 )) %>%
ggplot() +
geom_point(aes(x=ratio,y=shannon, col=substates), alpha=0.7) +
scale_x_continuous("Faecalibacterium:Bacteroides ratio\n from samples classified in\nBacteroides enriched branch",trans="log2", labels=scales::trans_format("frac_fun",scales::label_math(expr = 1/.x, format = force))) +
geom_vline(xintercept = 1/4, col="black", linetype=2, size=1.5) +
geom_vline(xintercept = 1/64, col="black", linetype=2, size=1.5) +
scale_colour_grey("Microbiota DMM Partitions\nclassified thank to\nFaecalibacterium:Bacteroides ratio") +
#scale_color_brewer("Microbiota DMM Partitions\nclassified thank to\nFaecalibacterium:Bacteroides ratio", palette = 8, type="div") +
theme_classic()

NA
NA
NA
NA
prevotella bacteroides ratio
f_GG = "k__Bacteria;p__Firmicutes;c__Clostridia;o__Clostridiales;f__Ruminococcaceae;g__Faecalibacterium"
b_GG = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Bacteroidaceae;g__Bacteroides"
p_GG = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Prevotellaceae;g__Prevotella"
genus %>%
filter(taxa %in% c(b_GG,p_GG)) %>%
tibble::column_to_rownames("taxa") %>%
t %>%
as.data.frame() %>%
dplyr::rename(Prevotella=2,Bacteroides=1) %>%
mutate(ratio=(Prevotella+1)/(Bacteroides+1)) -> p_b_ratio
p_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Prevotella DMM types") %>%
#pull(ratio) %>% log2() %>% magrittr::add(100) %>% diptest::dip()
ggplot() + geom_density(aes(x=ratio)) + scale_x_continuous(trans="log2") +
geom_vline(xintercept = 4) + cowplot::theme_cowplot() +
xlab("Prevotella Bacteroides ratio\nwithin Prevotella enriched branch")

p_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Prevotella DMM types") %>%
#pull(ratio) %>% log2 %>% diptest::dip.test()
ggplot() + geom_density(aes(x=ratio)) + scale_x_continuous(trans="log2") +
geom_vline(xintercept = 3) + cowplot::theme_cowplot() +
xlab("Prevotella Bacteroides ratio\nwithin Bacteroides enriched branch") -> p_prevotella_density
p_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Prevotella DMM types") %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character) %>%
merge(enterotypes_time_series_stability, by="Enterotypes_id") %>%
mutate(Enterotypes_id = Enterotypes_id %>% forcats::fct_reorder(stability)) %>%
group_by(Enterotypes_id) %>%
mutate(stability = median(stability)) %>%
ggplot() + geom_boxplot(aes(x=ratio,y=Enterotypes_id, fill=stability)) +
scale_x_continuous(trans="log2") +
scale_fill_continuous(type="viridis") +
geom_vline(xintercept = 3) + cowplot::theme_cowplot() +
xlab("Prevotella Bacteroides ratio") +
ylab("Prevotella DMM types") -> p_prevotella_partition
p_prevotella_density / p_prevotella_partition

p_b_ratio %>%
merge(enterotypes,., by.y="row.names", by.x="sample_name") %>%
filter(set != "outliers") %>%
#filter(value>0.80) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
filter(branches=="Prevotella DMM types") %>% pull(ratio) %>% median
[1] 3.052897
M14 M18
#compute prevotella/bacteroides ratio and merge
f_GG = "k__Bacteria;p__Firmicutes;c__Clostridia;o__Clostridiales;f__Ruminococcaceae;g__Faecalibacterium"
b_GG = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Bacteroidaceae;g__Bacteroides"
p_GG = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Prevotellaceae;g__Prevotella"
genus %>%
filter(taxa %in% c(b_GG,p_GG)) %>%
tibble::column_to_rownames("taxa") %>%
t %>%
as.data.frame() %>%
dplyr::rename(Prevotella=2,Bacteroides=1) %>%
mutate(ratio=(Prevotella+1)/(Bacteroides+1)) -> p_b_ratio
# metadata %>%
# filter(SAMPLE_TYPE == "Stool") %>%
# select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
# mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
# merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
# merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
# filter(set != "outliers") %>%
# filter(Enterotypes_id != 19) %>%
# group_by(HOST_SUBJECT_ID) %>%
# mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
# filter(n>1) %>%
#
# mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
# group_by(HOST_SUBJECT_ID) %>%
# arrange(HOST_SUBJECT_ID, days) %>%
# mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
# filter(Enterotypes_id %in% c(2,6)) %>%
# ggplot() + geom_line(aes(x=days,y=shannon,group=HOST_SUBJECT_ID, col=as.character(Enterotypes_id)))
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
merge(p_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon, ratio) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon),
ratio_before = lag(ratio)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
filter(Enterotypes_id %in% c(14,18), Enterotypes_id_before %in% c(14,18)) %>%
ungroup() %>%
select(SAMPLE_NAME,Enterotypes_id,shannon,ratio, Enterotypes_id_before,shannon_before, ratio_before) %>%
mutate(switch=paste(Enterotypes_id,Enterotypes_id_before)) -> df
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
ggplot() + geom_boxplot(aes(x=switch,y=delta_ratio)) +
ylab("Faecalibacterium/Bacteroides\nratio variation") +
xlab("") + cowplot::theme_cowplot() +
scale_x_discrete(label=c("within\npartition M14","between\nfrom M14 to M18","between\nfrom M14 to M18","within\npartition M18")) -> fig5H
fig5H

df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
with(.,pairwise.wilcox.test(delta_ratio,switch, data=.))
Pairwise comparisons using Wilcoxon rank sum exact test
data: delta_ratio and switch
14 14 14 18 18 14
14 18 1.00 - -
18 14 0.90 1.00 -
18 18 0.94 1.00 1.00
P value adjustment method: holm
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("14 14","18 18"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("14 14","14 18"), "M14","M18") ) %>%
#arrange(switch) %>%
ggplot() + geom_line(aes(x=ratio,y=SAMPLE_NAME, group=SAMPLE_NAME, col=stable)) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2") +
#facet_wrap(~switch, ncol=1, scale="free_y") +
cowplot::theme_cowplot() +
ylab("AGP participants") + xlab("Faecalibacterium/\nBacteroides ratio") +
scale_color_manual("", values=c("black","red"), label=c("stable","unstable")) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank()) +
facet_grid(start_partition~., scales = "free_y")

rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(shannon)) %>%
mutate(stable = ifelse(switch %in% c("14 14","18 18"), "stable","unstable") ) %>%
#filter(stable == "stable") %>%
ggplot() +
geom_point(aes(x=ratio,y=shannon,col=switch))+
geom_line(aes(x=ratio,y=shannon,group=SAMPLE_NAME ,col=switch)) +
scale_x_continuous(trans = "log2") + facet_wrap(~stable)

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(p_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
ggplot() + geom_density(aes(x=ratio, fill=switch), alpha=0.5) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2")

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(p_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
ggplot() +
#geom_density(aes(x=ratio), alpha=0.5) +
geom_density(aes(x=ratio, color=switch), alpha=0.5) +
cowplot::theme_cowplot() +
theme(axis.text.y = element_blank()) +
scale_x_continuous(trans = "log2")

# df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
# filter(switch %in% c("2 2", "2 6")) %>%
# merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
# reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
# ggplot() + geom_boxplot(aes(x=switch, y=value)) + facet_wrap(~variable, scale="free")
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("14 14", "14 18")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr")) %>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_1414vs1418.csv")
Avis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequos
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("18 18", "18 14")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr"))%>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_1818vs1814.csv")
Avis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequos
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
ggplot() + geom_point(aes(x=log2(ratio_before) - log2(ratio),y=log2(shannon_before/shannon), color=switch)) +
xlim(-4,4) + ylim(-0.5, 0.5) + cowplot::theme_cowplot() + scale_color_brewer("", type="qual", palette = 2) +
xlab("Prevotella/Bacteroides variation") + ylab("alpha-diversity variation") -> figS11A
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("14 14","18 18"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("14 14","14 18"), "M14","M18") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
#arrange(switch) %>%
ggplot() + geom_line(aes(x=ratio,y=SAMPLE_NAME, group=SAMPLE_NAME, col=stable)) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2") +
#facet_wrap(~switch, ncol=1, scale="free_y") +
cowplot::theme_cowplot() +
ylab("AGP participants") + xlab("Prevotella/\nBacteroides ratio") +
scale_color_manual("", values=c("black","red"), label=c("stable","unstable")) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank()) +
facet_grid(start_partition~., scales = "free_y") -> fig5H_full
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
mutate(stable = ifelse(switch %in% c("14 14","18 18"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("14 14","14 18"), "M14","M18") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
ggplot() + geom_boxplot(aes(x=start_partition,y=delta_ratio, col=stable)) +
ylab("Prevotella/Bacteroides\nratio variation") +
#scale_y_continuous(trans="log2") +
xlab("") + cowplot::theme_cowplot() + scale_color_manual("",values=c("black","red")) -> fig5Hinset
fig5H = fig5H_full + inset_element(fig5Hinset+ylab("variation")+guides(color=FALSE), 0.65,-0.1,1,0.3, ignore_tag = TRUE)
Avis : `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
fig5H

NA
NA
NA
NA
M7 M14
#compute prevotella/bacteroides ratio and merge
f_GG = "k__Bacteria;p__Firmicutes;c__Clostridia;o__Clostridiales;f__Ruminococcaceae;g__Faecalibacterium"
b_GG = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Bacteroidaceae;g__Bacteroides"
p_GG = "k__Bacteria;p__Bacteroidetes;c__Bacteroidia;o__Bacteroidales;f__Prevotellaceae;g__Prevotella"
genus %>%
filter(taxa %in% c(b_GG,p_GG)) %>%
tibble::column_to_rownames("taxa") %>%
t %>%
as.data.frame() %>%
dplyr::rename(Prevotella=2,Bacteroides=1) %>%
mutate(ratio=(Prevotella+1)/(Bacteroides+1)) -> p_b_ratio
# metadata %>%
# filter(SAMPLE_TYPE == "Stool") %>%
# select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
# mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
# merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
# merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
# filter(set != "outliers") %>%
# filter(Enterotypes_id != 19) %>%
# group_by(HOST_SUBJECT_ID) %>%
# mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
# filter(n>1) %>%
#
# mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
# group_by(HOST_SUBJECT_ID) %>%
# arrange(HOST_SUBJECT_ID, days) %>%
# mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
# filter(Enterotypes_id %in% c(2,6)) %>%
# ggplot() + geom_line(aes(x=days,y=shannon,group=HOST_SUBJECT_ID, col=as.character(Enterotypes_id)))
metadata %>%
filter(SAMPLE_TYPE == "Stool") %>%
select(HOST_SUBJECT_ID,SAMPLE_NAME, COLLECTION_TIMESTAMP) %>%
mutate(COLLECTION_TIMESTAMP = COLLECTION_TIMESTAMP %>% lubridate::as_datetime()) %>%
merge(enterotypes, by.x="SAMPLE_NAME", by.y="sample_name") %>%
merge(shannon, by.x="SAMPLE_NAME", by.y="row.names") %>%
merge(p_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
filter(set != "outliers") %>%
filter(Enterotypes_id != 19) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(min_date = min(COLLECTION_TIMESTAMP), n=n()) %>%
filter(n>1) %>%
mutate(days=COLLECTION_TIMESTAMP - min_date) %>%
filter(days == 0 | days > 60*60*24) %>%
group_by(HOST_SUBJECT_ID) %>%
arrange(HOST_SUBJECT_ID, days) %>%
mutate(sample_order=order(COLLECTION_TIMESTAMP)) %>%
mutate(branches = case_when(Enterotypes_id %in% c(18,14,16,17,7) ~ "Prevotella DMM types",
Enterotypes_id %in% c(11,15,6,8,10,3,4,2) ~ "Bacteroides DMM types",
Enterotypes_id %in% c(12,1,5,9) ~ "Clostridiales DMM types",
Enterotypes_id %in% c(13) ~ "Akkermansia DMM types",
TRUE ~ "outliers")
) %>%
mutate(days_0=branches[which.min(sample_order)]) %>%
#arrange(HOST_SUBJECT_ID) %>%
#mutate(sample_order=rank(days)) %>%
mutate(days = as.numeric(days)) %>%
select(SAMPLE_NAME, HOST_SUBJECT_ID, days, sample_order, branches, Enterotypes_id, shannon, ratio) %>%
mutate(Enterotypes_id = Enterotypes_id %>% as.character ) %>%
group_by(HOST_SUBJECT_ID) %>%
mutate(same_branches_lag = ifelse(branches == lag(branches), "yes","no"),
branches_before=lag(branches), days_delta= days - lag(days),
Enterotypes_id_before = lag(Enterotypes_id %>% as.character),
shannon_before = lag(shannon),
ratio_before = lag(ratio)) %>%
filter(sample_order >1) %>%
mutate(branches_pairs=paste0(branches_before,"-",branches)) %>%
filter(Enterotypes_id %in% c(14,7), Enterotypes_id_before %in% c(14,7)) %>%
ungroup() %>%
select(SAMPLE_NAME,Enterotypes_id,shannon,ratio, Enterotypes_id_before,shannon_before, ratio_before) %>%
mutate(switch=paste(Enterotypes_id,Enterotypes_id_before)) -> df
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
ggplot() + geom_boxplot(aes(x=switch,y=delta_ratio)) +
ylab("Prevotella/Bacteroides\nratio variation") +
xlab("") + cowplot::theme_cowplot() +
scale_x_discrete(label=c("within\npartition M14","between\nfrom M14 to M7","between\nfrom M14 to M7","within\npartition M7")) -> fig5I
fig5I

df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
with(.,pairwise.wilcox.test(delta_ratio,switch, data=.))
Pairwise comparisons using Wilcoxon rank sum exact test
data: delta_ratio and switch
14 14 14 7 7 14
14 7 0.155 - -
7 14 0.023 0.553 -
7 7 0.805 0.155 0.020
P value adjustment method: holm
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("14 14","7 7"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("14 14","14 7"), "M14","M7") ) %>%
#arrange(switch) %>%
ggplot() + geom_line(aes(x=ratio,y=SAMPLE_NAME, group=SAMPLE_NAME, col=stable)) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2") +
#facet_wrap(~switch, ncol=1, scale="free_y") +
cowplot::theme_cowplot() +
ylab("AGP participants") + xlab("Faecalibacterium/\nBacteroides ratio") +
scale_color_manual("", values=c("black","red"), label=c("stable","unstable")) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank()) +
facet_grid(start_partition~., scales = "free_y")

rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(shannon)) %>%
mutate(stable = ifelse(switch %in% c("14 14","7 7"), "stable","unstable") ) %>%
#filter(stable == "stable") %>%
ggplot() +
geom_point(aes(x=ratio,y=shannon,col=switch))+
geom_line(aes(x=ratio,y=shannon,group=SAMPLE_NAME ,col=switch)) +
scale_x_continuous(trans = "log2") + facet_wrap(~stable)

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(p_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
ggplot() + geom_density(aes(x=ratio, fill=switch), alpha=0.5) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2")

df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
merge(p_b_ratio, by.x="SAMPLE_NAME", by.y="row.names") %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(Enterotypes_id%>%as.numeric)) %>%
ggplot() +
#geom_density(aes(x=ratio), alpha=0.5) +
geom_density(aes(x=ratio, color=switch), alpha=0.5) +
cowplot::theme_cowplot() +
theme(axis.text.y = element_blank()) +
scale_x_continuous(trans = "log2")

# df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
# filter(switch %in% c("2 2", "2 6")) %>%
# merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
# reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
# ggplot() + geom_boxplot(aes(x=switch, y=value)) + facet_wrap(~variable, scale="free")
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("14 14", "14 7")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr")) %>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_1414vs147.csv")
Avis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequos
df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch) %>%
filter(switch %in% c("7 7", "7 14")) %>%
merge(metadata_enterotypes_num %>% select(-Enterotypes_id) %>% mutate_all(as.numeric), by.x="SAMPLE_NAME", by.y="row.names") %>%
reshape2::melt(id=c("SAMPLE_NAME","Enterotypes_id","switch")) %>%
group_by(variable) %>%
tidyr::nest() %>%
mutate(wilcox_test=purrr::map(data,~wilcox.test(.x$value~.x$switch)),
tidy=purrr::map(wilcox_test, broom::tidy)) %>%
tidyr::unnest(tidy,.drop=TRUE) %>%
arrange(p.value) %>%
ungroup() %>%
#mutate(p.value=p.adjust(p.value, method="fdr"))%>%
filter(p.value<0.05) %>% select(variable,p.value) %>% write.csv2(file="metadata_link_77vs714.csv")
Avis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequosAvis : impossible de calculer la p-value exacte avec des ex-aequos
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
ggplot() + geom_point(aes(x=log2(ratio_before) - log2(ratio),y=log2(shannon_before/shannon), color=switch)) +
xlim(-4,4) + ylim(-0.5, 0.5) + cowplot::theme_cowplot() + scale_color_brewer("", type="qual", palette = 2) +
xlab("Prevotella/Bacteroides variation") + ylab("alpha-diversity variation") -> figS11B
rbind(df %>% select(SAMPLE_NAME,Enterotypes_id,shannon, switch, ratio) ,
df %>% select(SAMPLE_NAME,Enterotypes_id_before,shannon_before, switch, ratio_before) %>% dplyr::rename(Enterotypes_id=Enterotypes_id_before,shannon=shannon_before, ratio=ratio_before)) %>%
mutate(SAMPLE_NAME = SAMPLE_NAME %>% forcats::fct_reorder(ratio)) %>%
mutate(stable = ifelse(switch %in% c("14 14","7 7"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("14 14","14 7"), "M14","M7") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
#arrange(switch) %>%
ggplot() + geom_line(aes(x=ratio,y=SAMPLE_NAME, group=SAMPLE_NAME, col=stable)) + theme(axis.text.y = element_blank()) + scale_x_continuous(trans = "log2") +
#facet_wrap(~switch, ncol=1, scale="free_y") +
cowplot::theme_cowplot() +
ylab("AGP participants") + xlab("Prevotella/\nBacteroides ratio") +
scale_color_manual("", values=c("black","red"), label=c("stable","unstable")) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank()) +
facet_grid(start_partition~., scales = "free_y") -> fig5I_full
df %>%
mutate(delta_ratio = abs(log2(ratio_before) - log2(ratio))) %>%
mutate(stable = ifelse(switch %in% c("14 14","7 7"), "stable","unstable") ) %>%
mutate(start_partition = ifelse(switch %in% c("14 14","14 7"), "M14","M7") ) %>%
mutate(start_partition = start_partition %>% forcats::fct_reorder(ratio, .desc=TRUE)) %>%
ggplot() + geom_boxplot(aes(x=start_partition,y=delta_ratio, col=stable)) +
ylab("Prevotella/Bacteroides\nratio variation") +
#scale_y_continuous(trans="log2") +
xlab("") + cowplot::theme_cowplot() + scale_color_manual("",values=c("black","red")) -> fig5Iinset
fig5I = fig5I_full + inset_element(fig5Iinset+ylab("variation")+guides(color=FALSE), 0.65,-0.1,1,0.3, ignore_tag = FALSE)
Avis : `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
fig5I

NA
NA
NA
NA
bimodality and stability
pseq=phyloseq::phyloseq(OTU=genus_for_phyloseq, sample_data(metadata_for_physeq), TAX=taxa_for_phyloseq )
Error in sample_data(metadata_for_physeq) :
could not find function "sample_data"
pseq=phyloseq(OTU=genus_for_phyloseq, sample_data(metadata_for_physeq), TAX=taxa_for_phyloseq )
#pseq <- pseq %>% subset_samples(value>0.80)
pseq <- pseq %>% subset_samples(Enterotypes_id %in% c("15","1"))
pseq <- microbiome::transform(pseq, "compositional")
pseq <- aggregate_rare(pseq, level="g", detection = .1/100, prevalence = 5/100)
pseq0 <- baseline(pseq)
otu_table(pseq) %>% dim
bimodality quantifycation
# Bimodality is better estimated from abundances at log scale (such as CLR)
pseq0.clr <- microbiome::transform(pseq0, "clr")
set.seed(4433)
bimodality.score <- bimodality(pseq0.clr, method = "potential_analysis",
bs.iter = 100, peak.threshold = 10,
min.density = 10)
bimodality.score %>% sort %>% round(3)
Tipping point
# Log10 abundance for a selected taxonomic group
# Pick the most bimodal taxa as an example
#tax <- names(which.max(bimodality.score))
tax = "g__Bacillus"
# Detect tipping points at log10 abundances
x <- abundances(microbiome::transform(pseq, "clr"))[tax,]
f <- abundances(microbiome::transform(pseq, "identity"))[tax,]
b <- abundances(microbiome::transform(pseq, "identity"))["g__Bacteroides",]
x=log2((f+1)/(b+1))
# Bootstrapped potential analysis to identify potential minima
# in practice, use more bootstrap iterations
potential.minima <- potential_analysis(x, bs.iter = 10)$minima
# Same with earlywarnings package (without bootstrap ie. less robust)
# library(earlywarnings)
# res <- livpotential_ews(x)$min.points
# Identify the potential minimum locations as tipping point candidates
tipping.samples <- sapply(potential.minima, function (m) {names(which.min(abs(sort(x) - m)))})
tipping.point <- abundances(pseq)[tax, tipping.samples]
print(tipping.point)
f <- abundances(microbiome::transform(pseq, "identity"))[tax,]
b <- abundances(microbiome::transform(pseq, "identity"))["g__Bacteroides",]
x=log2((f+1)/(b+1))
# Illustrate the detected tipping point
plot(density(x), main = tax)
abline(v = x[tipping.samples])
hist(x, main = tax)
abline(v = x[tipping.samples])
data.frame(x) %>%
merge(sample_data(pseq), by="row.names") %>%
filter(Enterotypes_id %in% c("15","1")) %>%
dplyr::rename(test=x) %>%
mutate(tip=ifelse(test < x[tipping.samples][1], "low", "high")) %>%
with(.,xtabs(~tip+Enterotypes_id, data=.)) #%>% chisq.test()
by branch
branches = c("Bacteroides DMM types","Prevotella DMM types", "Clostridiales DMM types", "Akkermansia DMM types")
res=NULL
for(branch in branches) {
set.seed(666)
pseq=phyloseq(OTU=genus_for_phyloseq, sample_data(metadata_for_physeq), TAX=taxa_for_phyloseq )
pseq <- pseq %>% subset_samples(value>0.80)
pseq <- pseq %>% subset_samples(branches == branch)
pseq <- microbiome::transform(pseq, "compositional")
pseq <- aggregate_rare(pseq, level="g", detection = .1/100, prevalence = 5/100)
pseq0 <- baseline(pseq)
intermediate.stability <- intermediate_stability(pseq, output = "scores")
pseq0.clr <- microbiome::transform(pseq0, "clr")
bimodality.score <- bimodality(pseq0.clr, method = "potential_analysis",
bs.iter = 100, peak.threshold = 10,
min.density = 10)
res=rbind(
as_tibble(data.frame(bimodality.score,intermediate.stability, branches=branch) %>% tibble::rownames_to_column("taxa")),
res
)
}
merge(res,
data.frame(bimodality_score_all=bimodality.score,intermediate_stability_all=intermediate.stability),
by.y="row.names", by.x="taxa") %>%
filter(branches != "Akkermansia DMM types") %>%
ggplot + geom_point(aes(x=intermediate_stability_all, y=intermediate.stability, col=branches)) +
geom_abline(slope=1)
merge(res,
data.frame(bimodality_score_all=bimodality.score,intermediate_stability_all=intermediate.stability),
by.y="row.names", by.x="taxa") %>%
filter(branches != "Akkermansia DMM types") %>%
filter(intermediate_stability_all>0,intermediate.stability< -0.1, bimodality.score>0.6) %>%
arrange(branches) %>% pull(taxa) %>% unique -> taxa_bistable_branch
merge(res,
data.frame(bimodality_score_all=bimodality.score,intermediate_stability_all=intermediate.stability),
by.y="row.names", by.x="taxa") %>%
filter(branches != "Akkermansia DMM types") %>%
filter(intermediate_stability_all< -0.1,intermediate.stability>0, bimodality_score_all>0.6) %>%
arrange(branches) %>% pull(taxa) %>% unique
data.frame(bimodality_score_all=bimodality.score,intermediate_stability_all=intermediate.stability) %>%
filter(intermediate_stability_all< -0.1, bimodality_score_all>0.6) %>%
row.names() -> taxa_bistable_all
pseq=phyloseq(OTU=genus_for_phyloseq, sample_data(metadata_for_physeq), TAX=taxa_for_phyloseq )
pseq0 <- baseline(pseq)
sample_data(pseq) %>%
as_tibble() %>%
mutate(Enterotypes_id = as.character(Enterotypes_id)) %>%
group_by(subject) %>%
arrange(subject) %>%
mutate(n=n()) %>%
filter(n>1) %>%
arrange(subject,time) %>%
mutate(sample_before = lag(sample), time_before=lag(time), Enterotypes_id_before=lag(Enterotypes_id)) %>%
filter(!(time_before==time)) %>%
select(subject,time,time_before,sample,sample_before,Enterotypes_id,Enterotypes_id_before) %>%
mutate(partition_stability=ifelse(Enterotypes_id_before==Enterotypes_id,"stable","unstable")) -> metadata_time_lag
samples_time_series = sample_data(pseq) %>% as_tibble() %>% group_by(subject) %>% mutate(n=n()) %>% filter(n>1) %>% pull(sample)
pseq %>%
aggregate_rare(level="g", detection = .1/100, prevalence = 5/100) %>%
microbiome::transform("clr") %>%
otu_table() %>%
data.frame(check.names = FALSE) %>%
tibble::rownames_to_column("taxa") %>%
as_tibble() %>%
filter(taxa %in% c(taxa_bistable_branch,taxa_bistable_all)) -> df_tmp
df_tmp %>%
select(taxa, all_of(samples_time_series)) %>%
reshape2::melt() -> taxa_time_melt
metadata_time_lag %>%
merge(taxa_time_melt, by.x="sample", by.y="variable") %>%
merge(taxa_time_melt, by.x=c("taxa","sample_before"), by.y=c("taxa","variable")) -> metadata_taxa_time_lag
metadata_taxa_time_lag %>%
filter(taxa %in% c("g__Lactobacillus","g__Desulfovibrio")) %>%
mutate(value_abs=ifelse(value.x<value.y, value.x, value.y)) %>%
mutate(delta = abs(value.x-value.y)) %>%
mutate(switch = paste(Enterotypes_id_before,Enterotypes_id, sep="_")) %>%
group_by(switch) %>%
mutate(n_switch = n()) %>%
filter(n_switch > 15) %>%
ungroup() %>%
group_by(taxa) %>%
mutate(sample = sample %>% forcats::fct_reorder(value_abs, .desc=TRUE)) %>%
ggplot() + geom_segment(aes(x=value.x, xend=value.y,y=sample,yend=sample, col=partition_stability)) +
facet_grid(switch~taxa, scales = "free") +
scale_color_manual(values=c("grey","pink")) +
cowplot::theme_cowplot() +
theme(axis.text.y = element_blank())
metadata_taxa_time_lag %>%
filter(taxa %in% c("g__Methanobrevibacter","g__Desulfovibrio")) %>%
mutate(value_abs=ifelse(value.x<value.y, value.x, value.y)) %>%
mutate(delta = abs((value.x+value.y)/2)) %>%
mutate(switch = paste(Enterotypes_id_before,Enterotypes_id, sep="_")) %>%
group_by(switch) %>%
mutate(n_switch = n()) %>%
filter(n_switch > 6) %>%
ungroup() %>%
ggplot() + geom_boxplot(aes(x=switch,y=delta)) +
facet_grid(partition_stability~taxa, scale="free", space = "free_y" ) +
coord_flip()
metadata_taxa_time_lag %>%
filter(taxa %in% c("g__Prevotella","g__Odoribacter")) %>%
mutate(value_abs=ifelse(value.x<value.y, value.x, value.y)) %>%
mutate(value_m = ((value.x+value.y)/2)) %>%
mutate(delta = abs(value.x-value.y)) %>%
mutate(switch = paste(Enterotypes_id_before,Enterotypes_id, sep="_")) %>%
group_by(switch) %>%
mutate(n_switch = n()) %>%
#filter(n_switch > 15) %>%
ungroup() %>%
#filter(partition_stability=="unstable") %>%
ggplot() + geom_point(aes(x=value_m,y=delta,col=partition_stability)) +
facet_grid(partition_stability~taxa)
metadata_taxa_time_lag %>%
filter(taxa %in% c("g__Prevotella","g__Bacillus")) %>%
mutate(value_abs=ifelse(value.x<value.y, value.x, value.y)) %>%
mutate(value_m = abs((value.x+value.y)/2)) %>%
mutate(delta = abs(value.x-value.y)) %>%
mutate(switch = paste(Enterotypes_id_before,Enterotypes_id, sep="_")) %>%
group_by(switch) %>%
mutate(n_switch = n()) %>%
#filter(n_switch > 15) %>%
ungroup()
res=NULL
for(i in 1:17){
for(j in i:18) {
if(i==j) next
i=as.character(i)
j=as.character(j)
switch=paste(i,j, sep="_")
metadata_taxa_time_lag %>%
#filter(taxa %in% c("g__Prevotella","g__Odoribacter")) %>%
filter(Enterotypes_id %in% c(i,j), Enterotypes_id_before %in% c(i,j)) %>%
mutate(delta= abs(value.x-value.y)) -> tmp1
if(length(names(table(tmp1$partition_stability))) == 1) {next}
tmp1 %>%
group_by(taxa) %>%
do(with(.,wilcox.test(delta~partition_stability, data=.) %>% broom::tidy())) %>%
filter(p.value<0.05) %>%
mutate(switch=switch) -> tmp2
res=rbind(tmp2,res)
} }
res %>% select(taxa,switch)
res2=NULL
for(i in 1:17){
for(j in i:18) {
if(i==j) next
i=as.character(i)
j=as.character(j)
switch=paste(i,j, sep="_")
metadata_taxa_time_lag %>%
#filter(taxa %in% c("g__Prevotella","g__Odoribacter")) %>%
filter(Enterotypes_id %in% c(i,j), Enterotypes_id_before %in% c(i,j)) %>%
mutate(value_m=(value.x+value.y/2)) %>%
#filter(partition_stability == "unstable") %>%
group_by(taxa) %>%
do(with(.,wilcox.test(value.x~Enterotypes_id, data=.) %>% broom::tidy())) %>%
filter(p.value<0.05) %>%
mutate(switch=switch) -> tmp
res2=rbind(tmp,res2)
} }
res2
merge(res %>% select(taxa, switch),
res2 %>% select(taxa, switch), by=c("taxa","switch"))
metadata_taxa_time_lag %>%
#filter(taxa %in% c("g__Prevotella","g__Odoribacter")) %>%
filter(Enterotypes_id %in% c("3","5"), Enterotypes_id_before %in% c("3","5")) %>%
mutate(value_m=(value.x+value.y/2)) %>%
#filter(partition_stability == "unstable") %>%
group_by(taxa) %>%
do(with(.,wilcox.test(value.x~Enterotypes_id, data=.) %>% broom::tidy())) %>%
filter(p.value<0.05)
metadata_taxa_time_lag %>%
filter(taxa %in% c("g__Prevotella","g__Odoribacter")) %>%
filter(Enterotypes_id %in% c("3","5"), Enterotypes_id_before %in% c("3","5")) %>%
filter(partition_stability == "unstable") %>%
mutate(value_m=(value.x+value.y/2)) %>%
ggplot() + ggforce::geom_sina(aes(x=Enterotypes_id, y=value_m))
metadata_taxa_time_lag %>%
filter(taxa %in% c("g__Akkermansia")) %>%
#filter(Enterotypes_id %in% c("1","5","9","12"), Enterotypes_id_before %in% c("1","5","9","12")) %>%
mutate(switch = paste(Enterotypes_id_before,Enterotypes_id, sep="_")) %>%
mutate(value_m=(value.x+value.y/2)) %>%
mutate(sample = sample %>% forcats::fct_reorder(value_m, .desc=TRUE)) %>%
#filter(partition_stability=="stable") %>%
ggplot() + geom_segment(aes(x=value.x, xend=value.y,y=sample,yend=sample)) +
facet_grid(partition_stability~taxa, scales = "free") +
#scale_color_manual(values=c("grey","pink")) +
cowplot::theme_cowplot() +
theme(axis.text.y = element_blank())
LS0tDQp0aXRsZTogImVudGVyb2JyYW5jaGVzIHZzIHRpbWUtc2VyaWVzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KDQoNCg0KYGBge3J9DQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpkZXZ0b29sczo6bG9hZF9hbGwocmVzZXQgPSBGQUxTRSkNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KDQpsb2FkKCJhZ3BfbWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtLnJkYSIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQoNCmVudGVyb3R5cGVzID0gcmVhZHI6OnJlYWRfY3N2MigiZW50ZXJvdHlwZXNfcHJlZGljdGlvbl9vdXRsaWVycy5jc3YiKVssLTFdDQoNCm1ldGFkYXRhPXJlYWQuY3N2MihzeXN0ZW0uZmlsZSgiZGF0YS1yYXcvTWV0YWRhdGFfMTAzMTdfMjAxOTEwMjItMTEyNDE0X2N1cmF0ZWR2NF9WU3YxLmNzdiIsIHBhY2thZ2UgPSAiZ3V0emlsbGEiKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSAlPiUgbXV0YXRlX2FsbChuYV9pZiwiIikNCg0Kc2hhbm5vbl9wYXRoID0gc3lzdGVtLmZpbGUoImRhdGEtcmF3L3FpaW1lL2dlbmVyYXRlZC1maWxlcy0yMDE5MDUxMi9hbHBoYS9zaGFubm9uLnF6YSIsIHBhY2thZ2UgPSAiZ3V0emlsbGEiKQ0KDQpzaGFubm9uID0gcWlpbWUyUjo6cmVhZF9xemEoc2hhbm5vbl9wYXRoKSRkYXRhICU+JSBhcy5kYXRhLmZyYW1lDQoNCmBgYA0KDQpgYGB7cn0NCg0KbWV0YWRhdGEgJT4lDQogIGZpbHRlcihTQU1QTEVfVFlQRSA9PSAiU3Rvb2wiKSAlPiUNCiAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRlKCkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBzdW1tYXJpc2Uobj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgcHVsbChuKSAlPiUgdGFibGUNCg0KDQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZSgpKSAlPiUNCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICBtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JSANCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9ZGF5cyx5PXNhbXBsZV9vcmRlciwgZ3JvdXA9SE9TVF9TVUJKRUNUX0lEKSkgKyBzY2FsZV95X2xvZzEwKCkNCg0KDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZSgpKSAlPiUNCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICBtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JSANCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9cmFuayhkYXlzKSkgJT4lIA0KICB4dGFicyh+IGJyYW5jaGVzICsgSE9TVF9TVUJKRUNUX0lELCBkYXRhPS4pICU+JQ0KICBhcy5kYXRhLmZyYW1lICU+JQ0KICBmaWx0ZXIoRnJlcSE9MCkNCg0KDQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZSgpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICE9IDE5KSAlPiUNCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JSANCiAgDQoNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIA0KICBtdXRhdGUoZGF5c18wPWJyYW5jaGVzW3doaWNoLm1pbihzYW1wbGVfb3JkZXIpXSkgJT4lIA0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCkgICU+JSANCiAgI211dGF0ZShzYW1wbGVfb3JkZXI9cmFuayhkYXlzKSkgJT4lDQogIG11dGF0ZShkYXlzID0gYXMubnVtZXJpYyhkYXlzKSkgJT4lIA0KICBmaWx0ZXIoYW55KGRheXM9PTApKSAlPiUgDQogIGZpbHRlcihzYW1wbGVfb3JkZXI+MSAmIGRheXMgPDI1KSAlPiUgDQogIGdncGxvdCgpICsgZ2VvbV90aWxlKGFlcyh4PXNhbXBsZV9vcmRlcix5PUhPU1RfU1VCSkVDVF9JRCwgZmlsbD1icmFuY2hlcykpICsNCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpKSArIGZhY2V0X3dyYXAofmRheXNfMCwgc2NhbGVzPSJmcmVlX3kiKQ0KDQoNCg0KDQpgYGANCg0KDQpgYGB7cn0NCg0KbWV0YWRhdGEgJT4lDQogIGZpbHRlcihTQU1QTEVfVFlQRSA9PSAiU3Rvb2wiKSAlPiUNCiAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRlKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQogIGZpbHRlcihuPjEpICU+JQ0KICANCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUgDQogIA0KDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JSANCiAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHg9ZGF5cyArMSx5PUhPU1RfU1VCSkVDVF9JRCwgY29sPWJyYW5jaGVzKSwgc2hhcGU9MTUpICsNCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpKSArIGZhY2V0X3dyYXAofmRheXNfMCwgc2NhbGVzPSJmcmVlX3kiKSArIHNjYWxlX3hfbG9nMTAoKQ0KIA0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGUoKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgZmlsdGVyKG4+MSkgJT4lDQogIA0KICBtdXRhdGUoZGF5cz1DT0xMRUNUSU9OX1RJTUVTVEFNUCAtIG1pbl9kYXRlKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JSANCiAgDQoNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIA0KICBtdXRhdGUoZGF5c18wPWJyYW5jaGVzW3doaWNoLm1pbihzYW1wbGVfb3JkZXIpXSkgJT4lIA0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBmaWx0ZXIoZGF5cyA+IDAsIGRheXM8MzY1KSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzZWxlY3QoZGF5c18wLGJyYW5jaGVzKSAlPiUgDQogIHh0YWJzKH5kYXlzXzArYnJhbmNoZXMsIGRhdGE9LikgJT4lIHByb3AudGFibGUoMSkNCg0KDQoNCg0KDQpgYGANCg0KDQoNCg0KDQoNCmBgYHtyfQ0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGUoKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgZmlsdGVyKG4+MSkgJT4lDQogIA0KICBtdXRhdGUoZGF5cz1DT0xMRUNUSU9OX1RJTUVTVEFNUCAtIG1pbl9kYXRlKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JSANCiAgDQoNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIA0KICBtdXRhdGUoZGF5c18wPWJyYW5jaGVzW3doaWNoLm1pbihzYW1wbGVfb3JkZXIpXSkgJT4lIA0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzKSAlPiUNCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKHNhbWVfYnJhbmNoZXNfbGFnID0gaWZlbHNlKGJyYW5jaGVzID09IGxhZyhicmFuY2hlcyksICJ5ZXMiLCJubyIpLCBicmFuY2hlc19iZWZvcmU9bGFnKGJyYW5jaGVzKSwgZGF5c19kZWx0YT0gZGF5cyAtIGxhZyhkYXlzKSkgJT4lIA0KICBmaWx0ZXIoc2FtcGxlX29yZGVyID4xKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzX3BhaXJzPXBhc3RlMChicmFuY2hlc19iZWZvcmUsIi0iLGJyYW5jaGVzKSkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9ib3hwbG90KGFlcyh4PWJyYW5jaGVzX3BhaXJzLCB5PWRheXNfZGVsdGErMSkpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSsgDQogIHNjYWxlX3lfbG9nMTAoKSArIGZhY2V0X3dyYXAofmJyYW5jaGVzX2JlZm9yZSwgc2NhbGVzID0gImZyZWUiLCBucm93PTEpDQoNCg0KDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCg0KbWV0YWRhdGEgJT4lDQogIGZpbHRlcihTQU1QTEVfVFlQRSA9PSAiU3Rvb2wiKSAlPiUNCiAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRldGltZSgpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICE9IDE5KSAlPiUNCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiAgDQogIGZpbHRlcihkYXlzID09IDAgfCBkYXlzID4gNjAqNjAqMjQpICU+JQ0KICANCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQsIGRheXMpICU+JQ0KICBtdXRhdGUoc2FtcGxlX29yZGVyPW9yZGVyKENPTExFQ1RJT05fVElNRVNUQU1QKSkgJT4lIA0KICANCg0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHBhcnRpdGlvbnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHBhcnRpdGlvbnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSBwYXJ0aXRpb25zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHBhcnRpdGlvbnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JSANCiAgI2FycmFuZ2UoSE9TVF9TVUJKRUNUX0lEKSAgJT4lIA0KICAjbXV0YXRlKHNhbXBsZV9vcmRlcj1yYW5rKGRheXMpKSAlPiUNCiAgbXV0YXRlKGRheXMgPSBhcy5udW1lcmljKGRheXMpKSAlPiUNCiAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCwgZGF5cywgc2FtcGxlX29yZGVyLCBicmFuY2hlcykgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShzYW1lX2JyYW5jaGVzX2xhZyA9IGlmZWxzZShicmFuY2hlcyA9PSBsYWcoYnJhbmNoZXMpLCAieWVzIiwibm8iKSwgYnJhbmNoZXNfYmVmb3JlPWxhZyhicmFuY2hlcyksIGRheXNfZGVsdGE9IGRheXMgLSBsYWcoZGF5cykpICU+JSANCiAgZmlsdGVyKHNhbXBsZV9vcmRlciA+MSkgJT4lDQogIG11dGF0ZShicmFuY2hlc19wYWlycz1wYXN0ZTAoYnJhbmNoZXNfYmVmb3JlLCItIixicmFuY2hlcykpICU+JQ0KICBtdXRhdGUoZGF5c19kZWx0YV9iaW5zID0gY3V0KGRheXNfZGVsdGEsIGJyZWFrcyA9IGMoLTEsNjAqNjAqMjQqNywxMjAqMjQqNjAqNjAsMzY1KjYwKjYwKjI0LDEwMDAwKjYwKjYwKjI0KSkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh4PWRheXNfZGVsdGFfYmlucywgZmlsbD1icmFuY2hlcyksIHBvc2l0aW9uPSJmaWxsIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKyBzY2FsZV9maWxsX2JyZXdlcigiYnJhbmNoZXMgYWZ0ZXIiLCB0eXBlPSJxdWFsIikgKw0KICBmYWNldF93cmFwKH5icmFuY2hlc19iZWZvcmUpICsgeGxhYigidGltZSByYW5nZSBiZXR3ZWVuIHR3byBzYW1wbGVzIikgKyB5bGFiKCJTYW1wbGVzICUiKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIjwgMSB3ZWVrIiwiMSB3ZWVrIHRvIDQgbW9udGhzIiwgIjQgdG8gMTIgbW9udGhzIiwgIj4gMTIgbW9udGhzIikpIC0+IGZpZ1M5QQ0KDQpmaWdTOUENCg0KDQpnZ3NhdmUoImZpZ3VyZXMvRmlnUzlBX2JyYW5jaGVfYmVmb3JlX2FmdGVyLnBkZiIpDQoNCmBgYA0KIyMgY29tcHV0ZSBwcmV2b3RlbGxhIGJhY3Rlcm9pZGVzIHJhdGlvIHdpdGhpbiBkYXlzDQpgYGB7cn0NCg0KDQpnZW51c19wYXRoID0gc3lzdGVtLmZpbGUoImRhdGEtcmF3L3FpaW1lL2dlbmVyYXRlZC1maWxlcy0yMDE5MDUxMi90YXhhL2dlbnVzLnF6YSIsIHBhY2thZ2UgPSAiZ3V0emlsbGEiKQ0KZ2VudXMgPSBxaWltZTJSOjpyZWFkX3F6YShnZW51c19wYXRoKSRkYXRhICU+JSBhcy5kYXRhLmZyYW1lICU+JSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigidGF4YSIpICAlPiUgYXNfdGliYmxlKCkNCg0KZ2VudXMgJT4lIA0KICBmaWx0ZXIodGF4YSAlaW4lIGMoImtfX0JhY3RlcmlhO3BfX0JhY3Rlcm9pZGV0ZXM7Y19fQmFjdGVyb2lkaWE7b19fQmFjdGVyb2lkYWxlcztmX19CYWN0ZXJvaWRhY2VhZTtnX19CYWN0ZXJvaWRlcyIsDQogICAgICAgICAgICAgICAgICAgICAia19fQmFjdGVyaWE7cF9fQmFjdGVyb2lkZXRlcztjX19CYWN0ZXJvaWRpYTtvX19CYWN0ZXJvaWRhbGVzO2ZfX1ByZXZvdGVsbGFjZWFlO2dfX1ByZXZvdGVsbGEiKSkgJT4lDQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJ0YXhhIikgJT4lDQogIHQoKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpIC0+IFRTX2FncF9nZW51c19QX0INCg0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQogIGZpbHRlcihuPjEpICU+JQ0KICANCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsZGF5cywgQ09MTEVDVElPTl9USU1FU1RBTVApIC0+IGhvc3Rfc2FtcGxlX2RheXMNCg0KDQpob3N0X3NhbXBsZV9kYXlzICU+JQ0KICBtZXJnZShob3N0X3NhbXBsZV9kYXlzLCBieT0iSE9TVF9TVUJKRUNUX0lEIikgJT4lDQogIGZpbHRlcighKFNBTVBMRV9OQU1FLng9PVNBTVBMRV9OQU1FLnkpKSAlPiUNCiAgZmlsdGVyKGRheXMueT5kYXlzLngpICU+JQ0KICBtdXRhdGUoZGF5c19kZWx0YSA9IGRheXMueS1kYXlzLngpICU+JQ0KICBmaWx0ZXIoZGF5c19kZWx0YSA8PSA2MCo2MCoyNCkgLT4gaG9zdF9zYW1wbGVfcGFpcnNfd2l0aGluX2RheXMNCg0KDQoNCg0KDQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZXRpbWUoKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgZmlsdGVyKG4+MSkgJT4lDQogIA0KICBtdXRhdGUoZGF5cz1DT0xMRUNUSU9OX1RJTUVTVEFNUCAtIG1pbl9kYXRlKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JSANCiAgDQoNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsYnJhbmNoZXMsQ09MTEVDVElPTl9USU1FU1RBTVApIC0+IGhvc3Rfc2FtcGxlX2VudGVyb3R5cGVzX2JyYW5jaGVzDQogIA0KICANCmhvc3Rfc2FtcGxlX3BhaXJzX3dpdGhpbl9kYXlzICU+JQ0KICBtZXJnZShob3N0X3NhbXBsZV9lbnRlcm90eXBlc19icmFuY2hlcywgYnkueD1jKCJIT1NUX1NVQkpFQ1RfSUQiLCJTQU1QTEVfTkFNRS54IiwgIkNPTExFQ1RJT05fVElNRVNUQU1QLngiKSwgYnkueT1jKCJIT1NUX1NVQkpFQ1RfSUQiLCJTQU1QTEVfTkFNRSIsIkNPTExFQ1RJT05fVElNRVNUQU1QIikpICU+JQ0KICBtZXJnZShob3N0X3NhbXBsZV9lbnRlcm90eXBlc19icmFuY2hlcywgYnkueD1jKCJIT1NUX1NVQkpFQ1RfSUQiLCJTQU1QTEVfTkFNRS55IiwgIkNPTExFQ1RJT05fVElNRVNUQU1QLnkiKSwgYnkueT1jKCJIT1NUX1NVQkpFQ1RfSUQiLCJTQU1QTEVfTkFNRSIsIkNPTExFQ1RJT05fVElNRVNUQU1QIikpICU+JQ0KICBtZXJnZShUU19hZ3BfZ2VudXNfUF9CLCBieS54PSJTQU1QTEVfTkFNRS54IiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIG1lcmdlKFRTX2FncF9nZW51c19QX0IsIGJ5Lng9IlNBTVBMRV9OQU1FLnkiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgZHBseXI6OnJlbmFtZShCYWN0ZXJvaWRlczEgPSAia19fQmFjdGVyaWE7cF9fQmFjdGVyb2lkZXRlcztjX19CYWN0ZXJvaWRpYTtvX19CYWN0ZXJvaWRhbGVzO2ZfX0JhY3Rlcm9pZGFjZWFlO2dfX0JhY3Rlcm9pZGVzLngiLA0KICAgICAgICAgICAgICAgIFByZXZvdGVsbGExICA9ICJrX19CYWN0ZXJpYTtwX19CYWN0ZXJvaWRldGVzO2NfX0JhY3Rlcm9pZGlhO29fX0JhY3Rlcm9pZGFsZXM7Zl9fUHJldm90ZWxsYWNlYWU7Z19fUHJldm90ZWxsYS54IiwNCiAgICAgICAgICAgICAgICBCYWN0ZXJvaWRlczIgPSAia19fQmFjdGVyaWE7cF9fQmFjdGVyb2lkZXRlcztjX19CYWN0ZXJvaWRpYTtvX19CYWN0ZXJvaWRhbGVzO2ZfX0JhY3Rlcm9pZGFjZWFlO2dfX0JhY3Rlcm9pZGVzLnkiLA0KICAgICAgICAgICAgICAgIFByZXZvdGVsbGEyICA9ICJrX19CYWN0ZXJpYTtwX19CYWN0ZXJvaWRldGVzO2NfX0JhY3Rlcm9pZGlhO29fX0JhY3Rlcm9pZGFsZXM7Zl9fUHJldm90ZWxsYWNlYWU7Z19fUHJldm90ZWxsYS55IikgJT4lDQogIG11dGF0ZShQQl9yYXRpb18xID0gbG9nMigoUHJldm90ZWxsYTErMSkvKEJhY3Rlcm9pZGVzMSsxKSksIFBCX3JhdGlvXzIgPSBsb2cyKChQcmV2b3RlbGxhMisxKS8oQmFjdGVyb2lkZXMyKzEpKSkgJT4lDQogIG11dGF0ZShkZWx0YSA9IFBCX3JhdGlvXzItUEJfcmF0aW9fMSkgLT4gaG9zdF9zYW1wbGVfZW50ZXJvdHlwZXNfYnJhbmNoZXNfUF9CX3JhdGlvDQoNCmhvc3Rfc2FtcGxlX2VudGVyb3R5cGVzX2JyYW5jaGVzX1BfQl9yYXRpbyAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzLnggJWluJSBjKCJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLCJQcmV2b3RlbGxhIERNTSB0eXBlcyIpLA0KICAgICAgICAgYnJhbmNoZXMueSAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIikpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh4PXBhc3RlKGJyYW5jaGVzLngpLCBmaWxsPWJyYW5jaGVzLnkpKSArIGNvb3JkX2ZsaXAoKQ0KDQoNCg0KaG9zdF9zYW1wbGVfZW50ZXJvdHlwZXNfYnJhbmNoZXNfUF9CX3JhdGlvICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXMueCAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIiksDQogICAgICAgICBicmFuY2hlcy55ICVpbiUgYygiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwiUHJldm90ZWxsYSBETU0gdHlwZXMiKSkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9ib3hwbG90KGFlcyh5PWRlbHRhLCBicmFuY2hlcy54LCBmaWxsPWJyYW5jaGVzLnkpKQ0KDQoNCg0KaG9zdF9zYW1wbGVfZW50ZXJvdHlwZXNfYnJhbmNoZXNfUF9CX3JhdGlvICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXMueCAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIiksDQogICAgICAgICBicmFuY2hlcy55ICVpbiUgYygiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwiUHJldm90ZWxsYSBETU0gdHlwZXMiKSkgJT4lDQogIGdncGxvdCgpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9UEJfcmF0aW9fMSwgeT1QQl9yYXRpb18yLCBjb2xvcj1wYXN0ZShicmFuY2hlcy54LCItPiIsYnJhbmNoZXMueSksIHNpemU9ZGF5c19kZWx0YSA8IDEqNjAqNjApKSArDQogIGdlb21fYWJsaW5lKHNsb3BlPTEsaW50ZXJjZXB0ID0gMCkgKw0KICBnZW9tX2FibGluZShzbG9wZT0xLGludGVyY2VwdCA9IC0yLjUsIGxpbmV0eXBlPTIpICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGU9MSxpbnRlcmNlcHQgPSAyLjUsIGxpbmV0eXBlPTIpICsNCiAgeGxhYigiUC9CIHJhdGlvIDFzdCBzYW1wbGUiKSArIHlsYWIoIlAvQiByYXRpbyAybmQgc2FtcGxlIikgKw0KICBzY2FsZV9zaXplX2Rpc2NyZXRlKCJsZXNzIHRoYW5cbjYwIG1pbnV0ZXMiKSArDQogIHNjYWxlX2NvbG91cl9kaXNjcmV0ZSgiIikgKw0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgLT4gZmlnUzlCDQogIA0KZmlnUzlCDQoNCg0KICANCiAgaG9zdF9zYW1wbGVfZW50ZXJvdHlwZXNfYnJhbmNoZXNfUF9CX3JhdGlvICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXMueCAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIiksDQogICAgICAgICBicmFuY2hlcy55ICVpbiUgYygiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwiUHJldm90ZWxsYSBETU0gdHlwZXMiKSkgJT4lDQogIGZpbHRlcihicmFuY2hlcy54ICVpbiUgIlByZXZvdGVsbGEgRE1NIHR5cGVzIikgJT4lDQogICAgbXV0YXRlKGxlc3NfdGhhbl9vbmVfaG91ciA9IGRheXNfZGVsdGEgPCAxKjYwKjYwKSAlPiUNCiAgICB4dGFicyh+YnJhbmNoZXMueSArIGxlc3NfdGhhbl9vbmVfaG91ciwgZGF0YT0uKSAjJT4lIGNoaXNxLnRlc3QoKQ0KICAgIA0KIA0KICBob3N0X3NhbXBsZV9lbnRlcm90eXBlc19icmFuY2hlc19QX0JfcmF0aW8gJT4lDQogIGZpbHRlcihicmFuY2hlcy54ICVpbiUgYygiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwiUHJldm90ZWxsYSBETU0gdHlwZXMiKSwNCiAgICAgICAgIGJyYW5jaGVzLnkgJWluJSBjKCJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLCJQcmV2b3RlbGxhIERNTSB0eXBlcyIpKSAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzLnggJWluJSAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIikgJT4lDQogICAgbXV0YXRlKGxlc3NfdGhhbl9vbmVfaG91ciA9IGRheXNfZGVsdGEgPCAxKjYwKjYwKSAlPiUNCiAgICB4dGFicyh+YnJhbmNoZXMueSArIGxlc3NfdGhhbl9vbmVfaG91ciwgZGF0YT0uKSAjJT4lIGNoaXNxLnRlc3QoKQ0KICANCiAgICAgICANCg0KYGBgDQoNCmNoZWNrIHN0b29sIGNvbGxldCBkYWlseSB0aW1lDQoNCmBgYHtyfQ0KDQoNCmhvc3Rfc2FtcGxlX2VudGVyb3R5cGVzX2JyYW5jaGVzX1BfQl9yYXRpbyAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzLnggJWluJSBjKCJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLCJQcmV2b3RlbGxhIERNTSB0eXBlcyIpLA0KICAgICAgICAgYnJhbmNoZXMueSAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIikpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX3BvaW50KGFlcyh4PVBCX3JhdGlvXzEsIHk9UEJfcmF0aW9fMiwgY29sb3I9cGFzdGUoYnJhbmNoZXMueCwiLT4iLGJyYW5jaGVzLnkpLCBzaXplPWRheXNfZGVsdGEgPCAxKjYwKjYwKSkgKw0KICBnZW9tX2FibGluZShzbG9wZT0xLGludGVyY2VwdCA9IDApICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGU9MSxpbnRlcmNlcHQgPSAtMi41LCBsaW5ldHlwZT0yKSArDQogIGdlb21fYWJsaW5lKHNsb3BlPTEsaW50ZXJjZXB0ID0gMi41LCBsaW5ldHlwZT0yKSArDQogIHhsYWIoIlAvQiByYXRpbyAxc3Qgc2FtcGxlIikgKyB5bGFiKCJQL0IgcmF0aW8gMm5kIHNhbXBsZSIpICsNCiAgc2NhbGVfc2l6ZV9kaXNjcmV0ZSgibGVzcyB0aGFuXG42MCBtaW51dGVzIikgKw0KICBzY2FsZV9jb2xvdXJfZGlzY3JldGUoIiIpDQoNCmhvc3Rfc2FtcGxlX2VudGVyb3R5cGVzX2JyYW5jaGVzX1BfQl9yYXRpbyAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzLnggJWluJSBjKCJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLCJQcmV2b3RlbGxhIERNTSB0eXBlcyIpLA0KICAgICAgICAgYnJhbmNoZXMueSAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIikpICU+JQ0KICBtdXRhdGUoaG91cnMueD1DT0xMRUNUSU9OX1RJTUVTVEFNUC54ICU+JSBsdWJyaWRhdGU6OmhvdXIoKSwgaG91cnMueT1DT0xMRUNUSU9OX1RJTUVTVEFNUC55ICU+JSBsdWJyaWRhdGU6OmhvdXIoKSkgJT4lDQogIG11dGF0ZShkYXl0aW1lID0gaWZlbHNlKGhvdXJzLnggPCAxMiAmIGhvdXJzLnkgPCAxMiwgImJvdGggbW9ybmluZyIsIGlmZWxzZShob3Vycy54ID49IDEyICYgaG91cnMueSA+PSAxMiwgImJvdGggYWZ0ZXJub29uIiwgIm5vIikpKSAlPiUNCiAgZ2dwbG90KCkgKyANCiAgZ2VvbV9wb2ludChhZXMoeD1QQl9yYXRpb18xLCB5PVBCX3JhdGlvXzIsIGNvbG9yPWRheXRpbWUpKSArDQogIGdlb21fYWJsaW5lKHNsb3BlPTEsaW50ZXJjZXB0ID0gMCkgKw0KICBnZW9tX2FibGluZShzbG9wZT0xLGludGVyY2VwdCA9IC0yLjUsIGxpbmV0eXBlPTIpICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGU9MSxpbnRlcmNlcHQgPSAyLjUsIGxpbmV0eXBlPTIpICsNCiAgeGxhYigiUC9CIHJhdGlvIDFzdCBzYW1wbGUiKSArIHlsYWIoIlAvQiByYXRpbyAybmQgc2FtcGxlIikgKw0KICBzY2FsZV9zaXplX2Rpc2NyZXRlKCJsZXNzIHRoYW5cbjYwIG1pbnV0ZXMiKSArDQogIHNjYWxlX2NvbG91cl9kaXNjcmV0ZSgiIikNCiANCg0KDQoNCg0KaG9zdF9zYW1wbGVfZW50ZXJvdHlwZXNfYnJhbmNoZXNfUF9CX3JhdGlvICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXMueCAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIiksDQogICAgICAgICBicmFuY2hlcy55ICVpbiUgYygiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwiUHJldm90ZWxsYSBETU0gdHlwZXMiKSkgJT4lDQogIG11dGF0ZShob3Vycy54PUNPTExFQ1RJT05fVElNRVNUQU1QLnggJT4lIGx1YnJpZGF0ZTo6aG91cigpLCBob3Vycy55PUNPTExFQ1RJT05fVElNRVNUQU1QLnkgJT4lIGx1YnJpZGF0ZTo6aG91cigpKSAlPiUNCiAgbXV0YXRlKGRheXRpbWUgPSBpZmVsc2UoaG91cnMueCA8IDEyICYgaG91cnMueSA8IDEyLCAiYm90aCBtb3JuaW5nIiwgaWZlbHNlKGhvdXJzLnggPj0gMTIgJiBob3Vycy55ID49IDEyLCAiYm90aCBhZnRlcm5vb24iLCAibm8iKSkpICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXMueD09IlByZXZvdGVsbGEgRE1NIHR5cGVzInxicmFuY2hlcy55PT0iUHJldm90ZWxsYSBETU0gdHlwZXMiKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX2JveHBsb3QoYWVzKGZpbGw9cGFzdGUoYnJhbmNoZXMueCwiLT4iLGJyYW5jaGVzLnkpLHk9KFBCX3JhdGlvXzErUEJfcmF0aW9fMikvMix4PWRheXRpbWUpKSArDQogIGNvb3JkX2ZsaXAoKQ0KDQoNCmhvc3Rfc2FtcGxlX2VudGVyb3R5cGVzX2JyYW5jaGVzX1BfQl9yYXRpbyAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzLnggJWluJSBjKCJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLCJQcmV2b3RlbGxhIERNTSB0eXBlcyIpLA0KICAgICAgICAgYnJhbmNoZXMueSAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIikpICU+JQ0KICBtdXRhdGUoaG91cnMueD1DT0xMRUNUSU9OX1RJTUVTVEFNUC54ICU+JSBsdWJyaWRhdGU6OmhvdXIoKSwgaG91cnMueT1DT0xMRUNUSU9OX1RJTUVTVEFNUC55ICU+JSBsdWJyaWRhdGU6OmhvdXIoKSkgJT4lDQogIG11dGF0ZShkYXl0aW1lID0gaWZlbHNlKGhvdXJzLnggPCAxMiAmIGhvdXJzLnkgPCAxMiwgImJvdGggbW9ybmluZyIsIGlmZWxzZShob3Vycy54ID49IDEyICYgaG91cnMueSA+PSAxMiwgImJvdGggYWZ0ZXJub29uIiwgIm5vIikpKSAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzLng9PSJQcmV2b3RlbGxhIERNTSB0eXBlcyJ8YnJhbmNoZXMueT09IlByZXZvdGVsbGEgRE1NIHR5cGVzIikgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9iYXIoYWVzKHg9cGFzdGUoYnJhbmNoZXMueCwiLT4iLGJyYW5jaGVzLnkpLCBmaWxsPWRheXRpbWUpLCBwb3NpdGlvbj0iZmlsbCIgKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpIA0KDQpob3N0X3NhbXBsZV9lbnRlcm90eXBlc19icmFuY2hlc19QX0JfcmF0aW8gJT4lDQogIGZpbHRlcihicmFuY2hlcy54ICVpbiUgYygiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwiUHJldm90ZWxsYSBETU0gdHlwZXMiKSwNCiAgICAgICAgIGJyYW5jaGVzLnkgJWluJSBjKCJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLCJQcmV2b3RlbGxhIERNTSB0eXBlcyIpKSAlPiUNCiAgbXV0YXRlKGhvdXJzLng9Q09MTEVDVElPTl9USU1FU1RBTVAueCAlPiUgbHVicmlkYXRlOjpob3VyKCksIGhvdXJzLnk9Q09MTEVDVElPTl9USU1FU1RBTVAueSAlPiUgbHVicmlkYXRlOjpob3VyKCkpICU+JQ0KICBtdXRhdGUoZGF5dGltZSA9IGlmZWxzZShob3Vycy54IDwgMTIgJiBob3Vycy55IDwgMTIsICJib3RoIiwgaWZlbHNlKGhvdXJzLnggPj0gMTIgJiBob3Vycy55ID49IDEyLCAiYm90aCIsICJubyIpKSkgJT4lDQogIGZpbHRlcihicmFuY2hlcy54PT0iUHJldm90ZWxsYSBETU0gdHlwZXMifGJyYW5jaGVzLnk9PSJQcmV2b3RlbGxhIERNTSB0eXBlcyIpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fYmFyKGFlcyh4PXBhc3RlKGJyYW5jaGVzLngsIi0+IixicmFuY2hlcy55KSwgZmlsbD1kYXl0aW1lKSwgcG9zaXRpb249ImZpbGwiICkgKyB4bGFiKCIiKSArIGNvb3JkX2ZsaXAoKQ0KDQoNCmhvc3Rfc2FtcGxlX2VudGVyb3R5cGVzX2JyYW5jaGVzX1BfQl9yYXRpbyAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzLnggJWluJSBjKCJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLCJQcmV2b3RlbGxhIERNTSB0eXBlcyIpLA0KICAgICAgICAgYnJhbmNoZXMueSAlaW4lIGMoIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIlByZXZvdGVsbGEgRE1NIHR5cGVzIikpICU+JQ0KICBtdXRhdGUoaG91cnMueD1DT0xMRUNUSU9OX1RJTUVTVEFNUC54ICU+JSBsdWJyaWRhdGU6OmhvdXIoKSwgaG91cnMueT1DT0xMRUNUSU9OX1RJTUVTVEFNUC55ICU+JSBsdWJyaWRhdGU6OmhvdXIoKSkgJT4lDQogIG11dGF0ZShkYXl0aW1lID0gaWZlbHNlKGhvdXJzLnggPCAxMiAmIGhvdXJzLnkgPCAxMiwgImJvdGgiLCBpZmVsc2UoaG91cnMueCA+PSAxMiAmIGhvdXJzLnkgPj0gMTIsICJib3RoIiwgIm5vIikpKSAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzLng9PSJQcmV2b3RlbGxhIERNTSB0eXBlcyJ8YnJhbmNoZXMueT09IlByZXZvdGVsbGEgRE1NIHR5cGVzIikgJT4lDQogIHh0YWJzKH4gcGFzdGUoYnJhbmNoZXMueCwiLT4iLGJyYW5jaGVzLnkpICsgZGF5dGltZSwgZGF0YT0uKSAlPiUNCiAgY2hpc3EudGVzdCgpDQoNCg0KYGBgDQoNCg0KIyMgZmlndXJlIHN1cHAgOQ0KDQpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xNn0NCg0KZmlnUzlBICsgZmlnUzlCICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpDQoNCmdnc2F2ZSgiZmlndXJlcy9maWdTOS5wZGYiKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGUoKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgZmlsdGVyKG4+MSkgJT4lDQogIA0KICBtdXRhdGUoZGF5cz1DT0xMRUNUSU9OX1RJTUVTVEFNUCAtIG1pbl9kYXRlKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JSANCiAgDQoNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIA0KICBtdXRhdGUoZGF5c18wPWJyYW5jaGVzW3doaWNoLm1pbihzYW1wbGVfb3JkZXIpXSkgJT4lIA0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBzZWxlY3QoU0FNUExFX05BTUUsIEhPU1RfU1VCSkVDVF9JRCwgZGF5cywgc2FtcGxlX29yZGVyLCBicmFuY2hlcykgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShzYW1lX2JyYW5jaGVzX2xhZyA9IGlmZWxzZShicmFuY2hlcyA9PSBsYWcoYnJhbmNoZXMpLCAieWVzIiwibm8iKSwgYnJhbmNoZXNfYmVmb3JlPWxhZyhicmFuY2hlcyksIGRheXNfZGVsdGE9IGRheXMgLSBsYWcoZGF5cykpICU+JSANCiAgZmlsdGVyKHNhbXBsZV9vcmRlciA+MSkgJT4lDQogIG11dGF0ZShicmFuY2hlc19wYWlycz1wYXN0ZTAoYnJhbmNoZXNfYmVmb3JlLCItIixicmFuY2hlcykpICU+JQ0KICBtdXRhdGUoZGF5c19kZWx0YV9iaW5zID0gY3V0KGRheXNfZGVsdGEsIGJyZWFrcyA9IGMoMCw3LDMwLDEyMCwzNjUsMTAwMDApKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZmlsdGVyKGlzLm5hKGRheXNfZGVsdGFfYmlucykpDQoNCg0KDQpgYGANCg0KDQpgYGB7cn0NCg0KbWV0YWRhdGEgJT4lDQogIGZpbHRlcihTQU1QTEVfVFlQRSA9PSAiU3Rvb2wiKSAlPiUNCiAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRldGltZSgpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICE9IDE5KSAlPiUNCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQsIGRheXMpICU+JQ0KICBtdXRhdGUoc2FtcGxlX29yZGVyPW9yZGVyKENPTExFQ1RJT05fVElNRVNUQU1QKSkgJT4lIA0KICANCg0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzXzA9YnJhbmNoZXNbd2hpY2gubWluKHNhbXBsZV9vcmRlcildKSAlPiUgDQogICNhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCkgICU+JSANCiAgI211dGF0ZShzYW1wbGVfb3JkZXI9cmFuayhkYXlzKSkgJT4lDQogIG11dGF0ZShkYXlzID0gYXMubnVtZXJpYyhkYXlzKSkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSwgSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkNCg0KDQpgYGANCiMjIyBzdGFiaWxpdHkgYnkgcGFydGl0aW9uDQpgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMH0NCg0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQogIGZpbHRlcihuPjEpICU+JQ0KICANCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUgDQogIA0KDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JSANCiAgI2FycmFuZ2UoSE9TVF9TVUJKRUNUX0lEKSAgJT4lIA0KICAjbXV0YXRlKHNhbXBsZV9vcmRlcj1yYW5rKGRheXMpKSAlPiUNCiAgbXV0YXRlKGRheXMgPSBhcy5udW1lcmljKGRheXMpKSAlPiUNCiAgc2VsZWN0KFNBTVBMRV9OQU1FLCBIT1NUX1NVQkpFQ1RfSUQsIEVudGVyb3R5cGVzX2lkLCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShkZWx0YV9kYXlzID0gZGF5cy1sYWcoZGF5cyksIGVudGVyb3R5cGVzX2JlZm9yZSA9IGxhZyhFbnRlcm90eXBlc19pZCkpICU+JQ0KICBtdXRhdGUoc3RhYmxlPWlmZWxzZShlbnRlcm90eXBlc19iZWZvcmU9PUVudGVyb3R5cGVzX2lkLCJzdGFibGUiLCJzd2l0Y2giKSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgZmlsdGVyKGRlbHRhX2RheXM+MjQqNjAqNjApICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHk9KGRlbHRhX2RheXMpLygyNCo2MCo2MCksIHg9cGFzdGUwKCJNIixlbnRlcm90eXBlc19iZWZvcmUpLCBmaWxsPXN0YWJsZSkpICsgDQogIHNjYWxlX3lfbG9nMTAoImRheXMiKSArIHhsYWIoIiIpICsgY293cGxvdDo6dGhlbWVfY293cGxvdCgpIC0+IHBfcGFydGl0aW9uX3N0YWJpbGl0eQ0KDQpwX3BhcnRpdGlvbl9zdGFiaWxpdHkNCg0KcF9wYXJ0aXRpb25fc3RhYmlsaXR5JGRhdGEgJT4lDQogIGZpbHRlcihzdGFibGU9PSJzdGFibGUiKSAlPiUNCiAgI2dyb3VwX2J5KGVudGVyb3R5cGVzX2JlZm9yZSkgJT4lDQogIHdpdGgoLixwYWlyd2lzZS53aWxjb3gudGVzdChkZWx0YV9kYXlzLGVudGVyb3R5cGVzX2JlZm9yZSwgZGF0YT0uKSkgJT4lIGJyb29tOjp0aWR5KCkNCg0KcF9wYXJ0aXRpb25fc3RhYmlsaXR5JGRhdGEgJT4lDQogICNmaWx0ZXIoc3RhYmxlPT0ic3RhYmxlIikgJT4lDQogICNncm91cF9ieShlbnRlcm90eXBlc19iZWZvcmUpICU+JQ0KICB3aXRoKC4scGFpcndpc2Uud2lsY294LnRlc3QoZGVsdGFfZGF5cyxzdGFibGUsIGRhdGE9LikpICU+JSBicm9vbTo6dGlkeSgpDQoNCnBfcGFydGl0aW9uX3N0YWJpbGl0eSRkYXRhICU+JQ0KICBncm91cF9ieShzdGFibGUpICU+JQ0KICBzdW1tYXJpc2UobT1tZWRpYW4oZGVsdGFfZGF5cy8oMjQqNjAqNjApKSwgDQogICAgICAgICAgICBxMjU9cXVhbnRpbGUoZGVsdGFfZGF5cy8oMjQqNjAqNjApLCAwLjI1KSwNCiAgICAgICAgICAgIHE3NT1xdWFudGlsZShkZWx0YV9kYXlzLygyNCo2MCo2MCksIDAuNzUpKQ0KDQoNCnBfcGFydGl0aW9uX3N0YWJpbGl0eSRkYXRhICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHk9KGRlbHRhX2RheXMpLygyNCo2MCo2MCksIGZpbGw9c3RhYmxlKSkgKw0KICBzY2FsZV95X2xvZzEwKCJkYXlzIikgKyB4bGFiKCIiKSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKQ0KDQpgYGANCg0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQ0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBtZXJnZShzaGFubm9uLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQogIGZpbHRlcihuPjEpICU+JQ0KICANCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUgDQogIA0KDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JQ0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBFbnRlcm90eXBlc19pZCwgc2hhbm5vbikgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIgKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShzYW1lX2JyYW5jaGVzX2xhZyA9IGlmZWxzZShicmFuY2hlcyA9PSBsYWcoYnJhbmNoZXMpLCAieWVzIiwibm8iKSwgDQogICAgICAgICBicmFuY2hlc19iZWZvcmU9bGFnKGJyYW5jaGVzKSwgZGF5c19kZWx0YT0gZGF5cyAtIGxhZyhkYXlzKSwgDQogICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgPSBsYWcoRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlciksDQogICAgICAgICBzaGFubm9uX2JlZm9yZSA9IGxhZyhzaGFubm9uKSkgJT4lDQogIGZpbHRlcihzYW1wbGVfb3JkZXIgPjEpICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfcGFpcnM9cGFzdGUwKGJyYW5jaGVzX2JlZm9yZSwiLSIsYnJhbmNoZXMpKSAlPiUNCiAgbXV0YXRlKGRheXNfZGVsdGFfYmlucyA9IGN1dChkYXlzX2RlbHRhLCBicmVha3MgPSBjKC0xLDYwKjYwKjI0LDEyMCoyNCo2MCo2MCwzNjUqNjAqNjAqMjQsMTAwMDAqNjAqNjAqMjQpKSkgJT4lDQogIGZpbHRlcihicmFuY2hlc19iZWZvcmUgPT0gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsIGJyYW5jaGVzID09ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiKSAlPiUNCiAgDQogIHNlbGVjdChzaGFubm9uX2JlZm9yZSxzaGFubm9uLEVudGVyb3R5cGVzX2lkLEVudGVyb3R5cGVzX2lkX2JlZm9yZSkgJT4lDQogICAgdW5ncm91cCgpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZCxFbnRlcm90eXBlc19pZF9iZWZvcmUpICU+JQ0KICBzdW1tYXJpc2Uoc2hhbm5vbj1tZWRpYW4oc2hhbm5vbiksIHNoYW5ub25fYmVmb3JlPW1lZGlhbihzaGFubm9uX2JlZm9yZSksIG5fcD1uKCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGdyb3VwX2J5KEVudGVyb3R5cGVzX2lkX2JlZm9yZSkgJT4lDQogIG11dGF0ZShwcm9wX25fcCA9IG5fcC9zdW0obl9wKSkgJT4lDQogIGdyb3VwX2J5KEVudGVyb3R5cGVzX2lkX2JlZm9yZSkgJT4lDQogIGFycmFuZ2UoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLCBkZXNjKHByb3Bfbl9wKSkgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBmYWN0b3IobGV2ZWw9YygiMiIsIjQiLCIzIiwiMTAiLCI4IiwiNiIsIjE1IiwiMTEiKSksDQogICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgPSBFbnRlcm90eXBlc19pZF9iZWZvcmUgJT4lIGZhY3RvcihsZXZlbD1jKCIyIiwiNCIsIjMiLCIxMCIsIjgiLCI2IiwiMTUiLCIxMSIpKSkgJT4lIA0KICBtdXRhdGUoc2hhbm5vbl9zZW5zID0gc2hhbm5vbl9iZWZvcmU+IHNoYW5ub24sIGVudGVyb3R5cGVfc2VucyA9IGFzLm51bWVyaWMoRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSA+IGFzLm51bWVyaWMoRW50ZXJvdHlwZXNfaWQpKSAtPiBCYWN0ZXJvaWRlc19lbnRlcm90eXBlc19zaGFubm9uX3BhaXJzIA0KDQoNCg0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBtZXJnZShzaGFubm9uLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQogIGZpbHRlcihuPjEpICU+JQ0KICANCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUgDQogIA0KDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JQ0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBFbnRlcm90eXBlc19pZCwgc2hhbm5vbikgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIgKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShzYW1lX2JyYW5jaGVzX2xhZyA9IGlmZWxzZShicmFuY2hlcyA9PSBsYWcoYnJhbmNoZXMpLCAieWVzIiwibm8iKSwgDQogICAgICAgICBicmFuY2hlc19iZWZvcmU9bGFnKGJyYW5jaGVzKSwgZGF5c19kZWx0YT0gZGF5cyAtIGxhZyhkYXlzKSwgDQogICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgPSBsYWcoRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlciksDQogICAgICAgICBzaGFubm9uX2JlZm9yZSA9IGxhZyhzaGFubm9uKSkgJT4lDQogIGZpbHRlcihzYW1wbGVfb3JkZXIgPjEpICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfcGFpcnM9cGFzdGUwKGJyYW5jaGVzX2JlZm9yZSwiLSIsYnJhbmNoZXMpKSAlPiUNCiAgbXV0YXRlKGRheXNfZGVsdGFfYmlucyA9IGN1dChkYXlzX2RlbHRhLCBicmVha3MgPSBjKC0xLDYwKjYwKjI0LDEyMCoyNCo2MCo2MCwzNjUqNjAqNjAqMjQsMTAwMDAqNjAqNjAqMjQpKSkgJT4lDQogIGZpbHRlcihicmFuY2hlc19iZWZvcmUgPT0gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwgYnJhbmNoZXMgPT0gIlByZXZvdGVsbGEgRE1NIHR5cGVzIikgJT4lDQogIA0KICBzZWxlY3Qoc2hhbm5vbl9iZWZvcmUsc2hhbm5vbixFbnRlcm90eXBlc19pZCxFbnRlcm90eXBlc19pZF9iZWZvcmUpICU+JQ0KICAgIHVuZ3JvdXAoKSAlPiUNCiAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWQsRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSAlPiUNCiAgc3VtbWFyaXNlKHNoYW5ub249bWVkaWFuKHNoYW5ub24pLCBzaGFubm9uX2JlZm9yZT1tZWRpYW4oc2hhbm5vbl9iZWZvcmUpLCBuX3A9bigpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZF9iZWZvcmUpICU+JQ0KICBtdXRhdGUocHJvcF9uX3AgPSBuX3Avc3VtKG5fcCkpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZF9iZWZvcmUpICU+JQ0KICBhcnJhbmdlKEVudGVyb3R5cGVzX2lkX2JlZm9yZSwgZGVzYyhwcm9wX25fcCkpICU+JQ0KICBtdXRhdGUoRW50ZXJvdHlwZXNfaWQgPSBFbnRlcm90eXBlc19pZCAlPiUgZmFjdG9yKGxldmVsPWMoIjciLCIxNyIsIjE2IiwiMTQiLCIxOCIpKSwNCiAgICAgICAgIEVudGVyb3R5cGVzX2lkX2JlZm9yZSA9IEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlPiUgZmFjdG9yKGxldmVsPWMoIjciLCIxNyIsIjE2IiwiMTQiLCIxOCIpKSkgJT4lIA0KICBtdXRhdGUoc2hhbm5vbl9zZW5zID0gc2hhbm5vbl9iZWZvcmU+IHNoYW5ub24sIGVudGVyb3R5cGVfc2VucyA9IGFzLm51bWVyaWMoRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSA+IGFzLm51bWVyaWMoRW50ZXJvdHlwZXNfaWQpKSAtPiBQcmV2b3RlbGxhX2VudGVyb3R5cGVzX3NoYW5ub25fcGFpcnMgDQoNCg0KDQpjb3dwbG90OjpwbG90X2dyaWQoDQpCYWN0ZXJvaWRlc19lbnRlcm90eXBlc19zaGFubm9uX3BhaXJzICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGZpbHRlcighKEVudGVyb3R5cGVzX2lkPT1FbnRlcm90eXBlc19pZF9iZWZvcmUpKSAlPiUNCiAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSAlPiUNCiAgYXJyYW5nZShFbnRlcm90eXBlc19pZF9iZWZvcmUsIGRlc2Mobl9wKSkgJT4lDQogIGRwbHlyOjpzbGljZSgxOjIpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX3NlZ21lbnQoYWVzKHk9c2hhbm5vbl9iZWZvcmUsIA0KICAgICAgICB5ZW5kPXNoYW5ub24sIA0KICAgICAgICB4PUVudGVyb3R5cGVzX2lkX2JlZm9yZSAlPiUgZmFjdG9yKGxldmVsPWMoIjIiLCI0IiwiMyIsIjEwIiwiOCIsIjYiLCIxNSIsIjExIikpLCANCiAgICAgICAgeGVuZD1FbnRlcm90eXBlc19pZCAlPiUgZmFjdG9yKGxldmVsPWMoIjIiLCI0IiwiMyIsIjEwIiwiOCIsIjYiLCIxNSIsIjExIikpLCANCiAgICAgICAgY29sb3I9ZW50ZXJvdHlwZV9zZW5zKSwgDQogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMSwiY20iKSkpICsNCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyh4PUVudGVyb3R5cGVzX2lkX2JlZm9yZSAlPiUgZmFjdG9yKGxldmVsPWMoIjIiLCI0IiwiMyIsIjEwIiwiOCIsIjYiLCIxNSIsIjExIikpLA0KICAgICAgICAgICAgICAgIHk9c2hhbm5vbl9iZWZvcmUsDQogICAgICAgICAgICAgICAgbGFiZWw9cm91bmQocHJvcF9uX3AsMikgJT4lIHNjYWxlczo6cGVyY2VudChhY2N1cmFjeT0xKSkpICsNCiAgeGxhYigiQmFjdGVyb2lkZXMgYnJhbmNoIHBhcnRpdGlvblxub3JkZXJlZCBieSBQSEFURSBjZW50cm9pZCBwb3NpdGlvbiIpICsNCiAgeWxhYigiYWxwaGEtZGl2ZXJzaXR5XG4oU2hhbm5vbikiKSArDQogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKCIiLCBsYWJlbHM9YygidG93YXJkIGJyYW5jaC10aXAiLCAidG93YXJkIGJyYW5jaC1yb290IikpLA0KDQpCYWN0ZXJvaWRlc19lbnRlcm90eXBlc19zaGFubm9uX3BhaXJzICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGZpbHRlcigoRW50ZXJvdHlwZXNfaWQ9PUVudGVyb3R5cGVzX2lkX2JlZm9yZSkpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX2JhcihhZXMoeD1FbnRlcm90eXBlc19pZF9iZWZvcmUseT1wcm9wX25fcCwgZmlsbD1zaGFubm9uKSwgc3RhdD0iaWRlbnRpdHkiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgeGxhYigiQmFjdGVyb2lkZXMgYnJhbmNoIHBhcnRpdGlvblxub3JkZXJlZCBieSBQSEFURSBjZW50cm9pZCBwb3NpdGlvbiIpICsNCiAgeWxhYigic3RhYmxlIHBhcnRpY2lwYW50IHNhbXBsZS1wYWlyZWRcbnByb3BvcnRpb25zIiksDQoNCg0KDQoNCg0KUHJldm90ZWxsYV9lbnRlcm90eXBlc19zaGFubm9uX3BhaXJzICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGZpbHRlcighKEVudGVyb3R5cGVzX2lkPT1FbnRlcm90eXBlc19pZF9iZWZvcmUpKSAlPiUNCiAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSAlPiUNCiAgYXJyYW5nZShFbnRlcm90eXBlc19pZF9iZWZvcmUsIGRlc2Mobl9wKSkgJT4lDQogIGRwbHlyOjpzbGljZSgxOjIpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX3NlZ21lbnQoYWVzKHk9c2hhbm5vbl9iZWZvcmUsIA0KICAgICAgICB5ZW5kPXNoYW5ub24sIA0KICAgICAgICB4PUVudGVyb3R5cGVzX2lkX2JlZm9yZSAlPiUgZmFjdG9yKGxldmVsPWMoIjciLCIxNyIsIjE2IiwiMTQiLCIxOCIpKSwgDQogICAgICAgIHhlbmQ9RW50ZXJvdHlwZXNfaWQgJT4lIGZhY3RvcihsZXZlbD1jKCI3IiwiMTciLCIxNiIsIjE0IiwiMTgiKSksIA0KICAgICAgICBjb2xvcj1lbnRlcm90eXBlX3NlbnMpLCANCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4xLCJjbSIpKSkgKw0KICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKHg9RW50ZXJvdHlwZXNfaWRfYmVmb3JlICU+JSBmYWN0b3IobGV2ZWw9YygiNyIsIjE3IiwiMTYiLCIxNCIsIjE4IikpLA0KICAgICAgICAgICAgICAgIHk9c2hhbm5vbl9iZWZvcmUsDQogICAgICAgICAgICAgICAgbGFiZWw9cm91bmQocHJvcF9uX3AsMikgJT4lIHNjYWxlczo6cGVyY2VudChhY2N1cmFjeT0xKSkpICsNCiAgeGxhYigiUHJldm90ZWxsYSBicmFuY2ggcGFydGl0aW9uXG5vcmRlcmVkIGJ5IFBIQVRFIGNlbnRyb2lkIHBvc2l0aW9uIikgKw0KICB5bGFiKCJhbHBoYS1kaXZlcnNpdHlcbihTaGFubm9uKSIpICsNCiAgc2NhbGVfY29sb3JfZGlzY3JldGUoIiIsIGxhYmVscz1jKCJ0b3dhcmQgYnJhbmNoLXRpcCIsICJ0b3dhcmQgYnJhbmNoLXJvb3QiKSksDQoNClByZXZvdGVsbGFfZW50ZXJvdHlwZXNfc2hhbm5vbl9wYWlycyAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIoKEVudGVyb3R5cGVzX2lkPT1FbnRlcm90eXBlc19pZF9iZWZvcmUpKSAlPiUNCiAgZ2dwbG90KCkgKyANCiAgZ2VvbV9iYXIoYWVzKHg9RW50ZXJvdHlwZXNfaWRfYmVmb3JlLHk9cHJvcF9uX3AsIGZpbGw9c2hhbm5vbiksIHN0YXQ9ImlkZW50aXR5IikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogIHhsYWIoIlByZXZvdGVsbGEgYnJhbmNoIHBhcnRpdGlvblxub3JkZXJlZCBieSBQSEFURSBjZW50cm9pZCBwb3NpdGlvbiIpICsNCiAgeWxhYigic3RhYmxlIHBhcnRpY2lwYW50IHNhbXBsZS1wYWlyZWRcbnByb3BvcnRpb25zIiksIG5yb3cgPSAyLCByZWxfd2lkdGhzID0gYygyLDEpKQ0KDQoNCg0KDQoNCmBgYA0KDQojIyBndXQgbWljcm9iaW90YSBwYXJ0aXRpb25zIG5ldHdvcmtzIGJhc2VkIG9uIHRpbWVzIHNlcmllcyANCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZXRpbWUoKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogIG1lcmdlKHNoYW5ub24sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgZmlsdGVyKG4+MSkgJT4lDQogIA0KICBtdXRhdGUoZGF5cz1DT0xMRUNUSU9OX1RJTUVTVEFNUCAtIG1pbl9kYXRlKSAlPiUgDQogIA0KICANCiAgZmlsdGVyKGRheXMgPT0gMCB8IGRheXMgPiA2MCo2MCoyNCkgJT4lDQogIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUgDQogIA0KDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JQ0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBFbnRlcm90eXBlc19pZCwgc2hhbm5vbikgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIgKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShzYW1lX2JyYW5jaGVzX2xhZyA9IGlmZWxzZShicmFuY2hlcyA9PSBsYWcoYnJhbmNoZXMpLCAieWVzIiwibm8iKSwgDQogICAgICAgICBicmFuY2hlc19iZWZvcmU9bGFnKGJyYW5jaGVzKSwgZGF5c19kZWx0YT0gZGF5cyAtIGxhZyhkYXlzKSwgDQogICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgPSBsYWcoRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlciksDQogICAgICAgICBzaGFubm9uX2JlZm9yZSA9IGxhZyhzaGFubm9uKSkgJT4lDQogIGZpbHRlcihzYW1wbGVfb3JkZXIgPjEpICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfcGFpcnM9cGFzdGUwKGJyYW5jaGVzX2JlZm9yZSwiLSIsYnJhbmNoZXMpKSAlPiUNCiAgbXV0YXRlKGRheXNfZGVsdGFfYmlucyA9IGN1dChkYXlzX2RlbHRhLCBicmVha3MgPSBjKC0xLDYwKjYwKjI0KjcsMTIwKjI0KjYwKjYwLDM2NSo2MCo2MCoyNCwxMDAwMCo2MCo2MCoyNCkpKSAlPiUNCiAgdW5ncm91cCgpIC0+IGVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX25ldHdvcmtfcmF3DQogICNmaWx0ZXIoZGF5c19kZWx0YV9iaW5zICVpbiUgYygiKC0xLDguNjRlKzA0XSIsIig4LjY0ZSswNCwxLjA0ZSswN10iKSkgJT4lDQogIA0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29ya19yYXcgJT4lDQpncm91cF9ieShFbnRlcm90eXBlc19pZF9iZWZvcmUsRW50ZXJvdHlwZXNfaWQpICU+JQ0KICBzdW1tYXJpc2Uobj1uKCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGFycmFuZ2UoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLGRlc2MobikpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZF9iZWZvcmUpICU+JQ0KICBtdXRhdGUocD1uL3N1bShuKSktPiBlbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrDQogICNkcGx5cjo6c2xpY2UoMTozKQ0KYGBgDQoNCiMjIyBmaWd1cmUgc3RhYmlsaXR5IHZzIHJhbmRvbQ0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX25ldHdvcmsgJT4lDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfYmVmb3JlID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBtdXRhdGUoZ3JvdXAgPSBpZmVsc2UoRW50ZXJvdHlwZXNfaWRfYmVmb3JlID09IEVudGVyb3R5cGVzX2lkLCAid2l0aGluIFBhcnRpdGlvbiIsIGlmZWxzZShicmFuY2hlc19iZWZvcmU9PWJyYW5jaGVzLCAid2l0aGluIEJyYW5jaGVzIiwgImJldHdlZW4gQnJhbmNoZXMiKSApKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2JhcihhZXMoeD1FbnRlcm90eXBlc19pZF9iZWZvcmUsIHk9cCwgZmlsbD1ncm91cCksIHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImZpbGwiKSArIA0KICBmYWNldF93cmFwKH5icmFuY2hlc19iZWZvcmUsIHNjYWxlcyA9ICJmcmVlIiwgbnJvdz0xKSANCg0KDQplbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrX3JhdyAlPiUNCiAgc2VsZWN0KEVudGVyb3R5cGVzX2lkLEVudGVyb3R5cGVzX2lkX2JlZm9yZSkgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IHNhbXBsZShFbnRlcm90eXBlc19pZCkpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZF9iZWZvcmUsRW50ZXJvdHlwZXNfaWQpICU+JQ0KICBzdW1tYXJpc2Uobj1uKCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGFycmFuZ2UoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLGRlc2MobikpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZF9iZWZvcmUpICU+JQ0KICBtdXRhdGUocD1uL3N1bShuKSkgICAtPiB0bXANCg0KDQp0bXAgJT4lDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfYmVmb3JlID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KIyAgbXV0YXRlKGdyb3VwID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkX2JlZm9yZSA9PSBFbnRlcm90eXBlc19pZCwgIndpdGhpbiBQYXJ0aXRpb24iLCBpZmVsc2UoYnJhbmNoZXNfYmVmb3JlPT1icmFuY2hlcywgIndpdGhpbiBCcmFuY2hlcyIsICJiZXR3ZWVuIEJyYW5jaGVzIikgKSkgJT4lDQogbXV0YXRlKGdyb3VwID0gaWZlbHNlKGJyYW5jaGVzX2JlZm9yZT09YnJhbmNoZXMsIndpdGhpbiBCcmFuY2hlcyIgLCJiZXR3ZWVuIEJyYW5jaGVzIikpICU+JQ0KICAgZ2dwbG90KCkgKyBnZW9tX2JhcihhZXMoeD1FbnRlcm90eXBlc19pZF9iZWZvcmUsIHk9cCwgZmlsbD1ncm91cCksIHN0YXQ9ImlkZW50aXR5IikgKyANCiAgZmFjZXRfd3JhcCh+YnJhbmNoZXNfYmVmb3JlLCBzY2FsZXMgPSAiZnJlZSIsIG5yb3c9MSkgDQoNCg0KDQoNCg0KDQoNCg0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29ya19yYW5kb209TlVMTA0KDQpmb3IgKGkgaW4gMToxMDApIHsNCmVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX25ldHdvcmtfcmF3ICU+JQ0KICBzZWxlY3QoRW50ZXJvdHlwZXNfaWQsRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gc2FtcGxlKEVudGVyb3R5cGVzX2lkKSkgJT4lDQogIGdyb3VwX2J5KEVudGVyb3R5cGVzX2lkX2JlZm9yZSxFbnRlcm90eXBlc19pZCkgJT4lDQogIHN1bW1hcmlzZShuPW4oKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgYXJyYW5nZShFbnRlcm90eXBlc19pZF9iZWZvcmUsZGVzYyhuKSkgJT4lDQogIGdyb3VwX2J5KEVudGVyb3R5cGVzX2lkX2JlZm9yZSkgJT4lDQogIG11dGF0ZShwPW4vc3VtKG4pLCBpdGVyYXRpb249aSkgICAtPiB0bXANCg0KICBlbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrX3JhbmRvbSA9DQogICAgcmJpbmQoZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29ya19yYW5kb20sdG1wKQ0KICANCg0KfQ0KDQoNCmVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX25ldHdvcmtfcmFuZG9tICU+JQ0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzX2JlZm9yZSA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiBtdXRhdGUoZ3JvdXAgPSBpZmVsc2UoRW50ZXJvdHlwZXNfaWRfYmVmb3JlID09IEVudGVyb3R5cGVzX2lkLCAid2l0aGluIFBhcnRpdGlvbiIsIGlmZWxzZShicmFuY2hlc19iZWZvcmU9PWJyYW5jaGVzLCAid2l0aGluIEJyYW5jaGVzIiwgImJldHdlZW4gQnJhbmNoZXMiKSApKSAlPiUNCiAjbXV0YXRlKGdyb3VwID0gaWZlbHNlKGJyYW5jaGVzX2JlZm9yZT09YnJhbmNoZXMsIndpdGhpbiBCcmFuY2hlcyIgLCJiZXR3ZWVuIEJyYW5jaGVzIikpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZF9iZWZvcmUsZ3JvdXAsaXRlcmF0aW9uKSAlPiUNCiAgc3VtbWFyaXNlKHA9c3VtKHApKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QoYWVzKHg9RW50ZXJvdHlwZXNfaWRfYmVmb3JlLCB5PXAsIGZpbGw9Z3JvdXApKQ0KDQoNCg0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29ya19yYW5kb20gJT4lDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYVxuRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzXG5ETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzXG5ETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2suIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzX2JlZm9yZSA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGFcbkRNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXNcbkRNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzXG5ETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygxMykgfiAiQWtrLiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogbXV0YXRlKGdyb3VwID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkX2JlZm9yZSA9PSBFbnRlcm90eXBlc19pZCwgIndpdGhpbiBQYXJ0aXRpb24iLCBpZmVsc2UoYnJhbmNoZXNfYmVmb3JlPT1icmFuY2hlcywgIndpdGhpbiBCcmFuY2hcbmJldHdlZW4gUGFydGl0aW9ucyIsICJiZXR3ZWVuIEJyYW5jaGVzIikgKSkgJT4lDQogI211dGF0ZShncm91cCA9IGlmZWxzZShicmFuY2hlc19iZWZvcmU9PWJyYW5jaGVzLCJ3aXRoaW4gQnJhbmNoZXMiICwiYmV0d2VlbiBCcmFuY2hlcyIpKSAlPiUNCiAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLGdyb3VwLGJyYW5jaGVzX2JlZm9yZSxpdGVyYXRpb24pICU+JQ0KICBzdW1tYXJpc2UocD1zdW0ocCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHNlbGVjdCgtaXRlcmF0aW9uKSAlPiUNCiAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLGJyYW5jaGVzX2JlZm9yZSxncm91cCkgJT4lDQogIHN1bW1hcmlzZShwOTU9cXVhbnRpbGUocCwwLjk1KSxwMDU9cXVhbnRpbGUocCwwLjA1KSkgJT4lDQogIG11dGF0ZShwPWlmZWxzZShncm91cCE9IndpdGhpbiBQYXJ0aXRpb24iLCBwMDUscDk1KSkgJT4lDQogIHNlbGVjdCgtcDk1LCAtcDA1KSAlPiUNCiAgbXV0YXRlKGRhdGFzZXQ9IlJhbmRvbWl6ZWQgQ0kgOTUlIikgJT4lDQogIA0KICByYmluZCggDQogICAgICAgICAgZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yayAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhXG5ETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXNcbkRNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXNcbkRNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFray4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfYmVmb3JlID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYVxuRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlc1xuRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXNcbkRNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDEzKSB+ICJBa2suIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgbXV0YXRlKGdyb3VwID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkX2JlZm9yZSA9PSBFbnRlcm90eXBlc19pZCwgIndpdGhpbiBQYXJ0aXRpb24iLCBpZmVsc2UoYnJhbmNoZXNfYmVmb3JlPT1icmFuY2hlcywgIndpdGhpbiBCcmFuY2hcbmJldHdlZW4gUGFydGl0aW9ucyIsICJiZXR3ZWVuIEJyYW5jaGVzIikgKSkgJT4lDQogICAgDQogICAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLGJyYW5jaGVzX2JlZm9yZSxncm91cCkgJT4lDQogIHN1bW1hcmlzZShwPXN1bShwKSkgJT4lDQogICAgbXV0YXRlKGRhdGFzZXQ9Ik9ic2VydmVkIikNCiAgICApICU+JQ0KICBmaWx0ZXIoZ3JvdXAgIT0gIndpdGhpbiBCcmFuY2hcbmJldHdlZW4gUGFydGl0aW9ucyIpICU+JQ0KICBtdXRhdGUoZ3JvdXAgPSBncm91cCAlPiUgZm9yY2F0czo6ZmN0X3JlbGV2ZWwoIndpdGhpbiBQYXJ0aXRpb24iLCJiZXR3ZWVuIEJyYW5jaGVzIikpICU+JQ0KZ2dwbG90KCkgKyBnZW9tX2JhcihhZXMoeD1wYXN0ZTAoIk0iLEVudGVyb3R5cGVzX2lkX2JlZm9yZSkseT1wLGZpbGw9ZGF0YXNldCksc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgZmFjZXRfZ3JpZChncm91cH5icmFuY2hlc19iZWZvcmUsIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgeGxhYigiR3V0IG1pY3JvYmlvbWUgcGFydGl0aW9ucyIpICsNCiAgeWxhYigiUHJvcG9ydGlvbnMiKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0xLCB2anVzdD0wLjUpKSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpIC0+IGZpZzVNX3N0YWJpbGl0eQ0KICANCiAgDQpmaWc1TV9zdGFiaWxpdHkNCg0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQplbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrDQoNCg0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yayAlPiUNCiAgZHBseXI6OnNsaWNlKDEpICU+JQ0KICBwdWxsKG4pICU+JSBzdW0NCg0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yayAlPiUNCiAgZHBseXI6OnNsaWNlKDI6MjApICU+JQ0KICBwdWxsKG4pICU+JSBzdW0NCg0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yayAlPiUNCiAgcHVsbChuKSAlPiUgc3VtDQoNCg0KICBlbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrICU+JQ0KICAgICN1bmdyb3VwKCkgJT4lDQogICAgZmlsdGVyKHA+MC4wNSkgLT4gZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yaw0KDQogIA0KDQogIA0KICAgDQplbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrICU+JQ0KICBkcGx5cjo6c2xpY2UoMSkgJT4lDQogIHB1bGwobikgJT4lIHN1bQ0KDQplbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrICU+JQ0KICBkcGx5cjo6c2xpY2UoMjoyMCkgJT4lDQogIHB1bGwobikgJT4lIHN1bQ0KDQplbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrICU+JQ0KICBwdWxsKG4pICU+JSBzdW0NCg0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yayAlPiUgd3JpdGUudGFibGUoZmlsZT0iZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yay50eHQiLCBzZXAgPSAiXHQiKSAgDQogIA0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yayAlPiUNCiAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSAlPiUNCiAgc3VtbWFyaXNlKHA9c3VtKHApKSAlPiUgcHVsbChwKSAlPiUgc3VtbWFyeSgpICMgaWYgeW91IHNlbGVjdCB0aGUgdG9wIDIgc3dpdGNoZXMgKyBzdGFiaWxpdHkgKD0+NjYlIGF2ZXJhZ2UpDQoNCg0KDQplbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWRfYmVmb3JlPT1FbnRlcm90eXBlc19pZCkgJT4lDQogIHNlbGVjdChFbnRlcm90eXBlc19pZF9iZWZvcmUscCkgJT4lDQogIGRwbHlyOjpyZW5hbWUoc3RhYmlsaXR5PXAsIEVudGVyb3R5cGVzX2lkPUVudGVyb3R5cGVzX2lkX2JlZm9yZSktPiBlbnRlcm90eXBlc190aW1lX3Nlcmllc19zdGFiaWxpdHkNCg0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfbmV0d29yayAlPiUNCiAgZmlsdGVyKCEoRW50ZXJvdHlwZXNfaWRfYmVmb3JlPT1FbnRlcm90eXBlc19pZCkpICU+JQ0KICBzZWxlY3QoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLEVudGVyb3R5cGVzX2lkLCBwKSAtPiBlbnRlcm90eXBlc190aW1lX3Nlcmllc19zd2l0Y2gNCg0KIyBlbnRlcm90eXBlc190aW1lX3Nlcmllc19uZXR3b3JrICU+JQ0KIyAgIGZpbHRlcighKEVudGVyb3R5cGVzX2lkX2JlZm9yZT09RW50ZXJvdHlwZXNfaWQpKSAlPiUNCiMgICBzZWxlY3QoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLEVudGVyb3R5cGVzX2lkLCBuLCBwKSAlPiUNCiMgICBmaWx0ZXIobj41KSAlPiUgc2VsZWN0KEVudGVyb3R5cGVzX2lkX2JlZm9yZSxFbnRlcm90eXBlc19pZCwgcCkgLT4gZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfc3dpdGNoDQoNCmVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N0YWJpbGl0eSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikpIC0+IGVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N0YWJpbGl0eQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQ0KbGlicmFyeShpZ3JhcGgpDQpsaWJyYXJ5KGdncmFwaCkNCg0KDQojaWdyYXBoOjpncmFwaC5kYXRhLmZyYW1lKGVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N3aXRjaCkNCmdyYXBoIDwtIGlncmFwaDo6Z3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N3aXRjaCkNCg0KVihncmFwaCkNCg0KZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfc3RhYmlsaXR5ID0NCmVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N0YWJpbGl0eSAlPiUgLlttYXRjaChuYW1lcyhWKGdyYXBoKSksIGVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N0YWJpbGl0eSRFbnRlcm90eXBlc19pZCksXQ0KDQpWKGdyYXBoKSRzdGFiaWxpdHkgPC0gZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfc3RhYmlsaXR5JHN0YWJpbGl0eSAgICAgICAgIA0KVihncmFwaCkkYnJhbmNoZXMgPC0gIGVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N0YWJpbGl0eSRicmFuY2hlcyANClYoZ3JhcGgpJHBhcnRpdGlvbl9uYW1lcyA8LSAgIGVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N0YWJpbGl0eSRFbnRlcm90eXBlc19pZA0KICANCmdncmFwaChncmFwaCwgd2VpZ2h0cz1wLCBsYXlvdXQ9InN0cmVzcyIpICsNCiAgZ2VvbV9lZGdlX2ZhbihhZXMoYWxwaGEgPSBwLCBjb2xvcj1wKSwgYXJyb3c9YXJyb3coYW5nbGUgPSAyMCwgbGVuZ3RoID0gdW5pdCg0LCAibW0iKSksIGVuZF9jYXAgPSBjaXJjbGUoMywgJ21tJykpICsgDQogICNzY2FsZV9hbHBoYV9vcmRpbmFsKCJwYXJ0aWNpcGFudHMgcHJvcG9ydGlvbiIpICsNCiAgI2dlb21fbm9kZV9wb2ludChhZXMoY29sb3I9YnJhbmNoZXMsc2l6ZT1zdGFiaWxpdHkqMikpICsNCiAgI2dlb21fbm9kZV9wb2ludChhZXMoY29sb3I9YnJhbmNoZXMsc2l6ZT1zdGFiaWxpdHkpKSArDQogIGdlb21fbm9kZV9sYWJlbChhZXMobGFiZWw9cGFydGl0aW9uX25hbWVzLCBmaWxsPWJyYW5jaGVzICU+JSBnc3ViKCJETU0gdHlwZXMiLCIiLC4pLCBzaXplPXN0YWJpbGl0eSksIHNoYXBlPTE1KSArIA0KICAjZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsPXBhcnRpdGlvbl9uYW1lcyksIHJlcGVsPVRSVUUpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGU9InF1YWwiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKCJETU0gdHlwZXMiLCB0eXBlPSJxdWFsIikgKw0KICBzY2FsZV9hbHBoYV9jb250aW51b3VzKCJwYXJ0aWNpcGFudHMgcHJvcG9ydGlvbiIpICsgDQogIHNjYWxlX2VkZ2VfYWxwaGEoImluZC4gcHJvcG9ydGlvbiAoc3dpdGNoKSIpICsgDQogIHNjYWxlX2VkZ2VfY29sb3JfY29udGludW91cygiaW5kLiBwcm9wb3J0aW9uIChzd2l0Y2gpIiwgbG93ID0gImdyZXkiLCBoaWdoID0icmVkIiwgZ3VpZGUgPSBGQUxTRSkgKw0KICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoImluZC4gcHJvcG9ydGlvbiAoc3RhYmxlKSIsIHRyYW5zPSJsb2cxMCIsIGxpbWl0cyA9IGMoMC4xLDAuOSksIGJyZWFrcyA9IGMoMC4zLDAuNiwwLjkpKSArDQogIHRoZW1lX3ZvaWQoKSAtPiBmaWc1QQ0KICANCmZpZzVBDQoNCmVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N0YWJpbGl0eSAlPiUNCiAgI2ZpbHRlcihicmFuY2hlcz09IkJhY3Rlcm9pZGVzIERNTSB0eXBlcyJ8IEVudGVyb3R5cGVzX2lkICVpbiUgYygxLDUpKSAlPiUNCiAgI211dGF0ZShFbnRlcm90eXBlc19pZD1FbnRlcm90eXBlc19pZCAlPiUgYXMuY2hhcmFjdGVyICU+JSBmYWN0b3IobGV2ZWxzPWMoIjEiLCI1IiwiMiIsIjQiLCIzIiwiOCIsIjEwIiwiNiIsIjE1IiwiMTEiKSkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh4PUVudGVyb3R5cGVzX2lkLCB5PXN0YWJpbGl0eSksIHN0YXQ9ImlkZW50aXR5IikgKw0KICB4bGFiKCJCYWN0ZXJvaWRlcyBicmFuY2ggcGFydGl0aW9uc1xub3JkZXJlZCBieSBQSEFURSBjZW50cm9pZCBwb3NpdGlvbiIpICsNCiAgeWxhYigic3RhYmlsaXR5IikgKw0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkNCiAgDQoNCmBgYA0KDQoNCiMjIyMgdG8gcHV0IG5ldHdvcmsgaW4gQlcNCmBgYHtyfQ0KDQpnZ3JhcGgoZ3JhcGgsIHdlaWdodHM9cCwgbGF5b3V0PSJzdHJlc3MiKSArDQogIGdlb21fZWRnZV9mYW4oYWVzKGFscGhhID0gcCwgY29sb3I9cCksIGFycm93PWFycm93KGFuZ2xlID0gMjAsIGxlbmd0aCA9IHVuaXQoNCwgIm1tIikpLCBlbmRfY2FwID0gY2lyY2xlKDMsICdtbScpKSArIA0KICAjc2NhbGVfYWxwaGFfb3JkaW5hbCgicGFydGljaXBhbnRzIHByb3BvcnRpb24iKSArDQogICNnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG9yPWJyYW5jaGVzLHNpemU9c3RhYmlsaXR5KjIpKSArDQogICNnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG9yPWJyYW5jaGVzLHNpemU9c3RhYmlsaXR5KSkgKw0KICBnZW9tX25vZGVfbGFiZWwoYWVzKGxhYmVsPXBhc3RlMChwYXJ0aXRpb25fbmFtZXMsYnJhbmNoZXMgJT4lIHN0cmluZ3I6OnN0cl9zdWIoc3RhcnQ9MSwgZW5kPTEpKSwgDQogICAgICAgICAgICAgICAgICAgICAgZmlsbD1wYXN0ZTAoYnJhbmNoZXMgJT4lIGdzdWIoIkRNTSB0eXBlcyIsIiIsLiksIiAoIixicmFuY2hlcyAlPiUgc3RyaW5ncjo6c3RyX3N1YihzdGFydD0xLCBlbmQ9MSksIikiKSwgc2l6ZT1zdGFiaWxpdHkpKSArIA0KICAjZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsPXBhcnRpdGlvbl9uYW1lcyksIHJlcGVsPVRSVUUpICsNCiAgI3NjYWxlX2NvbG9yX2dyZXkoKSArDQogIHNjYWxlX2ZpbGxfZ3JleSgibWFpbiB0YXhhIERNTSBwYXJ0aXRpb25zIikgKw0KICBzY2FsZV9hbHBoYV9jb250aW51b3VzKCJwYXJ0aWNpcGFudHMgcHJvcG9ydGlvbiIpICsgDQogIHNjYWxlX2VkZ2VfYWxwaGEoImluZC4gcHJvcG9ydGlvbiAoc3dpdGNoKSIpICsgDQogIHNjYWxlX2VkZ2VfY29sb3JfY29udGludW91cygiaW5kLiBwcm9wb3J0aW9uIChzd2l0Y2gpIiwgbG93ID0gImdyZXkiLCBoaWdoID0iYmxhY2siLCBndWlkZSA9IEZBTFNFKSArDQogIHNjYWxlX3NpemVfY29udGludW91cygiaW5kLiBwcm9wb3J0aW9uIChzdGFibGUpIiwgdHJhbnM9ImxvZzEwIiwgbGltaXRzID0gYygwLjEsMC45KSwgYnJlYWtzID0gYygwLjMsMC42LDAuOSkpICsNCiAgdGhlbWVfdm9pZCgpDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZXRpbWUoKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogIG1lcmdlKHNoYW5ub24sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgZmlsdGVyKG4+MSkgJT4lDQogIA0KICBtdXRhdGUoZGF5cz1DT0xMRUNUSU9OX1RJTUVTVEFNUCAtIG1pbl9kYXRlKSAlPiUgDQogIA0KICANCiAgZmlsdGVyKGRheXMgPT0gMCB8IGRheXMgPiA2MCo2MCoyNCkgJT4lDQogIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUgDQogIA0KDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JQ0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBzZWxlY3QoU0FNUExFX05BTUUsSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBFbnRlcm90eXBlc19pZCwgc2hhbm5vbikgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIgKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShzYW1lX2JyYW5jaGVzX2xhZyA9IGlmZWxzZShicmFuY2hlcyA9PSBsYWcoYnJhbmNoZXMpLCAieWVzIiwibm8iKSwgDQogICAgICAgICBicmFuY2hlc19iZWZvcmU9bGFnKGJyYW5jaGVzKSwgZGF5c19kZWx0YT0gZGF5cyAtIGxhZyhkYXlzKSwgDQogICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgPSBsYWcoRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlciksDQogICAgICAgICBzaGFubm9uX2JlZm9yZSA9IGxhZyhzaGFubm9uKSkgJT4lDQogIGZpbHRlcihzYW1wbGVfb3JkZXIgPjEpICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfcGFpcnM9cGFzdGUwKGJyYW5jaGVzX2JlZm9yZSwiLSIsYnJhbmNoZXMpKSAlPiUNCiAgbXV0YXRlKGRheXNfZGVsdGFfYmlucyA9IGN1dChkYXlzX2RlbHRhLCBicmVha3MgPSBjKC0xLDYwKjYwKjI0KjcsMTIwKjI0KjYwKjYwLDM2NSo2MCo2MCoyNCwxMDAwMCo2MCo2MCoyNCkpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLngsRW50ZXJvdHlwZXNfaWRfYmVmb3JlLHZhbHVlKSAlPiUNCiAgbXV0YXRlKHN0YWJpbGl0eT1pZmVsc2UoRW50ZXJvdHlwZXNfaWQueD09RW50ZXJvdHlwZXNfaWRfYmVmb3JlLCAic3RhYmxlIiwidW5zdGFibGUiKSkgJT4lDQogICN3aXRoKC4sd2lsY294LnRlc3QoZGF0YT0uLCB2YWx1ZX5zdGFiaWxpdHkpKQ0KICAjZ2dwbG90KCkgKyBnZ2ZvcmNlOjpnZW9tX3NpbmEoYWVzKHg9c3RhYmlsaXR5LHk9dmFsdWUpKSAjKyBmYWNldF93cmFwKH5FbnRlcm90eXBlc19pZF9iZWZvcmUpDQogIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKHg9c3RhYmlsaXR5LGZpbGw9dmFsdWU+MC44KSwgcG9zaXRpb249ImZpbGwiKSAjKyBmYWNldF93cmFwKH5FbnRlcm90eXBlc19pZC54KQ0KICAjZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHkoYWVzKHg9dmFsdWUsIGZpbGw9c3RhYmlsaXR5KSwgYWxwaGE9MC41KQ0KDQoNCmBgYA0KDQoNCg0KDQojIyBtYWluIHN3aXRjaGVzIGFuZCBrZXlzdG9uZSBzcGVjaWVzDQoNCm1haW4gc3dpdGNoZXMgb2NjdXJyZWQgYmV0d2VlbiAjNiBhbmQgIzIsICMzIGFuZCAjNQ0KDQojIyMgTTYgTTINCmBgYHtyfQ0KI2NvbXB1dGUgZnByYXUvYmFjdGVyb2lkZXMgcmF0aW8gYW5kIG1lcmdlDQoNCmZfR0cgPSAia19fQmFjdGVyaWE7cF9fRmlybWljdXRlcztjX19DbG9zdHJpZGlhO29fX0Nsb3N0cmlkaWFsZXM7Zl9fUnVtaW5vY29jY2FjZWFlO2dfX0ZhZWNhbGliYWN0ZXJpdW0iDQpiX0dHID0gImtfX0JhY3RlcmlhO3BfX0JhY3Rlcm9pZGV0ZXM7Y19fQmFjdGVyb2lkaWE7b19fQmFjdGVyb2lkYWxlcztmX19CYWN0ZXJvaWRhY2VhZTtnX19CYWN0ZXJvaWRlcyINCg0KZ2VudXMgJT4lDQogIGZpbHRlcih0YXhhICVpbiUgYyhmX0dHLGJfR0cpKSAlPiUNCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoInRheGEiKSAlPiUNCiAgdCAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICBkcGx5cjo6cmVuYW1lKEZlYWNhbGliYWN0ZXJpdW09MixCYWN0ZXJvaWRlcz0xKSAlPiUNCiAgbXV0YXRlKHJhdGlvPUZlYWNhbGliYWN0ZXJpdW0vQmFjdGVyb2lkZXMpIC0+IGZfYl9yYXRpbw0KDQojIG1ldGFkYXRhICU+JQ0KIyAgIGZpbHRlcihTQU1QTEVfVFlQRSA9PSAiU3Rvb2wiKSAlPiUNCiMgICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQojICAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZXRpbWUoKSkgJT4lDQojICAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiMgICBtZXJnZShzaGFubm9uLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KIyAgIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQojICAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICE9IDE5KSAlPiUNCiMgICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KIyAgIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiMgICBmaWx0ZXIobj4xKSAlPiUNCiMgICANCiMgICBtdXRhdGUoZGF5cz1DT0xMRUNUSU9OX1RJTUVTVEFNUCAtIG1pbl9kYXRlKSAlPiUgDQojICAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiMgICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQojICAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JQ0KIyAgIGZpbHRlcihFbnRlcm90eXBlc19pZCAlaW4lIGMoMiw2KSkgJT4lDQojICAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9ZGF5cyx5PXNoYW5ub24sZ3JvdXA9SE9TVF9TVUJKRUNUX0lELCBjb2w9YXMuY2hhcmFjdGVyKEVudGVyb3R5cGVzX2lkKSkpIA0KICANCg0KbWV0YWRhdGEgJT4lDQogIGZpbHRlcihTQU1QTEVfVFlQRSA9PSAiU3Rvb2wiKSAlPiUNCiAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KICANCiAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZXRpbWUoKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogIG1lcmdlKHNoYW5ub24sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIG1lcmdlKGZfYl9yYXRpbywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICE9IDE5KSAlPiUNCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiAgDQogIA0KICBmaWx0ZXIoZGF5cyA9PSAwIHwgZGF5cyA+IDYwKjYwKjI0KSAlPiUNCiAgDQogIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUgDQogIA0KDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JQ0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBzZWxlY3QoU0FNUExFX05BTUUsIEhPU1RfU1VCSkVDVF9JRCwgZGF5cywgc2FtcGxlX29yZGVyLCBicmFuY2hlcywgRW50ZXJvdHlwZXNfaWQsIHNoYW5ub24sIHJhdGlvKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlciApICU+JSANCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKHNhbWVfYnJhbmNoZXNfbGFnID0gaWZlbHNlKGJyYW5jaGVzID09IGxhZyhicmFuY2hlcyksICJ5ZXMiLCJubyIpLCANCiAgICAgICAgIGJyYW5jaGVzX2JlZm9yZT1sYWcoYnJhbmNoZXMpLCBkYXlzX2RlbHRhPSBkYXlzIC0gbGFnKGRheXMpLCANCiAgICAgICAgIEVudGVyb3R5cGVzX2lkX2JlZm9yZSA9IGxhZyhFbnRlcm90eXBlc19pZCAlPiUgYXMuY2hhcmFjdGVyKSwNCiAgICAgICAgIHNoYW5ub25fYmVmb3JlID0gbGFnKHNoYW5ub24pLA0KICAgICAgICAgcmF0aW9fYmVmb3JlID0gbGFnKHJhdGlvKSkgJT4lDQogIGZpbHRlcihzYW1wbGVfb3JkZXIgPjEpICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfcGFpcnM9cGFzdGUwKGJyYW5jaGVzX2JlZm9yZSwiLSIsYnJhbmNoZXMpKSAlPiUNCiAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICVpbiUgYygyLDYpLCBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDIsNikpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLHJhdGlvLCBFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHJhdGlvX2JlZm9yZSkgJT4lDQogIG11dGF0ZShzd2l0Y2g9cGFzdGUoRW50ZXJvdHlwZXNfaWQsRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSkgLT4gZGYNCg0KZGYgJT4lDQogIG11dGF0ZShkZWx0YV9yYXRpbyA9IGFicyhsb2cyKHJhdGlvX2JlZm9yZSkgLSBsb2cyKHJhdGlvKSkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYm94cGxvdChhZXMoeD1zd2l0Y2gseT1kZWx0YV9yYXRpbykpICsgDQogIHlsYWIoIkZhZWNhbGliYWN0ZXJpdW0vQmFjdGVyb2lkZXNcbnJhdGlvIHZhcmlhdGlvbiIpICsgDQogIHhsYWIoIiIpICsgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsgDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWw9Yygid2l0aGluXG5wYXJ0aXRpb24gTTIiLCJiZXR3ZWVuXG5mcm9tIE0yIHRvIE02IiwiYmV0d2VlblxuZnJvbSBNNiB0byBNMiIsIndpdGhpblxucGFydGl0aW9uIE02IikpIC0+IGZpZzVCDQoNCmZpZzVCDQoNCmRmICU+JQ0KICBtdXRhdGUoZGVsdGFfcmF0aW8gPSBhYnMobG9nMihyYXRpb19iZWZvcmUpIC0gbG9nMihyYXRpbykpKSAlPiUNCiAgd2l0aCguLHBhaXJ3aXNlLndpbGNveC50ZXN0KGRlbHRhX3JhdGlvLHN3aXRjaCwgZGF0YT0uKSkNCg0KDQpyYmluZChkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCwgcmF0aW8pICwNCiAgICAgIGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub25fYmVmb3JlLCBzd2l0Y2gsIHJhdGlvX2JlZm9yZSkgJT4lIGRwbHlyOjpyZW5hbWUoRW50ZXJvdHlwZXNfaWQ9RW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub249c2hhbm5vbl9iZWZvcmUsIHJhdGlvPXJhdGlvX2JlZm9yZSkpICU+JSANCiAgICAgICAgbXV0YXRlKFNBTVBMRV9OQU1FID0gU0FNUExFX05BTUUgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMiAyIiwiNiA2IiksICJzdGFibGUiLCJ1bnN0YWJsZSIpICApICU+JQ0KICBtdXRhdGUoc3RhcnRfcGFydGl0aW9uID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjIgMiIsIjIgNiIpLCAiTTIiLCJNNiIpICApICU+JQ0KICAjYXJyYW5nZShzd2l0Y2gpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD1yYXRpbyx5PVNBTVBMRV9OQU1FLCBncm91cD1TQU1QTEVfTkFNRSwgY29sPXN0YWJsZSkpICArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikgKyANCiAgI2ZhY2V0X3dyYXAofnN3aXRjaCwgbmNvbD0xLCBzY2FsZT0iZnJlZV95IikgKw0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICB5bGFiKCJBR1AgcGFydGljaXBhbnRzIikgKyB4bGFiKCJGYWVjYWxpYmFjdGVyaXVtL1xuQmFjdGVyb2lkZXMgcmF0aW8iKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgiIiwgdmFsdWVzPWMoImJsYWNrIiwicmVkIiksIGxhYmVsPWMoInN0YWJsZSIsInVuc3RhYmxlIikpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgZmFjZXRfZ3JpZChzdGFydF9wYXJ0aXRpb25+Liwgc2NhbGVzID0gImZyZWVfeSIpDQoNCg0KcmJpbmQoZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gsIHJhdGlvKSAsDQogICAgICBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uX2JlZm9yZSwgc3dpdGNoLCByYXRpb19iZWZvcmUpICU+JSBkcGx5cjo6cmVuYW1lKEVudGVyb3R5cGVzX2lkPUVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uPXNoYW5ub25fYmVmb3JlLCByYXRpbz1yYXRpb19iZWZvcmUpKSAlPiUgDQogICAgICAgIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihzaGFubm9uKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMiAyIiwiNiA2IiksICJzdGFibGUiLCJ1bnN0YWJsZSIpICApICU+JQ0KICAjZmlsdGVyKHN0YWJsZSA9PSAic3RhYmxlIikgJT4lDQogIGdncGxvdCgpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9cmF0aW8seT1zaGFubm9uLGNvbD1zd2l0Y2gpKSsgDQogIGdlb21fbGluZShhZXMoeD1yYXRpbyx5PXNoYW5ub24sZ3JvdXA9U0FNUExFX05BTUUgLGNvbD1zd2l0Y2gpKSArDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikgKyBmYWNldF93cmFwKH5zdGFibGUpIC0+IGZpZzVKX2VsbGlzcHNlDQoNCmZpZzVKX2VsbGlzcHNlDQoNCg0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBtZXJnZShmX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihFbnRlcm90eXBlc19pZCU+JWFzLm51bWVyaWMpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8sIGZpbGw9c3dpdGNoKSwgYWxwaGE9MC41KSAgKyB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMiIpDQoNCmRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgbWVyZ2UoZl9iX3JhdGlvLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoRW50ZXJvdHlwZXNfaWQlPiVhcy5udW1lcmljKSkgJT4lDQogIGdncGxvdCgpICsgDQogICNnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8pLCBhbHBoYT0wLjUpICArIA0KICBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8sIGNvbG9yPXN3aXRjaCksIGFscGhhPTAuNSkgICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikNCg0KIyBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQojICAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjIgMiIsICIyIDYiKSkgJT4lDQojICAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiMgICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KIyAgIGdncGxvdCgpICsgZ2VvbV9ib3hwbG90KGFlcyh4PXN3aXRjaCwgeT12YWx1ZSkpICsgZmFjZXRfd3JhcCh+dmFyaWFibGUsIHNjYWxlPSJmcmVlIikNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIyIDIiLCAiMiA2IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIHRpZHlyOjpuZXN0KCkgICU+JSANCiAgbXV0YXRlKHdpbGNveF90ZXN0PXB1cnJyOjptYXAoZGF0YSx+d2lsY294LnRlc3QoLngkdmFsdWV+Lngkc3dpdGNoKSksDQogICAgICAgIHRpZHk9cHVycnI6Om1hcCh3aWxjb3hfdGVzdCwgYnJvb206OnRpZHkpKSAlPiUgDQogICAgICB0aWR5cjo6dW5uZXN0KHRpZHksLmRyb3A9VFJVRSkgJT4lDQogIGFycmFuZ2UocC52YWx1ZSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgI211dGF0ZShwLnZhbHVlPXAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIikpICU+JQ0KICBmaWx0ZXIocC52YWx1ZTwwLjA1KSAlPiUgc2VsZWN0KHZhcmlhYmxlLHAudmFsdWUpICU+JSB3cml0ZS5jc3YyKGZpbGU9Im1ldGFkYXRhX2xpbmtfMjJ2czI2LmNzdiIpDQoNCg0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBmaWx0ZXIoc3dpdGNoICVpbiUgYygiNiA2IiwgIjYgMiIpKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQ9YygiU0FNUExFX05BTUUiLCJFbnRlcm90eXBlc19pZCIsInN3aXRjaCIpKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICB0aWR5cjo6bmVzdCgpICAlPiUgDQogIG11dGF0ZSh3aWxjb3hfdGVzdD1wdXJycjo6bWFwKGRhdGEsfndpbGNveC50ZXN0KC54JHZhbHVlfi54JHN3aXRjaCkpLA0KICAgICAgICB0aWR5PXB1cnJyOjptYXAod2lsY294X3Rlc3QsIGJyb29tOjp0aWR5KSkgJT4lIA0KICAgICAgdGlkeXI6OnVubmVzdCh0aWR5LC5kcm9wPVRSVUUpICU+JQ0KICBhcnJhbmdlKHAudmFsdWUpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogICNtdXRhdGUocC52YWx1ZT1wLmFkanVzdChwLnZhbHVlLCBtZXRob2Q9ImZkciIpKSU+JQ0KICBmaWx0ZXIocC52YWx1ZTwwLjA1KSAlPiUgc2VsZWN0KHZhcmlhYmxlLHAudmFsdWUpICU+JSB3cml0ZS5jc3YyKGZpbGU9Im1ldGFkYXRhX2xpbmtfNjZ2czYyLmNzdiIpDQoNCg0KZGYgJT4lDQogIG11dGF0ZShkZWx0YV9yYXRpbyA9IGFicyhsb2cyKHJhdGlvX2JlZm9yZSkgLSBsb2cyKHJhdGlvKSkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHg9bG9nMihyYXRpb19iZWZvcmUpIC0gbG9nMihyYXRpbykseT1sb2cyKHNoYW5ub25fYmVmb3JlL3NoYW5ub24pLCBjb2xvcj1zd2l0Y2gpKSArDQogIHhsaW0oLTQsNCkgKyB5bGltKC0wLjUsIDAuNSkgKyBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKyBzY2FsZV9jb2xvcl9icmV3ZXIoIiIsIHR5cGU9InF1YWwiLCBwYWxldHRlID0gMikgKw0KICB4bGFiKCJGZWFjYWxpYmFjdGVyaXVtL0JhY3Rlcm9pZGVzIHZhcmlhdGlvbiIpICsgeWxhYigiYWxwaGEtZGl2ZXJzaXR5IHZhcmlhdGlvbiIpIC0+IGZpZ1MxMEENCg0KDQoNCg0KcmJpbmQoZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gsIHJhdGlvKSAsDQogICAgICBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uX2JlZm9yZSwgc3dpdGNoLCByYXRpb19iZWZvcmUpICU+JSBkcGx5cjo6cmVuYW1lKEVudGVyb3R5cGVzX2lkPUVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uPXNoYW5ub25fYmVmb3JlLCByYXRpbz1yYXRpb19iZWZvcmUpKSAlPiUgDQogICAgICAgIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihyYXRpbykpICU+JQ0KICBtdXRhdGUoc3RhYmxlID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjIgMiIsIjYgNiIpLCAic3RhYmxlIiwidW5zdGFibGUiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCIyIDIiLCIyIDYiKSwgIk0yIiwiTTYiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IHN0YXJ0X3BhcnRpdGlvbiAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8sIC5kZXNjPVRSVUUpKSAlPiUNCiAgI2FycmFuZ2Uoc3dpdGNoKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9cmF0aW8seT1TQU1QTEVfTkFNRSwgZ3JvdXA9U0FNUExFX05BTUUsIGNvbD1zdGFibGUpKSAgKyB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMiIpICsgDQogICNmYWNldF93cmFwKH5zd2l0Y2gsIG5jb2w9MSwgc2NhbGU9ImZyZWVfeSIpICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgeWxhYigiQUdQIHBhcnRpY2lwYW50cyIpICsgeGxhYigiRmFlY2FsaWJhY3Rlcml1bS9cbkJhY3Rlcm9pZGVzIHJhdGlvIikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwoIiIsIHZhbHVlcz1jKCJibGFjayIsInJlZCIpLCBsYWJlbD1jKCJzdGFibGUiLCJ1bnN0YWJsZSIpKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIGZhY2V0X2dyaWQoc3RhcnRfcGFydGl0aW9ufi4sIHNjYWxlcyA9ICJmcmVlX3kiKSAtPiBmaWc1Ql9mdWxsDQoNCg0KZGYgJT4lDQogIG11dGF0ZShkZWx0YV9yYXRpbyA9IGFicyhsb2cyKHJhdGlvX2JlZm9yZSkgLSBsb2cyKHJhdGlvKSkpICU+JQ0KICBtdXRhdGUoc3RhYmxlID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjIgMiIsIjYgNiIpLCAic3RhYmxlIiwidW5zdGFibGUiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCIyIDIiLCIyIDYiKSwgIk0yIiwiTTYiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IHN0YXJ0X3BhcnRpdGlvbiAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8sIC5kZXNjPVRSVUUpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QoYWVzKHg9c3RhcnRfcGFydGl0aW9uLHk9ZGVsdGFfcmF0aW8sIGNvbD1zdGFibGUpKSArIA0KICB5bGFiKCJGYWVjYWxpYmFjdGVyaXVtL0JhY3Rlcm9pZGVzXG5yYXRpbyB2YXJpYXRpb24iKSArIA0KICAjc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSJsb2cyIikgKw0KICB4bGFiKCIiKSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArIHNjYWxlX2NvbG9yX21hbnVhbCgiIix2YWx1ZXM9YygiYmxhY2siLCJyZWQiKSkgLT4gZmlnNUJpbnNldA0KDQoNCmZpZzVCID0gZmlnNUJfZnVsbCArIGluc2V0X2VsZW1lbnQoZmlnNUJpbnNldCt5bGFiKCJ2YXJpYXRpb24iKStndWlkZXMoY29sb3I9RkFMU0UpLCAwLjY1LC0wLjEsMSwwLjMsIGlnbm9yZV90YWcgPSBUUlVFKQ0KDQpmaWc1Qg0KDQpgYGANCg0KYGBge3J9DQoNCnJiaW5kKGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoLCByYXRpbykgLA0KICAgICAgZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHN3aXRjaCwgcmF0aW9fYmVmb3JlKSAlPiUgZHBseXI6OnJlbmFtZShFbnRlcm90eXBlc19pZD1FbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbj1zaGFubm9uX2JlZm9yZSwgcmF0aW89cmF0aW9fYmVmb3JlKSkgJT4lIA0KICAgICAgICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8pKSAlPiUNCiAgbXV0YXRlKHN0YWJsZSA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCIyIDIiLCI2IDYiKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMiAyIiwiMiA2IiksICJNMiIsIk02IikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBzdGFydF9wYXJ0aXRpb24gJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvLCAuZGVzYz1UUlVFKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogICN3aXRoKC4sd2lsY294LnRlc3QoZGF0YT0uLCB2YWx1ZX5zdGFibGUpKQ0KICBnZ3Bsb3QoKSArIGdnZm9yY2U6Omdlb21fc2luYQkoYWVzKHg9c3RhYmxlLHk9dmFsdWUsY29sb3I9RW50ZXJvdHlwZXNfaWQueCkpDQoNCg0KcmJpbmQoZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gsIHJhdGlvKSAsDQogICAgICBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uX2JlZm9yZSwgc3dpdGNoLCByYXRpb19iZWZvcmUpICU+JSBkcGx5cjo6cmVuYW1lKEVudGVyb3R5cGVzX2lkPUVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uPXNoYW5ub25fYmVmb3JlLCByYXRpbz1yYXRpb19iZWZvcmUpKSAlPiUgDQogICAgICAgIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihyYXRpbykpICU+JQ0KICBtdXRhdGUoc3RhYmxlID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjIgMiIsIjYgNiIpLCAic3RhYmxlIiwidW5zdGFibGUiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCIyIDIiLCIyIDYiKSwgIk0yIiwiTTYiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IHN0YXJ0X3BhcnRpdGlvbiAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8sIC5kZXNjPVRSVUUpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZ3JvdXBfYnkoc3dpdGNoKSAlPiUNCiAgc3VtbWFyaXNlKHEwNSA9IHF1YW50aWxlKHJhdGlvLCAwLjA1KSwgDQogICAgICAgICAgICBxMjUgPSBxdWFudGlsZShyYXRpbywgMC4yNSksIA0KICAgICAgICAgICAgcTUwPW1lZGlhbihyYXRpbyksIA0KICAgICAgICAgICAgcTc1ID0gcXVhbnRpbGUocmF0aW8sIDAuNzUpLA0KICAgICAgICAgICAgcTk1ID0gcXVhbnRpbGUocmF0aW8sIDAuOTUpKQ0KDQoNCmBgYA0KDQoNCiMjIyBwY2EgYW5hbHlzaXMNCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQoNCmxpYnJhcnkoYWRlNCkNCg0KY2JpbmQoZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICAjZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjIgMiIsICIyIDYiLCAiNiA2IiwgIjYgMiIpKSAlPiUNCiAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjIgMiIsICI2IDYiKSkgJT4lDQogIG1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYyksIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIHNlbGVjdCgxOjQpLA0KDQoNCmRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgI2ZpbHRlcihzd2l0Y2ggJWluJSBjKCIyIDIiLCAiMiA2IiwgIjYgNiIsICI2IDIiKSkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIyIDIiLCAiNiA2IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBzZWxlY3QoLTEsLTIsLTMsLTQpICU+JQ0KICBhZGU0OjpkdWRpLnBjYShzY2FubmYgPSBGQUxTRSwgbmY9MikgJT4lDQogIC4kbGkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHg9QXhpczEsIHk9QXhpczIsIGNvbD1zd2l0Y2gpKQ0KDQoNCg0KDQoNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIyIDIiLCAiMiA2IiwgIjYgNiIsICI2IDIiKSkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIyIDIiLCAiNiA2IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBzZWxlY3QoLTEsLTIsLTMsLTQpIC0+IGRmX3BjYV9wcmVwDQogIA0KYWRlNDo6ZHVkaS5wY2EoZGZfcGNhX3ByZXAsIHNjYW5uZiA9IEZBTFNFLCBuZj0yKSAtPiBwY2FfMl82DQoNCg0KZGYgJT4lIA0KICBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUgDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIyIDIiLCAiMiA2IiwgIjYgNiIsICI2IDIiKSkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIyIDIiLCAiNiA2IikpICU+JQ0KICBwdWxsKHN3aXRjaCkgJT4lIGFzLmZhY3RvcigpIC0+IGRmX2ZhYw0KICBhZGU0OjpiY2EocGNhXzJfNiwgZmFjPWRmX2ZhYywgc2Nhbm5mPUYpICU+JSByYW5kdGVzdCgpDQoNCg0KDQoNCmNiaW5kKGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjIgMiIsICIyIDYiLCAiNiA2IiwgIjYgMiIpKSAlPiUNCiAgI2ZpbHRlcihzd2l0Y2ggJWluJSBjKCIyIDIiLCAiNiA2IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBzZWxlY3QoMTo0KSwNCg0KDQpkZiAlPiUgDQogIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JSANCiAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjIgMiIsICIyIDYiLCAiNiA2IiwgIjYgMiIpKSAlPiUNCiAgcHVsbChzd2l0Y2gpICU+JSBhcy5mYWN0b3IoKSAlPiUNCiAgYWRlNDo6YmNhKHBjYV8yXzYsIGZhYz0uLCBzY2FubmY9RikgJT4lDQogIC4kbHMpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHg9Q1MxLHk9Q1MyLGNvbG9yPXN3aXRjaCkpDQoNCg0KDQoNCg0KDQpgYGANCg0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0NCnJiaW5kKA0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBmaWx0ZXIoc3dpdGNoICVpbiUgYygiMiAyIiwgIjIgNiIpKSAlPiUNCiAgbXV0YXRlKHN3aXRjaD0gc3dpdGNoICU+JSBmYWN0b3IobGV2ZWxzID0gYygiMiAyIiwgIjIgNiIpKSkgJT4lDQogIG1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYyksIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkPWMoIlNBTVBMRV9OQU1FIiwiRW50ZXJvdHlwZXNfaWQiLCJzd2l0Y2giKSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgdGlkeXI6Om5lc3QoKSAgJT4lIA0KICBtdXRhdGUoY29yX3Rlc3Q9cHVycnI6Om1hcChkYXRhLH5jb3IudGVzdCgueCR2YWx1ZSwueCRzd2l0Y2ggJT4lIGFzLmZhY3RvciAlPiUgYXMubnVtZXJpYygpLCBtZXRob2Q9InNwZWFybWFuIikpLA0KICAgICAgICB0aWR5PXB1cnJyOjptYXAoY29yX3Rlc3QsIGJyb29tOjp0aWR5KSkgJT4lIA0KICAgICAgdGlkeXI6OnVubmVzdCh0aWR5LC5kcm9wPVRSVUUpICU+JQ0KICBhcnJhbmdlKHAudmFsdWUpICU+JQ0KICBtdXRhdGUoc3dpdGNoPWMoIjItPjYiKSkgJT4lDQogIHNlbGVjdCh2YXJpYWJsZSxlc3RpbWF0ZSxwLnZhbHVlLHN3aXRjaCkgJT4lIG11dGF0ZShxLnZhbHVlPXAuYWRqdXN0KHAudmFsdWUsImZkciIpKSwNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCI2IDYiLCAiNiAyIikpICU+JSANCiAgbXV0YXRlKHN3aXRjaD0gc3dpdGNoICU+JSBmYWN0b3IobGV2ZWxzID0gYygiNiA2IiwgIjYgMiIpKSkgJT4lDQogIG1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYyksIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkPWMoIlNBTVBMRV9OQU1FIiwiRW50ZXJvdHlwZXNfaWQiLCJzd2l0Y2giKSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgdGlkeXI6Om5lc3QoKSAgJT4lIA0KICBtdXRhdGUoY29yX3Rlc3Q9cHVycnI6Om1hcChkYXRhLH5jb3IudGVzdCgueCR2YWx1ZSwueCRzd2l0Y2ggJT4lIGFzLmZhY3RvciAlPiUgYXMubnVtZXJpYygpLCBtZXRob2Q9InNwZWFybWFuIikpLA0KICAgICAgICB0aWR5PXB1cnJyOjptYXAoY29yX3Rlc3QsIGJyb29tOjp0aWR5KSkgJT4lIA0KICAgICAgdGlkeXI6OnVubmVzdCh0aWR5LC5kcm9wPVRSVUUpICU+JQ0KICBhcnJhbmdlKHAudmFsdWUpICU+JQ0KICBtdXRhdGUoc3dpdGNoPWMoIjYtPjIiKSkgJT4lDQogIHNlbGVjdCh2YXJpYWJsZSxlc3RpbWF0ZSxwLnZhbHVlLHN3aXRjaCkgJT4lIG11dGF0ZShxLnZhbHVlPXAuYWRqdXN0KHAudmFsdWUsImZkciIpKSkgJT4lDQogIA0KICBmaWx0ZXIocS52YWx1ZTwwLjA1KSAlPiUNCiAgDQpnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh4PXZhcmlhYmxlLHk9ZXN0aW1hdGUsZmlsbD1zd2l0Y2gpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArIGNvb3JkX2ZsaXAoKSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSAtPiBmaWc1RA0KICANCg0KDQpkZiAlPiUNCiAgbXV0YXRlKGRlbHRhX3JhdGlvID0gYWJzKGxvZzIocmF0aW9fYmVmb3JlKSAtIGxvZzIocmF0aW8pKSkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCwgc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQ9YygiU0FNUExFX05BTUUiLCJFbnRlcm90eXBlc19pZCIsInN3aXRjaCIsInNoYW5ub24iLCJzaGFubm9uX2JlZm9yZSIsInJhdGlvIiwicmF0aW9fYmVmb3JlIikpIA0KDQoNCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJldCkNCnNldC5zZWVkKDY2NikNCnRyYWluLmNvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJyZXBlYXRlZGN2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5RnVuY3Rpb249dHdvQ2xhc3NTdW1tYXJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyID0gMTAsIHJlcGVhdHMgPSA1LCBjbGFzc1Byb2JzPVQsIHNhdmVQcmVkaWN0aW9ucyA9IFQpDQoNCmRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjIgMiIsICIyIDYiKSkgJT4lDQogIG1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYyksIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lIHNlbGVjdCgtU0FNUExFX05BTUUsLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlKHN3aXRjaCA9IHBhc3RlMCgicCIsc3dpdGNoKSAlPiUgZ3N1YigiXFwgIiwiIiwuKSAlPiUgYXMuZmFjdG9yKSAgIC0+IGRmXzIyXzI2DQogIA0KDQojIFRyYWluIHRoZSBtb2RlbA0Kc3VwcHJlc3NXYXJuaW5ncyhtb2RlbCA8LSB0cmFpbihzd2l0Y2ggfi4sIGRhdGEgPSBkZl8yMl8yNiwgbWV0aG9kID0gInJmIiwNCiAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluLmNvbnRyb2wpKQ0KIyBTdW1tYXJpemUgdGhlIHJlc3VsdHMNCnByaW50KG1vZGVsKQ0KDQoNCmxpYnJhcnkocFJPQykNCiMgU2VsZWN0IGEgcGFyYW1ldGVyIHNldHRpbmcNCnNlbGVjdGVkSW5kaWNlcyA8LSBtb2RlbCRwcmVkJG10cnkgPT0gMg0KI3NlbGVjdGVkSW5kaWNlcyA8LSBtb2RlbCRwcmVkJG5jb21wID09IDENCiMgUGxvdDoNCnBsb3Qucm9jKG1vZGVsJHByZWQkb2JzW3NlbGVjdGVkSW5kaWNlc10sDQogICAgICAgICBtb2RlbCRwcmVkJHAyNltzZWxlY3RlZEluZGljZXNdKQ0KYGBgDQoNCg0KDQoNCg0KIyMjIE01IE0zDQoNCmBgYHtyfQ0KbWV0YWRhdGEgJT4lDQogIGZpbHRlcihTQU1QTEVfVFlQRSA9PSAiU3Rvb2wiKSAlPiUNCiAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KICANCiAgbXV0YXRlKENPTExFQ1RJT05fVElNRVNUQU1QID0gQ09MTEVDVElPTl9USU1FU1RBTVAgJT4lIGx1YnJpZGF0ZTo6YXNfZGF0ZXRpbWUoKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogIG1lcmdlKHNoYW5ub24sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIG1lcmdlKGZfYl9yYXRpbywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICE9IDE5KSAlPiUNCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiAgDQogIGZpbHRlcihkYXlzID09IDAgfCBkYXlzID4gNjAqNjAqMjQpICU+JQ0KICANCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQsIGRheXMpICU+JQ0KICBtdXRhdGUoc2FtcGxlX29yZGVyPW9yZGVyKENPTExFQ1RJT05fVElNRVNUQU1QKSkgJT4lIA0KICANCg0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzXzA9YnJhbmNoZXNbd2hpY2gubWluKHNhbXBsZV9vcmRlcildKSAlPiUNCiAgI2FycmFuZ2UoSE9TVF9TVUJKRUNUX0lEKSAgJT4lIA0KICAjbXV0YXRlKHNhbXBsZV9vcmRlcj1yYW5rKGRheXMpKSAlPiUNCiAgbXV0YXRlKGRheXMgPSBhcy5udW1lcmljKGRheXMpKSAlPiUNCiAgc2VsZWN0KFNBTVBMRV9OQU1FLCBIT1NUX1NVQkpFQ1RfSUQsIGRheXMsIHNhbXBsZV9vcmRlciwgYnJhbmNoZXMsIEVudGVyb3R5cGVzX2lkLCBzaGFubm9uLCByYXRpbykgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIgKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShzYW1lX2JyYW5jaGVzX2xhZyA9IGlmZWxzZShicmFuY2hlcyA9PSBsYWcoYnJhbmNoZXMpLCAieWVzIiwibm8iKSwgDQogICAgICAgICBicmFuY2hlc19iZWZvcmU9bGFnKGJyYW5jaGVzKSwgZGF5c19kZWx0YT0gZGF5cyAtIGxhZyhkYXlzKSwgDQogICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgPSBsYWcoRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlciksDQogICAgICAgICBzaGFubm9uX2JlZm9yZSA9IGxhZyhzaGFubm9uKSwNCiAgICAgICAgIHJhdGlvX2JlZm9yZSA9IGxhZyhyYXRpbykpICU+JQ0KICBmaWx0ZXIoc2FtcGxlX29yZGVyID4xKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzX3BhaXJzPXBhc3RlMChicmFuY2hlc19iZWZvcmUsIi0iLGJyYW5jaGVzKSkgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAlaW4lIGMoMyw1KSwgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygzLDUpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbixyYXRpbywgRW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub25fYmVmb3JlLCByYXRpb19iZWZvcmUpICU+JQ0KICBtdXRhdGUoc3dpdGNoPXBhc3RlKEVudGVyb3R5cGVzX2lkLEVudGVyb3R5cGVzX2lkX2JlZm9yZSkpIC0+IGRmDQoNCmRmICU+JQ0KICBtdXRhdGUoZGVsdGFfcmF0aW8gPSBhYnMobG9nMihyYXRpb19iZWZvcmUpIC0gbG9nMihyYXRpbykpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QoYWVzKHg9c3dpdGNoLHk9ZGVsdGFfcmF0aW8pKSArIA0KICB5bGFiKCJGYWVjYWxpYmFjdGVyaXVtL0JhY3Rlcm9pZGVzXG5yYXRpbyB2YXJpYXRpb24iKSArIA0KICB4bGFiKCIiKSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArIA0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsPWMoIndpdGhpblxucGFydGl0aW9uIE0zIiwiYmV0d2VlblxuZnJvbSBNMyB0byBNNSIsImJldHdlZW5cbmZyb20gTTUgdG8gTTMiLCJ3aXRoaW5cbnBhcnRpdGlvbiBNNSIpKSAtPiBmaWc1Qw0KDQpmaWc1Qw0KDQoNCg0KZGYgJT4lDQogIG11dGF0ZShkZWx0YV9yYXRpbyA9IGFicyhsb2cyKHJhdGlvX2JlZm9yZSkgLSBsb2cyKHJhdGlvKSkpICU+JQ0KICB3aXRoKC4scGFpcndpc2Uud2lsY294LnRlc3QoZGVsdGFfcmF0aW8sc3dpdGNoLCBkYXRhPS4pKQ0KDQoNCnJiaW5kKGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoLCByYXRpbykgLA0KICAgICAgZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHN3aXRjaCwgcmF0aW9fYmVmb3JlKSAlPiUgZHBseXI6OnJlbmFtZShFbnRlcm90eXBlc19pZD1FbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbj1zaGFubm9uX2JlZm9yZSwgcmF0aW89cmF0aW9fYmVmb3JlKSkgJT4lIA0KICAgICAgICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8pKSAlPiUNCiAgYXJyYW5nZShzd2l0Y2gpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD1yYXRpbyx5PVNBTVBMRV9OQU1FLCBncm91cD1TQU1QTEVfTkFNRSwgY29sPXN3aXRjaCkpICArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikgKyBmYWNldF93cmFwKH5zd2l0Y2gsIG5jb2w9MSwgc2NhbGU9ImZyZWVfeSIpIA0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIG1lcmdlKGZfYl9yYXRpbywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgbXV0YXRlKFNBTVBMRV9OQU1FID0gU0FNUExFX05BTUUgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKEVudGVyb3R5cGVzX2lkJT4lYXMubnVtZXJpYykpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fZGVuc2l0eShhZXMoeD1yYXRpbywgZmlsbD1zd2l0Y2gpLCBhbHBoYT0wLjUpICArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikNCg0KDQoNCnJiaW5kKGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoLCByYXRpbykgLA0KICAgICAgZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHN3aXRjaCwgcmF0aW9fYmVmb3JlKSAlPiUgZHBseXI6OnJlbmFtZShFbnRlcm90eXBlc19pZD1FbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbj1zaGFubm9uX2JlZm9yZSwgcmF0aW89cmF0aW9fYmVmb3JlKSkgJT4lIA0KICAgICAgICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoc2hhbm5vbikpICU+JQ0KICBtdXRhdGUoc3RhYmxlID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjMgMyIsIjUgNSIpLCAic3RhYmxlIiwidW5zdGFibGUiKSAgKSAlPiUNCiAgI2ZpbHRlcihzdGFibGUgPT0gInN0YWJsZSIpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX3BvaW50KGFlcyh4PXJhdGlvLHk9c2hhbm5vbixjb2w9c3dpdGNoKSkrIA0KICBnZW9tX2xpbmUoYWVzKHg9cmF0aW8seT1zaGFubm9uLGdyb3VwPVNBTVBMRV9OQU1FICxjb2w9c3dpdGNoKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMiIpICsgZmFjZXRfd3JhcCh+c3RhYmxlKSAtPiBmaWc1S19lbGxpc3BzZQ0KDQpmaWc1S19lbGxpc3BzZQ0KDQoNCg0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBmaWx0ZXIoc3dpdGNoICVpbiUgYygiNSA1IiwgIjUgMyIpKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQ9YygiU0FNUExFX05BTUUiLCJFbnRlcm90eXBlc19pZCIsInN3aXRjaCIpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QoYWVzKHg9c3dpdGNoLCB5PXZhbHVlKSkgKyBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGU9ImZyZWUiKQ0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCI1IDUiLCAiMyAzIikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYm94cGxvdChhZXMoeD1zd2l0Y2gsIHk9dmFsdWUpKSArIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBzY2FsZT0iZnJlZSIpDQoNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCI1IDUiLCAiNSAzIikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIHRpZHlyOjpuZXN0KCkgICU+JSANCiAgbXV0YXRlKHdpbGNveF90ZXN0PXB1cnJyOjptYXAoZGF0YSx+d2lsY294LnRlc3QoLngkdmFsdWV+Lngkc3dpdGNoKSksDQogICAgICAgIHRpZHk9cHVycnI6Om1hcCh3aWxjb3hfdGVzdCwgYnJvb206OnRpZHkpKSAlPiUgDQogICAgICB0aWR5cjo6dW5uZXN0KHRpZHksLmRyb3A9VFJVRSkgJT4lDQogIGFycmFuZ2UocC52YWx1ZSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiNtdXRhdGUocC52YWx1ZT1wLmFkanVzdChwLnZhbHVlLCBtZXRob2Q9ImZkciIpKSAlPiUNCiAgZmlsdGVyKHAudmFsdWU8MC4wNSkgJT4lIHNlbGVjdCh2YXJpYWJsZSxwLnZhbHVlKSAlPiUgd3JpdGUuY3N2MihmaWxlPSJtZXRhZGF0YV9saW5rXzU1dnM1My5jc3YiKQ0KDQoNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiMyA1IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIHRpZHlyOjpuZXN0KCkgICU+JSANCiAgbXV0YXRlKHdpbGNveF90ZXN0PXB1cnJyOjptYXAoZGF0YSx+d2lsY294LnRlc3QoLngkdmFsdWV+Lngkc3dpdGNoKSksDQogICAgICAgIHRpZHk9cHVycnI6Om1hcCh3aWxjb3hfdGVzdCwgYnJvb206OnRpZHkpKSAlPiUgDQogICAgICB0aWR5cjo6dW5uZXN0KHRpZHksLmRyb3A9VFJVRSkgJT4lDQogIGFycmFuZ2UocC52YWx1ZSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgI211dGF0ZShwLnZhbHVlPXAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIikpICU+JQ0KICBmaWx0ZXIocC52YWx1ZTwwLjA1KSAlPiUgc2VsZWN0KHZhcmlhYmxlLHAudmFsdWUpICU+JSB3cml0ZS5jc3YyKGZpbGU9Im1ldGFkYXRhX2xpbmtfMzN2czM1LmNzdiIpDQoNCg0KDQoNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiNSA1IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIHRpZHlyOjpuZXN0KCkgICU+JSANCiAgbXV0YXRlKHdpbGNveF90ZXN0PXB1cnJyOjptYXAoZGF0YSx+d2lsY294LnRlc3QoLngkdmFsdWV+Lngkc3dpdGNoKSksDQogICAgICAgIHRpZHk9cHVycnI6Om1hcCh3aWxjb3hfdGVzdCwgYnJvb206OnRpZHkpKSAlPiUgDQogICAgICB0aWR5cjo6dW5uZXN0KHRpZHksLmRyb3A9VFJVRSkgJT4lDQogIGFycmFuZ2UocC52YWx1ZSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiNtdXRhdGUocC52YWx1ZT1wLmFkanVzdChwLnZhbHVlLCBtZXRob2Q9ImZkciIpKSAlPiUNCiAgZmlsdGVyKHAudmFsdWU8MC4wNSkgJT4lIHNlbGVjdCh2YXJpYWJsZSxwLnZhbHVlKSAlPiUgd3JpdGUuY3N2MihmaWxlPSJtZXRhZGF0YV9saW5rXzMzdnM1NS5jc3YiKQ0KDQoNCg0KDQpkZiAlPiUNCiAgbXV0YXRlKGRlbHRhX3JhdGlvID0gYWJzKGxvZzIocmF0aW9fYmVmb3JlKSAtIGxvZzIocmF0aW8pKSkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoeD1sb2cyKHJhdGlvX2JlZm9yZSkgLSBsb2cyKHJhdGlvKSx5PWxvZzIoc2hhbm5vbl9iZWZvcmUvc2hhbm5vbiksIGNvbG9yPXN3aXRjaCkpICsNCiAgeGxpbSgtNCw0KSArIHlsaW0oLTAuNSwgMC41KSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArIHNjYWxlX2NvbG9yX2JyZXdlcigiIiwgdHlwZT0icXVhbCIsIHBhbGV0dGUgPSAyKSArDQogIHhsYWIoIkZlYWNhbGliYWN0ZXJpdW0vQmFjdGVyb2lkZXMgdmFyaWF0aW9uIikgKyB5bGFiKCJhbHBoYS1kaXZlcnNpdHkgdmFyaWF0aW9uIikgLT4gZmlnUzEwQg0KDQoNCg0KDQoNCnJiaW5kKGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoLCByYXRpbykgLA0KICAgICAgZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHN3aXRjaCwgcmF0aW9fYmVmb3JlKSAlPiUgZHBseXI6OnJlbmFtZShFbnRlcm90eXBlc19pZD1FbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbj1zaGFubm9uX2JlZm9yZSwgcmF0aW89cmF0aW9fYmVmb3JlKSkgJT4lIA0KICAgICAgICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8pKSAlPiUNCiAgbXV0YXRlKHN0YWJsZSA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCI1IDUiLCIzIDMiKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiNSA1IiwiNSAzIiksICJNNSIsIk0zIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBzdGFydF9wYXJ0aXRpb24gJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvLCAuZGVzYz1UUlVFKSkgJT4lDQogICNhcnJhbmdlKHN3aXRjaCkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PXJhdGlvLHk9U0FNUExFX05BTUUsIGdyb3VwPVNBTVBMRV9OQU1FLCBjb2w9c3RhYmxlKSkgICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpICsgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzIiKSArIA0KICAjZmFjZXRfd3JhcCh+c3dpdGNoLCBuY29sPTEsIHNjYWxlPSJmcmVlX3kiKSArDQogIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArDQogIHlsYWIoIkFHUCBwYXJ0aWNpcGFudHMiKSArIHhsYWIoIkZhZWNhbGliYWN0ZXJpdW0vXG5CYWN0ZXJvaWRlcyByYXRpbyIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKCIiLCB2YWx1ZXM9YygiYmxhY2siLCJyZWQiKSwgbGFiZWw9Yygic3RhYmxlIiwidW5zdGFibGUiKSkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICBmYWNldF9ncmlkKHN0YXJ0X3BhcnRpdGlvbn4uLCBzY2FsZXMgPSAiZnJlZV95IikgLT4gZmlnNUNfZnVsbA0KDQoNCmRmICU+JQ0KICBtdXRhdGUoZGVsdGFfcmF0aW8gPSBhYnMobG9nMihyYXRpb19iZWZvcmUpIC0gbG9nMihyYXRpbykpKSAlPiUNCiAgbXV0YXRlKHN0YWJsZSA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCI1IDUiLCIzIDMiKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiNSA1IiwiNSAzIiksICJNNSIsIk0zIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBzdGFydF9wYXJ0aXRpb24gJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvLCAuZGVzYz1UUlVFKSkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9ib3hwbG90KGFlcyh4PXN0YXJ0X3BhcnRpdGlvbix5PWRlbHRhX3JhdGlvLCBjb2w9c3RhYmxlKSkgKyANCiAgeWxhYigiRmFlY2FsaWJhY3Rlcml1bS9CYWN0ZXJvaWRlc1xucmF0aW8gdmFyaWF0aW9uIikgKyANCiAgI3NjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nMiIpICsNCiAgeGxhYigiIikgKyBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwoIiIsdmFsdWVzPWMoImJsYWNrIiwicmVkIikpIC0+IGZpZzVDaW5zZXQNCg0KDQpmaWc1QyA9IGZpZzVDX2Z1bGwgKyBpbnNldF9lbGVtZW50KGZpZzVDaW5zZXQreWxhYigidmFyaWF0aW9uIikrZ3VpZGVzKGNvbG9yPUZBTFNFKSwgMC42LC0wLjEsMSwwLjMsIGlnbm9yZV90YWcgPSBUUlVFKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkEiKQ0KDQoNCg0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBtZXJnZShmX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihFbnRlcm90eXBlc19pZCU+JWFzLm51bWVyaWMpKSAlPiUNCiAgbXV0YXRlKHN0YWJsZSA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCI1IDUiLCIzIDMiKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiNSA1IiwiNSAzIiksICJNNSIsIk0zIikgICkgJT4lDQogICNmaWx0ZXIoc3RhYmxlIT0ic3RhYmxlIikgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9cmF0aW8pLCBhbHBoYT0wLjUpICArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikNCg0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBtZXJnZShmX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihFbnRlcm90eXBlc19pZCU+JWFzLm51bWVyaWMpKSAlPiUNCiAgbXV0YXRlKHN0YWJsZSA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCI1IDUiLCIzIDMiKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiNSA1IiwiNSAzIiksICJNNSIsIk0zIikgICkgJT4lIA0KICAjZmlsdGVyKHN0YWJsZSE9InN0YWJsZSIpICU+JQ0KICBwdWxsKHJhdGlvKSAlPiUNCiAgbG9nKC4sMikgJT4lIGRpcHRlc3Q6OmRpcC50ZXN0KCkNCg0KDQpgYGANCmBgYHtyfQ0KDQoNCnJiaW5kKGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoLCByYXRpbykgLA0KICAgICAgZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHN3aXRjaCwgcmF0aW9fYmVmb3JlKSAlPiUgZHBseXI6OnJlbmFtZShFbnRlcm90eXBlc19pZD1FbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbj1zaGFubm9uX2JlZm9yZSwgcmF0aW89cmF0aW9fYmVmb3JlKSkgJT4lIA0KICAgICAgICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8pKSAlPiUNCiAgbXV0YXRlKHN0YWJsZSA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCI1IDUiLCIzIDMiKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiNSA1IiwiNSAzIiksICJNNSIsIk0zIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBzdGFydF9wYXJ0aXRpb24gJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvLCAuZGVzYz1UUlVFKSkgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQogICN3aXRoKC4sd2lsY294LnRlc3QoZGF0YT0uLCB2YWx1ZX5zdGFibGUpKQ0KICAjZ2dwbG90KCkgKyBnZ2ZvcmNlOjpnZW9tX3NpbmEJKGFlcyh4PXN0YWJsZSx5PXZhbHVlLGNvbG9yPUVudGVyb3R5cGVzX2lkLngpKQ0KICBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh4PXN0YWJsZSxmaWxsPXZhbHVlPjAuOSksIHBvc2l0aW9uPSJmaWxsIikNCg0KcmJpbmQoZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gsIHJhdGlvKSAsDQogICAgICBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uX2JlZm9yZSwgc3dpdGNoLCByYXRpb19iZWZvcmUpICU+JSBkcGx5cjo6cmVuYW1lKEVudGVyb3R5cGVzX2lkPUVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uPXNoYW5ub25fYmVmb3JlLCByYXRpbz1yYXRpb19iZWZvcmUpKSAlPiUgDQogICAgICAgIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihyYXRpbykpICU+JQ0KICBtdXRhdGUoc3RhYmxlID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjUgNSIsIjMgMyIpLCAic3RhYmxlIiwidW5zdGFibGUiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCI1IDUiLCI1IDMiKSwgIk01IiwiTTMiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IHN0YXJ0X3BhcnRpdGlvbiAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8sIC5kZXNjPVRSVUUpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZmlsdGVyKHZhbHVlPnF1YW50aWxlKHZhbHVlLDIvMyl8dmFsdWU8cXVhbnRpbGUodmFsdWUsMS8zKSkgJT4lDQogIG11dGF0ZSh2YWx1ZT12YWx1ZT5xdWFudGlsZSh2YWx1ZSwwLjUpKSAlPiUNCiAgd2l0aCguLCBjaGlzcS50ZXN0KHN0YWJsZSx2YWx1ZSkpDQogIA0KICANCiAgI2dncGxvdCgpICsgZ2VvbV9iYXIoYWVzKHg9c3RhYmxlLGZpbGw9dmFsdWU+cXVhbnRpbGUodmFsdWUsMC41KSksIHBvc2l0aW9uPSJmaWxsIikgKyBzY2FsZV9maWxsX2JyZXdlcigiIikNCg0KDQpyYmluZChkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCwgcmF0aW8pICwNCiAgICAgIGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub25fYmVmb3JlLCBzd2l0Y2gsIHJhdGlvX2JlZm9yZSkgJT4lIGRwbHlyOjpyZW5hbWUoRW50ZXJvdHlwZXNfaWQ9RW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub249c2hhbm5vbl9iZWZvcmUsIHJhdGlvPXJhdGlvX2JlZm9yZSkpICU+JSANCiAgICAgICAgbXV0YXRlKFNBTVBMRV9OQU1FID0gU0FNUExFX05BTUUgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiNSA1IiwiMyAzIiksICJzdGFibGUiLCJ1bnN0YWJsZSIpICApICU+JQ0KICBtdXRhdGUoc3RhcnRfcGFydGl0aW9uID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjUgNSIsIjUgMyIpLCAiTTUiLCJNMyIpICApICU+JQ0KICBtdXRhdGUoc3RhcnRfcGFydGl0aW9uID0gc3RhcnRfcGFydGl0aW9uICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihyYXRpbywgLmRlc2M9VFJVRSkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIodmFsdWU+MC45OSwgc3RhYmxlPT1zdGFibGUpICU+JQ0KICBwdWxsKHJhdGlvKSAlPiUgZGlwdGVzdDo6ZGlwLnRlc3QoKQ0KICANCiAgI2dncGxvdCgpICsgZ2VvbV9kZW5zaXR5KGFlcyh4PXJhdGlvKSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZzIiKQ0KICANCg0KcmJpbmQoZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gsIHJhdGlvKSAsDQogICAgICBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uX2JlZm9yZSwgc3dpdGNoLCByYXRpb19iZWZvcmUpICU+JSBkcGx5cjo6cmVuYW1lKEVudGVyb3R5cGVzX2lkPUVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uPXNoYW5ub25fYmVmb3JlLCByYXRpbz1yYXRpb19iZWZvcmUpKSAlPiUgDQogICAgICAgIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihyYXRpbykpICU+JQ0KICBtdXRhdGUoc3RhYmxlID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjIgMiIsIjYgNiIpLCAic3RhYmxlIiwidW5zdGFibGUiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCIyIDIiLCIyIDYiKSwgIk0yIiwiTTYiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IHN0YXJ0X3BhcnRpdGlvbiAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8sIC5kZXNjPVRSVUUpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZ3JvdXBfYnkoc3dpdGNoKSAlPiUNCiAgc3VtbWFyaXNlKHEwNSA9IHF1YW50aWxlKHJhdGlvLCAwLjA1KSwgcTI1ID0gcXVhbnRpbGUocmF0aW8sIDAuMjUpLCBxNTA9bWVkaWFuKHJhdGlvKSwgIHE3NSA9IHF1YW50aWxlKHJhdGlvLCAwLjc1KSwgcTk1ID0gcXVhbnRpbGUocmF0aW8sIDAuOTUpKQ0KDQpgYGANCg0KDQojIyMgcGNhDQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KDQoNCmxpYnJhcnkoYWRlNCkNCg0KY2JpbmQoZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICAjZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjMgMyIsICIzIDUiLCAiNSA1IiwgIjUgMyIpKSAlPiUNCiAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjMgMyIsICI1IDUiKSkgJT4lDQogIG1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYyksIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIHNlbGVjdCgxOjQpLA0KDQoNCmRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgI2ZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiMyA1IiwgIjUgNSIsICI1IDMiKSkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiNSA1IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBzZWxlY3QoLTEsLTIsLTMsLTQpICU+JQ0KICBhZGU0OjpkdWRpLnBjYShzY2FubmYgPSBGQUxTRSwgbmY9MikgJT4lDQogIC4kbGkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHg9QXhpczEsIHk9QXhpczIsIGNvbD1zd2l0Y2gpKQ0KDQoNCg0KDQoNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiMyA1IiwgIjUgNSIsICI1IDMiKSkgJT4lDQogICNmaWx0ZXIoc3dpdGNoICVpbiUgYygiMyAzIiwgIjUgNSIpKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgc2VsZWN0KC0xLC0yLC0zLC00KSAtPiBkZl9wY2FfcHJlcA0KICANCmFkZTQ6OmR1ZGkucGNhKGRmX3BjYV9wcmVwLCBzY2FubmYgPSBGQUxTRSwgbmY9MikgLT4gcGNhXzNfNQ0KDQoNCmRmICU+JSANCiAgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lIA0KICBmaWx0ZXIoc3dpdGNoICVpbiUgYygiMyAzIiwgIjMgNSIsICI1IDUiLCAiNSAzIikpICU+JQ0KICAjZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjMgMyIsICI1IDUiKSkgJT4lDQogIHB1bGwoc3dpdGNoKSAlPiUgYXMuZmFjdG9yKCkgLT4gZGZfZmFjDQogIGFkZTQ6OmJjYShwY2FfM181LCBmYWM9ZGZfZmFjLCBzY2FubmY9RikgJT4lIHJhbmR0ZXN0KCkNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiMyA1IiwgIjUgNSIsICI1IDMiKSkgJT4lDQogICNmaWx0ZXIoc3dpdGNoICVpbiUgYygiMyAzIiwgIjUgNSIpKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgc2VsZWN0KC0xLC0yLC0zLC00KSAtPiBkZl9wY2FfcHJlcA0KICANCmFkZTQ6OmR1ZGkucGNhKGRmX3BjYV9wcmVwLCBzY2FubmYgPSBGQUxTRSwgbmY9MikgLT4gcGNhXzNfNQ0KDQoNCg0KDQpjYmluZChkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiMyA1IiwgIjUgNSIsICI1IDMiKSkgJT4lDQogICNmaWx0ZXIoc3dpdGNoICVpbiUgYygiMyAzIiwgIjUgNSIpKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgc2VsZWN0KDE6NCksDQoNCg0KZGYgJT4lIA0KICBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUgDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiMyA1IiwgIjUgNSIsICI1IDMiKSkgJT4lDQogICNmaWx0ZXIoc3dpdGNoICVpbiUgYygiMyAzIiwgIjUgNSIpKSAlPiUNCiAgcHVsbChzd2l0Y2gpICU+JSBhcy5mYWN0b3IoKSAlPiUNCiAgYWRlNDo6YmNhKHBjYV8zXzUsIGZhYz0uLCBzY2FubmY9RikgJT4lDQogIC4kbHMpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYm94cGxvdChhZXMoeT1DUzEsIHg9c3dpdGNoKSkgDQoNCg0KDQoNCg0KYGBgDQoNCg0KDQoNCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KcmJpbmQoDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIzIDMiLCAiMyA1IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIHRpZHlyOjpuZXN0KCkgICU+JSANCiAgbXV0YXRlKGNvcl90ZXN0PXB1cnJyOjptYXAoZGF0YSx+Y29yLnRlc3QoLngkdmFsdWUsLngkc3dpdGNoICU+JSBhcy5mYWN0b3IgJT4lIGFzLm51bWVyaWMoKSwgbWV0aG9kPSJzcGVhcm1hbiIpKSwNCiAgICAgICAgdGlkeT1wdXJycjo6bWFwKGNvcl90ZXN0LCBicm9vbTo6dGlkeSkpICU+JSANCiAgICAgIHRpZHlyOjp1bm5lc3QodGlkeSwuZHJvcD1UUlVFKSAlPiUNCiAgYXJyYW5nZShwLnZhbHVlKSAlPiUNCiAgbXV0YXRlKHN3aXRjaD1jKCIzLT41IikpICU+JQ0KICBzZWxlY3QodmFyaWFibGUsZXN0aW1hdGUscC52YWx1ZSxzd2l0Y2gpLA0KDQoNCmRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjUgNSIsICI1IDMiKSkgJT4lDQogIG1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYyksIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkPWMoIlNBTVBMRV9OQU1FIiwiRW50ZXJvdHlwZXNfaWQiLCJzd2l0Y2giKSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgdGlkeXI6Om5lc3QoKSAgJT4lIA0KICBtdXRhdGUoY29yX3Rlc3Q9cHVycnI6Om1hcChkYXRhLH5jb3IudGVzdCgueCR2YWx1ZSwueCRzd2l0Y2ggJT4lIGFzLmZhY3RvciAlPiUgYXMubnVtZXJpYygpLCBtZXRob2Q9InNwZWFybWFuIikpLA0KICAgICAgICB0aWR5PXB1cnJyOjptYXAoY29yX3Rlc3QsIGJyb29tOjp0aWR5KSkgJT4lIA0KICAgICAgdGlkeXI6OnVubmVzdCh0aWR5LC5kcm9wPVRSVUUpICU+JQ0KICBhcnJhbmdlKHAudmFsdWUpICU+JQ0KICBtdXRhdGUoc3dpdGNoPWMoIjUtPjMiKSkgJT4lDQogIHNlbGVjdCh2YXJpYWJsZSxlc3RpbWF0ZSxwLnZhbHVlLHN3aXRjaCkpICU+JQ0KICBmaWx0ZXIocC52YWx1ZTwwLjA1KSAlPiUNCiAgDQpnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh4PXZhcmlhYmxlLHk9ZXN0aW1hdGUsZmlsbD1zd2l0Y2gpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArIGNvb3JkX2ZsaXAoKSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSAtPiBmaWc1RQ0KICANCg0KYGBgDQoNCg0KDQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShjYXJldCkNCnNldC5zZWVkKDY2NikNCnRyYWluLmNvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJyZXBlYXRlZGN2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5RnVuY3Rpb249dHdvQ2xhc3NTdW1tYXJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyID0gMTAsIHJlcGVhdHMgPSA1LCBjbGFzc1Byb2JzPVQsIHNhdmVQcmVkaWN0aW9ucyA9IFQpDQoNCmRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjUgNSIsICI1IDMiKSkgJT4lDQogIG1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYyksIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lIHNlbGVjdCgtU0FNUExFX05BTUUsLUVudGVyb3R5cGVzX2lkLCAtc2hhbm5vbikgJT4lIG11dGF0ZShzd2l0Y2ggPSBwYXN0ZTAoInAiLHN3aXRjaCkgJT4lIGdzdWIoIlxcICIsIiIsLikgJT4lIGFzLmZhY3RvcikgICAtPiBkZl81NV81Mw0KICANCg0KIyBUcmFpbiB0aGUgbW9kZWwNCnN1cHByZXNzV2FybmluZ3MobW9kZWwgPC0gdHJhaW4oc3dpdGNoIH4uLCBkYXRhID0gZGZfNTVfNTMsIG1ldGhvZCA9ICJyZiIsDQogICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi5jb250cm9sLCBwcmVQcm9jPWMoImNlbnRlciIsICJzY2FsZSIpKSkNCiMgU3VtbWFyaXplIHRoZSByZXN1bHRzDQpwcmludChtb2RlbCkNCg0KdmFySW1wKG1vZGVsLCBzY2FsZSA9IEZBTFNFLCB1c2VNb2RlbD1UUlVFKQ0Kcm9jX2ltcCA8LSBmaWx0ZXJWYXJJbXAoeCA9IGRmXzU1XzUzICU+JSBzZWxlY3QoLXN3aXRjaCksIHkgPSBkZl81NV81MyRzd2l0Y2gpDQoNCg0KbGlicmFyeShwUk9DKQ0KIyBTZWxlY3QgYSBwYXJhbWV0ZXIgc2V0dGluZw0Kc2VsZWN0ZWRJbmRpY2VzIDwtIG1vZGVsJHByZWQkbXRyeSA9PSAxMDANCiMgUGxvdDoNCnBsb3Qucm9jKG1vZGVsJHByZWQkb2JzW3NlbGVjdGVkSW5kaWNlc10sDQogICAgICAgICBtb2RlbCRwcmVkJHA1NVtzZWxlY3RlZEluZGljZXNdKQ0KYGBgDQoNCg0KDQoNCiMjIEZpZ3VyZSA1IC0gVGltZSBzZXJpZXMNCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMn0NCg0KbGlicmFyeShwYXRjaHdvcmspDQoNCg0KIyhmaWc1QSB8IChmaWc1Qi9maWc1Qyl8KGZpZzVEL2ZpZzVFKSkgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDIsMSwxLjUpKSArcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpDQoNCiMgcGF0Y2hfcGxvdCA9ICgoZmlnNUEgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJBIikpIHwgDQojICAgICANCiMgICAgICgoZmlnNUJfZnVsbCArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkIiKSArDQojICAgICAgICBpbnNldF9lbGVtZW50KGZpZzVCaW5zZXQgKyANCiMgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJ2YXJpYXRpb24iKSsNCiMgICAgICAgICAgICAgICAgICAgICAgICBndWlkZXMoY29sb3I9RkFMU0UpLCAwLjYsLTAuMSwxLDAuMywgaWdub3JlX3RhZyA9IEZBTFNFKSkvDQojICAgICAgICANCiMgICAgICAgIChmaWc1Q19mdWxsICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQyIpICsNCiMgICAgICAgIGluc2V0X2VsZW1lbnQoZmlnNUNpbnNldCsNCiMgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJ2YXJpYXRpb24iKSsNCiMgICAgICAgICAgICAgICAgICAgICAgICBndWlkZXMoY29sb3I9RkFMU0UpLCAwLjYsLTAuMSwxLDAuMywgaWdub3JlX3RhZyA9IEZBTFNFKSkpKSArDQojICAgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpICArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMiwxLjUpKQ0KIyANCiMgcGF0Y2hfcGxvdFtbMl1dW1sxXV0gKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJBIikNCg0KDQooKGZpZzVBKSB8IChmaWc1Ql9mdWxsL2ZpZzVDX2Z1bGwpKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gImEiKSArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMiwxLjUpKQ0KDQpnZ3NhdmUoImZpZ3VyZXMvZmlndXJlNV9iaXMucGRmIikNCg0KYGBgDQoNCg0KYGBge3J9DQoNCmdlbnVzICU+JQ0KICBmaWx0ZXIodGF4YSAlaW4lIGMoZl9HRyxiX0dHKSkgJT4lDQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJ0YXhhIikgJT4lDQogIHQgJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgZHBseXI6OnJlbmFtZShGZWFjYWxpYmFjdGVyaXVtPTIsQmFjdGVyb2lkZXM9MSkgJT4lDQogIG11dGF0ZShyYXRpbz1GZWFjYWxpYmFjdGVyaXVtL0JhY3Rlcm9pZGVzKSAtPiBmX2JfcmF0aW8NCg0KIyBtZXRhZGF0YSAlPiUNCiMgICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQojICAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KIyAgIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KIyAgIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQojICAgbWVyZ2Uoc2hhbm5vbiwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiMgICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KIyAgIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQojICAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiMgICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQojICAgZmlsdGVyKG4+MSkgJT4lDQojICAgDQojICAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KIyAgIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQojICAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQsIGRheXMpICU+JQ0KIyAgIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUNCiMgICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgJWluJSBjKDIsNikpICU+JQ0KIyAgIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PWRheXMseT1zaGFubm9uLGdyb3VwPUhPU1RfU1VCSkVDVF9JRCwgY29sPWFzLmNoYXJhY3RlcihFbnRlcm90eXBlc19pZCkpKSANCiAgDQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBtZXJnZShzaGFubm9uLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBtZXJnZShmX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgI2ZpbHRlcihuPjEpICU+JQ0KICANCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICANCiAgDQogIGZpbHRlcihkYXlzID09IDAgfCBkYXlzID4gNjAqNjAqMjQpICU+JQ0KICANCiAgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JSANCiAgDQoNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIA0KICBtdXRhdGUoZGF5c18wPWJyYW5jaGVzW3doaWNoLm1pbihzYW1wbGVfb3JkZXIpXSkgJT4lDQogICNhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCkgICU+JSANCiAgI211dGF0ZShzYW1wbGVfb3JkZXI9cmFuayhkYXlzKSkgJT4lDQogIG11dGF0ZShkYXlzID0gYXMubnVtZXJpYyhkYXlzKSkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSwgSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBFbnRlcm90eXBlc19pZCwgc2hhbm5vbiwgcmF0aW8pICU+JQ0KICBtdXRhdGUoRW50ZXJvdHlwZXNfaWQgPSBFbnRlcm90eXBlc19pZCAlPiUgYXMuY2hhcmFjdGVyICkgJT4lIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUoc2FtZV9icmFuY2hlc19sYWcgPSBpZmVsc2UoYnJhbmNoZXMgPT0gbGFnKGJyYW5jaGVzKSwgInllcyIsIm5vIiksIA0KICAgICAgICAgYnJhbmNoZXNfYmVmb3JlPWxhZyhicmFuY2hlcyksIGRheXNfZGVsdGE9IGRheXMgLSBsYWcoZGF5cyksIA0KICAgICAgICAgRW50ZXJvdHlwZXNfaWRfYmVmb3JlID0gbGFnKEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIpLA0KICAgICAgICAgc2hhbm5vbl9iZWZvcmUgPSBsYWcoc2hhbm5vbiksDQogICAgICAgICByYXRpb19iZWZvcmUgPSBsYWcocmF0aW8pKSAlPiUNCiAgZmlsdGVyKHNhbXBsZV9vcmRlciA+MSkgJT4lDQogIG11dGF0ZShicmFuY2hlc19wYWlycz1wYXN0ZTAoYnJhbmNoZXNfYmVmb3JlLCItIixicmFuY2hlcykpICU+JQ0KICAjZmlsdGVyKEVudGVyb3R5cGVzX2lkICVpbiUgYygyLDYpLCBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDIsNikpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLHJhdGlvLCBFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHJhdGlvX2JlZm9yZSkgJT4lDQogIG11dGF0ZShzd2l0Y2g9cGFzdGUoRW50ZXJvdHlwZXNfaWQsRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSkgLT4gZGYNCg0KDQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBtZXJnZShzaGFubm9uLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBtZXJnZShmX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyLDUsMSkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYm94cGxvdChhZXMoeD1sb2cyKHJhdGlvKSwgeT1hcy5jaGFyYWN0ZXIoRW50ZXJvdHlwZXNfaWQpKSkNCg0KDQoNCmBgYA0KIyMjIGZpZyBzdXBwDQpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0NCg0KZmlnUzEwQSArIGZpZ1MxMEIgKyBwYXRjaHdvcms6OnBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWwgPSAiYSIpDQoNCg0KZ2dzYXZlKCJmaWdTMTAucGRmIikNCg0KYGBgDQoNCiMjIGRlc2NyaXB0aXZlIHN0YXQNCg0KDQpgYGB7cn0NCmdlbnVzICU+JQ0KICBmaWx0ZXIodGF4YSAlaW4lIGMoZl9HRyxiX0dHKSkgJT4lDQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJ0YXhhIikgJT4lDQogIHQgJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgZHBseXI6OnJlbmFtZShGZWFjYWxpYmFjdGVyaXVtPTIsQmFjdGVyb2lkZXM9MSkgJT4lDQogIG11dGF0ZShyYXRpbz1GZWFjYWxpYmFjdGVyaXVtL0JhY3Rlcm9pZGVzKSAtPiBmX2JfcmF0aW8NCg0KIyBtZXRhZGF0YSAlPiUNCiMgICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQojICAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KIyAgIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KIyAgIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQojICAgbWVyZ2Uoc2hhbm5vbiwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiMgICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KIyAgIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQojICAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiMgICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQojICAgZmlsdGVyKG4+MSkgJT4lDQojICAgDQojICAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KIyAgIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQojICAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQsIGRheXMpICU+JQ0KIyAgIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUNCiMgICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgJWluJSBjKDIsNikpICU+JQ0KIyAgIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PWRheXMseT1zaGFubm9uLGdyb3VwPUhPU1RfU1VCSkVDVF9JRCwgY29sPWFzLmNoYXJhY3RlcihFbnRlcm90eXBlc19pZCkpKSANCiAgDQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBtZXJnZShzaGFubm9uLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBtZXJnZShmX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgI2ZpbHRlcihuPjEpICU+JQ0KICANCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICANCiAgDQogIGZpbHRlcihkYXlzID09IDAgfCBkYXlzID4gNjAqNjAqMjQpICU+JQ0KICANCiAgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JSANCiAgDQoNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIA0KICBtdXRhdGUoZGF5c18wPWJyYW5jaGVzW3doaWNoLm1pbihzYW1wbGVfb3JkZXIpXSkgJT4lDQogICNhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCkgICU+JSANCiAgI211dGF0ZShzYW1wbGVfb3JkZXI9cmFuayhkYXlzKSkgJT4lDQogIG11dGF0ZShkYXlzID0gYXMubnVtZXJpYyhkYXlzKSkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSwgSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBFbnRlcm90eXBlc19pZCwgc2hhbm5vbiwgcmF0aW8pICU+JQ0KICBtdXRhdGUoRW50ZXJvdHlwZXNfaWQgPSBFbnRlcm90eXBlc19pZCAlPiUgYXMuY2hhcmFjdGVyICkgJT4lIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUoc2FtZV9icmFuY2hlc19sYWcgPSBpZmVsc2UoYnJhbmNoZXMgPT0gbGFnKGJyYW5jaGVzKSwgInllcyIsIm5vIiksIA0KICAgICAgICAgYnJhbmNoZXNfYmVmb3JlPWxhZyhicmFuY2hlcyksIGRheXNfZGVsdGE9IGRheXMgLSBsYWcoZGF5cyksIA0KICAgICAgICAgRW50ZXJvdHlwZXNfaWRfYmVmb3JlID0gbGFnKEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIpLA0KICAgICAgICAgc2hhbm5vbl9iZWZvcmUgPSBsYWcoc2hhbm5vbiksDQogICAgICAgICByYXRpb19iZWZvcmUgPSBsYWcocmF0aW8pKSAlPiUNCiAgZmlsdGVyKHNhbXBsZV9vcmRlciA+MSkgJT4lDQogIG11dGF0ZShicmFuY2hlc19wYWlycz1wYXN0ZTAoYnJhbmNoZXNfYmVmb3JlLCItIixicmFuY2hlcykpICU+JQ0KICAjZmlsdGVyKEVudGVyb3R5cGVzX2lkICVpbiUgYygyLDYpLCBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKDIsNikpICU+JQ0KICB1bmdyb3VwKCkgLT4gbWV0YWRhdGFfdGltZV90bXANCg0KbWV0YWRhdGFfdGltZV90bXAkSE9TVF9TVUJKRUNUX0lEICU+JSBsZW5ndGgoKQ0KDQptZXRhZGF0YV90aW1lX3RtcCRIT1NUX1NVQkpFQ1RfSUQgJT4lIHVuaXF1ZSAlPiUgbGVuZ3RoKCkNCg0KbWVkaWFuKG1ldGFkYXRhX3RpbWVfdG1wJGRheXNfZGVsdGEpIC8gKDYwKjYwKjI0KQ0KDQpxdWFudGlsZShtZXRhZGF0YV90aW1lX3RtcCRkYXlzX2RlbHRhLCBjKDAuMjUsMC43NSkpIC8gKDYwKjYwKjI0KQ0KDQoNCg0KbWV0YWRhdGFfdGltZV90bXAgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZF9iZWZvcmUgPT0gRW50ZXJvdHlwZXNfaWQpICU+JSBkaW0NCg0KbWV0YWRhdGFfdGltZV90bXAgJT4lDQogIG11dGF0ZShkYXlzX2RlbHRhX2JpbnMgPSBjdXQoZGF5c19kZWx0YSwgYnJlYWtzID0gYygtMSw2MCo2MCoyNCo3LDEyMCoyNCo2MCo2MCwzNjUqNjAqNjAqMjQsMTAwMDAqNjAqNjAqMjQpKSkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9ZGF5c19kZWx0YS8oMjQqNjAqNjApLCBmaWxsPWMoRW50ZXJvdHlwZXNfaWRfYmVmb3JlID09IEVudGVyb3R5cGVzX2lkKSksIHBvc2l0aW9uID0gImZpbGwiLCBicmVha3MgPSBjKC0xLDcsMzAsMzY1LDEwMDApKQ0KICANCm1ldGFkYXRhX3RpbWVfdG1wICU+JQ0KICBtdXRhdGUoZGF5c19kZWx0YV9iaW5zID0gY3V0KGRheXNfZGVsdGEsIGJyZWFrcyA9IGMoLTEsNjAqNjAqMjQqNywxMjAqMjQqNjAqNjAsMzY1KjYwKjYwKjI0LDEwMDAwKjYwKjYwKjI0KSkpICU+JQ0KZ2dwbG90KCkgKyBnZW9tX2JhcihhZXMoeD1kYXlzX2RlbHRhX2JpbnMsIGZpbGw9YyhFbnRlcm90eXBlc19pZF9iZWZvcmUgPT0gRW50ZXJvdHlwZXNfaWQpKSwgcG9zaXRpb249ImZpbGwiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArIHNjYWxlX2ZpbGxfYnJld2VyKCJzYW1lIHBhcnRpdGlvbnMiLCB0eXBlPSJxdWFsIikgKw0KICBmYWNldF93cmFwKH5icmFuY2hlc19iZWZvcmUpICsgeGxhYigidGltZSByYW5nZSBiZXR3ZWVuIHR3byBzYW1wbGVzIikgKyB5bGFiKCJTYW1wbGVzICUiKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIndlZWsiLCI0IG1vbnRocyIsICI0IHRvIDEyIG1vbnRocyIsICI+IDEyIG1vbnRocyIpKQ0KDQoNCm1ldGFkYXRhX3RpbWVfdG1wICU+JQ0KICBtdXRhdGUoZGF5c19kZWx0YV9iaW5zID0gY3V0KGRheXNfZGVsdGEsIGJyZWFrcyA9IGMoLTEsNjAqNjAqMjQqNywxMjAqMjQqNjAqNjAsMzY1KjYwKjYwKjI0LDEwMDAwKjYwKjYwKjI0KSkpICU+JQ0KZ2dwbG90KCkgKyBnZW9tX2JhcihhZXMoeD1kYXlzX2RlbHRhX2JpbnMsIGZpbGw9YyhFbnRlcm90eXBlc19pZF9iZWZvcmUgPT0gRW50ZXJvdHlwZXNfaWQpKSwgcG9zaXRpb249ImZpbGwiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArIHNjYWxlX2ZpbGxfYnJld2VyKCJzYW1lIHBhcnRpdGlvbnMiLCB0eXBlPSJxdWFsIikgKw0KICB4bGFiKCJ0aW1lIHJhbmdlIGJldHdlZW4gdHdvIHNhbXBsZXMiKSArIHlsYWIoIlNhbXBsZXMgJSIpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9Yygid2VlayIsIjQgbW9udGhzIiwgIjQgdG8gMTIgbW9udGhzIiwgIj4gMTIgbW9udGhzIikpICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpDQoNCg0KDQoNCmBgYA0KDQoNCg0KDQojIyMgRiBCIHJhdGlvDQoNCmBgYHtyfQ0KDQpnZW51cyAlPiUNCiAgZmlsdGVyKHRheGEgJWluJSBjKGZfR0csYl9HRykpICU+JQ0KICB0aWJibGU6OmNvbHVtbl90b19yb3duYW1lcygidGF4YSIpICU+JQ0KICB0ICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIGRwbHlyOjpyZW5hbWUoRmVhY2FsaWJhY3Rlcml1bT0yLEJhY3Rlcm9pZGVzPTEpICU+JQ0KICBtdXRhdGUocmF0aW89RmVhY2FsaWJhY3Rlcml1bS9CYWN0ZXJvaWRlcykgLT4gZl9iX3JhdGlvDQoNCiMgbWV0YWRhdGEgJT4lDQojICAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KIyAgIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiMgICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRldGltZSgpKSAlPiUNCiMgICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KIyAgIG1lcmdlKHNoYW5ub24sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQojICAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiMgICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KIyAgIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQojICAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KIyAgIGZpbHRlcihuPjEpICU+JQ0KIyAgIA0KIyAgIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiMgICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KIyAgIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiMgICBtdXRhdGUoc2FtcGxlX29yZGVyPW9yZGVyKENPTExFQ1RJT05fVElNRVNUQU1QKSkgJT4lDQojICAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICVpbiUgYygyLDYpKSAlPiUNCiMgICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD1kYXlzLHk9c2hhbm5vbixncm91cD1IT1NUX1NVQkpFQ1RfSUQsIGNvbD1hcy5jaGFyYWN0ZXIoRW50ZXJvdHlwZXNfaWQpKSkgDQogIA0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIA0KICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRldGltZSgpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgbWVyZ2Uoc2hhbm5vbiwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgbWVyZ2UoZl9iX3JhdGlvLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQogICNmaWx0ZXIobj4xKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiAgDQogIA0KICBmaWx0ZXIoZGF5cyA9PSAwIHwgZGF5cyA+IDYwKjYwKjI0KSAlPiUNCiAgDQogIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCwgZGF5cykgJT4lDQogIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUgDQogIA0KDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICANCiAgbXV0YXRlKGRheXNfMD1icmFuY2hlc1t3aGljaC5taW4oc2FtcGxlX29yZGVyKV0pICU+JQ0KICAjYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQpICAlPiUgDQogICNtdXRhdGUoc2FtcGxlX29yZGVyPXJhbmsoZGF5cykpICU+JQ0KICBtdXRhdGUoZGF5cyA9IGFzLm51bWVyaWMoZGF5cykpICU+JQ0KICBzZWxlY3QoU0FNUExFX05BTUUsIEhPU1RfU1VCSkVDVF9JRCwgZGF5cywgc2FtcGxlX29yZGVyLCBicmFuY2hlcywgRW50ZXJvdHlwZXNfaWQsIHNoYW5ub24sIHJhdGlvKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlciApICU+JSANCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgbXV0YXRlKHNhbWVfYnJhbmNoZXNfbGFnID0gaWZlbHNlKGJyYW5jaGVzID09IGxhZyhicmFuY2hlcyksICJ5ZXMiLCJubyIpLCANCiAgICAgICAgIGJyYW5jaGVzX2JlZm9yZT1sYWcoYnJhbmNoZXMpLCBkYXlzX2RlbHRhPSBkYXlzIC0gbGFnKGRheXMpLCANCiAgICAgICAgIEVudGVyb3R5cGVzX2lkX2JlZm9yZSA9IGxhZyhFbnRlcm90eXBlc19pZCAlPiUgYXMuY2hhcmFjdGVyKSwNCiAgICAgICAgIHNoYW5ub25fYmVmb3JlID0gbGFnKHNoYW5ub24pLA0KICAgICAgICAgcmF0aW9fYmVmb3JlID0gbGFnKHJhdGlvKSkgJT4lDQogIGZpbHRlcihzYW1wbGVfb3JkZXIgPjEpICU+JQ0KICBtdXRhdGUoYnJhbmNoZXNfcGFpcnM9cGFzdGUwKGJyYW5jaGVzX2JlZm9yZSwiLSIsYnJhbmNoZXMpKSAlPiUNCiAgI2ZpbHRlcihFbnRlcm90eXBlc19pZCAlaW4lIGMoMiw2KSwgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygyLDYpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbixyYXRpbywgRW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub25fYmVmb3JlLCByYXRpb19iZWZvcmUsIGJyYW5jaGVzKSAlPiUNCiAgbXV0YXRlKHN3aXRjaD1wYXN0ZShFbnRlcm90eXBlc19pZCxFbnRlcm90eXBlc19pZF9iZWZvcmUpKSAtPiBkZg0KDQoNCg0KZGYgJT4lDQogIGZpbHRlcihicmFuY2hlcz09IkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8pKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMiIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS80KQ0KDQoNCmdlbnVzICU+JQ0KICBmaWx0ZXIodGF4YSAlaW4lIGMoZl9HRyxiX0dHKSkgJT4lDQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJ0YXhhIikgJT4lDQogIHQgJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgZHBseXI6OnJlbmFtZShGZWFjYWxpYmFjdGVyaXVtPTIsQmFjdGVyb2lkZXM9MSkgJT4lDQogIG11dGF0ZShyYXRpbz0oRmVhY2FsaWJhY3Rlcml1bSsxKS8oQmFjdGVyb2lkZXMrMSkpIC0+IGZfYl9yYXRpbw0KDQpmcmFjX2Z1bj1mdW5jdGlvbih4KSAxL3gNCg0KIyBmX2JfcmF0aW8gJT4lDQojICAgbWVyZ2UoZW50ZXJvdHlwZXMsLiwgYnkueT0icm93Lm5hbWVzIiwgYnkueD0ic2FtcGxlX25hbWUiKSAlPiUNCiMgICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KIyAgIGZpbHRlcih2YWx1ZT4wLjgwKSAlPiUNCiMgICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQojICAgICAgICAgICkgJT4lDQojICAgZmlsdGVyKGJyYW5jaGVzPT0iQmFjdGVyb2lkZXMgRE1NIHR5cGVzIikgJT4lDQojICAgZ2dwbG90KCkgKyANCiMgICBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8pKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMiIpICsNCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLzQpDQoNCmZfYl9yYXRpbyAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsLiwgYnkueT0icm93Lm5hbWVzIiwgYnkueD0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiAgI2ZpbHRlcih2YWx1ZT4wLjgwKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIGZpbHRlcihicmFuY2hlcz09IkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIpICU+JSANCiAgI3B1bGwocmF0aW8pICU+JSBsb2cyKCkgJT4lIG1pY3JvYmlvbWU6OmJpbW9kYWxpdHkobWV0aG9kID0gIlNhcmxlLmZpbml0ZS5zYW1wbGUiLCBicy5pdGVyPTEwMCwgdmVyYm9zZT1UUlVFKQ0KICBnZ3Bsb3QoKSArIGdlb21fZGVuc2l0eShhZXMoeD1yYXRpbykpICsgDQogICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZzIiLCBsYWJlbHM9c2NhbGVzOjp0cmFuc19mb3JtYXQoImZyYWNfZnVuIixzY2FsZXM6OmxhYmVsX21hdGgoZXhwciA9IDEvLngsIGZvcm1hdCA9IGZvcmNlKSkpICsNCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDEvNSkgKyANCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgeGxhYigiRmFlY2FsaWJhY3Rlcml1bSBCYWN0ZXJvaWRlcyByYXRpb1xud2l0aGluIEJhY3Rlcm9pZGVzIGVucmljaGVkIGJyYW5jaCIpIC0+IHBfZnByYXVfZGVuc2l0eQ0KDQoNCg0KZl9iX3JhdGlvICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywuLCBieS55PSJyb3cubmFtZXMiLCBieS54PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICAjZmlsdGVyKHZhbHVlPjAuODApICU+JQ0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzPT0iQmFjdGVyb2lkZXMgRE1NIHR5cGVzIikgJT4lIA0KICBtdXRhdGUoRW50ZXJvdHlwZXNfaWQgPSBFbnRlcm90eXBlc19pZCAlPiUgYXMuY2hhcmFjdGVyKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfc3RhYmlsaXR5LCBieT0iRW50ZXJvdHlwZXNfaWQiKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gRW50ZXJvdHlwZXNfaWQgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHN0YWJpbGl0eSkpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZCkgJT4lDQogIG11dGF0ZShzdGFiaWxpdHkgPSBtZWRpYW4oc3RhYmlsaXR5KSkgJT4lDQogICNwdWxsKHJhdGlvKSAlPiUgbG9nMigpICU+JSBtaWNyb2Jpb21lOjpiaW1vZGFsaXR5KG1ldGhvZCA9ICJTYXJsZS5maW5pdGUuc2FtcGxlIiwgYnMuaXRlcj0xMDAsIHZlcmJvc2U9VFJVRSkNCiAgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QoYWVzKHg9cmF0aW8seT1FbnRlcm90eXBlc19pZCwgZmlsbD1zdGFiaWxpdHkpKSArDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMiIsIGxhYmVscz1zY2FsZXM6OnRyYW5zX2Zvcm1hdCgiZnJhY19mdW4iLHNjYWxlczo6bGFiZWxfbWF0aChleHByID0gMS8ueCwgZm9ybWF0ID0gZm9yY2UpKSkgKw0KICBzY2FsZV9maWxsX2NvbnRpbnVvdXModHlwZT0idmlyaWRpcyIpICsNCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDEvNSkgKyANCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgeWxhYigiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIikgKw0KICB4bGFiKCJGYWVjYWxpYmFjdGVyaXVtIEJhY3Rlcm9pZGVzIHJhdGlvIikgLT4gcF9mcHJhdV9wYXJ0aXRpb24NCg0KDQpwX2ZwcmF1X2RlbnNpdHkvcF9mcHJhdV9wYXJ0aXRpb24NCg0KZl9iX3JhdGlvICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywuLCBieS55PSJyb3cubmFtZXMiLCBieS54PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICAjZmlsdGVyKHZhbHVlPjAuODApICU+JQ0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzPT0iQmFjdGVyb2lkZXMgRE1NIHR5cGVzIikgJT4lIA0KICBwdWxsKHJhdGlvKSAlPiUgbWVkaWFuDQoNCmBgYA0KDQoNCiMjIyMgRnByYXUgQmFjdGVyb2lkZXMgaW4gQlcNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTZ9DQoNCmZfYl9yYXRpbyAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsLiwgYnkueT0icm93Lm5hbWVzIiwgYnkueD0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiAgI2ZpbHRlcih2YWx1ZT4wLjgwKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIGZpbHRlcihicmFuY2hlcz09IkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIpICU+JSANCiAgI3B1bGwocmF0aW8pICU+JSBsb2cyKCkgJT4lIG1pY3JvYmlvbWU6OmJpbW9kYWxpdHkobWV0aG9kID0gIlNhcmxlLmZpbml0ZS5zYW1wbGUiLCBicy5pdGVyPTEwMCwgdmVyYm9zZT1UUlVFKQ0KICBnZ3Bsb3QoKSArIGdlb21fZGVuc2l0eShhZXMoeD1yYXRpbykpICsgDQogICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZzIiLCBsYWJlbHM9c2NhbGVzOjp0cmFuc19mb3JtYXQoImZyYWNfZnVuIixzY2FsZXM6OmxhYmVsX21hdGgoZXhwciA9IDEvLngsIGZvcm1hdCA9IGZvcmNlKSkpICsNCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDEvNSkgKyANCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgeGxhYigiRmFlY2FsaWJhY3Rlcml1bSBCYWN0ZXJvaWRlcyByYXRpb1xud2l0aGluIEJhY3Rlcm9pZGVzIGVucmljaGVkIGJyYW5jaCIpIC0+IHBfZnByYXVfZGVuc2l0eQ0KDQoNCg0KZl9iX3JhdGlvICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywuLCBieS55PSJyb3cubmFtZXMiLCBieS54PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICAjZmlsdGVyKHZhbHVlPjAuODApICU+JQ0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzPT0iQmFjdGVyb2lkZXMgRE1NIHR5cGVzIikgJT4lIA0KICBtdXRhdGUoRW50ZXJvdHlwZXNfaWQgPSBFbnRlcm90eXBlc19pZCAlPiUgYXMuY2hhcmFjdGVyKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXNfdGltZV9zZXJpZXNfc3RhYmlsaXR5LCBieT0iRW50ZXJvdHlwZXNfaWQiKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gRW50ZXJvdHlwZXNfaWQgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHN0YWJpbGl0eSkpICU+JQ0KICBncm91cF9ieShFbnRlcm90eXBlc19pZCkgJT4lDQogIG11dGF0ZShzdGFiaWxpdHkgPSBtZWRpYW4oc3RhYmlsaXR5KSkgJT4lDQogICNwdWxsKHJhdGlvKSAlPiUgbG9nMigpICU+JSBtaWNyb2Jpb21lOjpiaW1vZGFsaXR5KG1ldGhvZCA9ICJTYXJsZS5maW5pdGUuc2FtcGxlIiwgYnMuaXRlcj0xMDAsIHZlcmJvc2U9VFJVRSkNCiAgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QoYWVzKHg9cmF0aW8seT1FbnRlcm90eXBlc19pZCwgZmlsbD1zdGFiaWxpdHkpKSArDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMiIsIGxhYmVscz1zY2FsZXM6OnRyYW5zX2Zvcm1hdCgiZnJhY19mdW4iLHNjYWxlczo6bGFiZWxfbWF0aChleHByID0gMS8ueCwgZm9ybWF0ID0gZm9yY2UpKSkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0id2hpdGUiLGhpZ2g9ImJsYWNrIikgKw0KICAjZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS81KSArIA0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICB5bGFiKCJCYWN0ZXJvaWRlcyBETU0gcGFydGl0aW9ucyIpICsNCiAgeGxhYigiRmFlY2FsaWJhY3Rlcml1bSBCYWN0ZXJvaWRlcyByYXRpbyIpIC0+IHBfZnByYXVfcGFydGl0aW9uDQoNCg0KcF9mcHJhdV9kZW5zaXR5L3BfZnByYXVfcGFydGl0aW9uDQoNCg0KYGBgDQoNCg0KDQoNCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQoNCmZfYl9yYXRpbyAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsLiwgYnkueT0icm93Lm5hbWVzIiwgYnkueD0ic2FtcGxlX25hbWUiKSAlPiUNCiAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiAgI2ZpbHRlcih2YWx1ZT4wLjgwKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIGZpbHRlcihicmFuY2hlcz09IkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIpICU+JSANCiAgcHVsbChyYXRpbykgJT4lICBwb3RlbnRpYWxfYW5hbHlzaXMoeCwgYnMuaXRlciA9IDEwKQ0KICBnZ3Bsb3QoKSArIGdlb21fZGVuc2l0eShhZXMoeD1yYXRpbywgY29sb3I9dmFsdWU+MC44MCkpICsgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSJsb2cyIikNCg0KDQoNCg0KDQoNCmBgYA0KIyMjIGZfYl9yYXRpbyB2cyBhbHBoYQ0KDQpgYGB7cn0NCmZyYWNfZnVuPWZ1bmN0aW9uKHgpIDEveA0KDQpmX2JfcmF0aW8gJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLC4sIGJ5Lnk9InJvdy5uYW1lcyIsIGJ5Lng9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogICNmaWx0ZXIodmFsdWU+MC44MCkgJT4lDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXM9PSJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiKSAlPiUNCiAgbWVyZ2Uoc2hhbm5vbiwgYnkueD0ic2FtcGxlX25hbWUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgbXV0YXRlKHN1YnN0YXRlcyA9ICJIaWdoIChtMiwgbTQsIG04KSIpICU+JQ0KICBtdXRhdGUoc3Vic3RhdGVzID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkICVpbiUgYygiMTEiLCI2IiwiMTAiLCIzIiksICJNZWRpdW0gKG0zLCBtNiwgbTEwLCBtMTEpIixzdWJzdGF0ZXMpKSAlPiUNCiAgbXV0YXRlKHN1YnN0YXRlcyA9IGlmZWxzZShFbnRlcm90eXBlc19pZCAlaW4lIGMoIjE1IiksICJMb3cgKG0xNSkiLHN1YnN0YXRlcykpICU+JQ0KICBtdXRhdGUoc3Vic3RhdGVzID0gc3Vic3RhdGVzICU+JSBmb3JjYXRzOjpmY3RfcmVsZXZlbCgiSGlnaCAobTIsIG00LCBtOCkiLGFmdGVyPTIgKSkgJT4lDQogIGdncGxvdCgpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9cmF0aW8seT1zaGFubm9uLCBjb2w9c3Vic3RhdGVzKSwgYWxwaGE9MC41KSAgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKCJGYWVjYWxpYmFjdGVyaXVtOkJhY3Rlcm9pZGVzIHJhdGlvXG4gZnJvbSBzYW1wbGVzIGNsYXNzaWZpZWQgaW5cbkJhY3Rlcm9pZGVzIGVucmljaGVkIGJyYW5jaCIsdHJhbnM9ImxvZzIiLCBsYWJlbHM9c2NhbGVzOjp0cmFuc19mb3JtYXQoImZyYWNfZnVuIixzY2FsZXM6OmxhYmVsX21hdGgoZXhwciA9IDEvLngsIGZvcm1hdCA9IGZvcmNlKSkpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS80LCBjb2w9InJlZCIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS82NCwgY29sPSJyZWQiKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcigiTWljcm9iaW90YSBETU0gUGFydGl0aW9uc1xuY2xhc3NpZmllZCB0aGFuayB0b1xuRmFlY2FsaWJhY3Rlcml1bTpCYWN0ZXJvaWRlcyByYXRpbyIsIHBhbGV0dGUgPSA4LCB0eXBlPSJkaXYiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQoNCg0KDQpgYGANCiMjIyMgZl9iX3JhdGlvIHZzIGFscGhhIGluIEJXDQoNCg0KYGBge3J9DQoNCmZyYWNfZnVuPWZ1bmN0aW9uKHgpIDEveA0KDQpmX2JfcmF0aW8gJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLC4sIGJ5Lnk9InJvdy5uYW1lcyIsIGJ5Lng9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogICNmaWx0ZXIodmFsdWU+MC44MCkgJT4lDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXM9PSJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiKSAlPiUNCiAgbWVyZ2Uoc2hhbm5vbiwgYnkueD0ic2FtcGxlX25hbWUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgbXV0YXRlKHN1YnN0YXRlcyA9ICJIaWdoIChtMiwgbTQsIG04KSIpICU+JQ0KICBtdXRhdGUoc3Vic3RhdGVzID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkICVpbiUgYygiMTEiLCI2IiwiMTAiLCIzIiksICJNZWRpdW0gKG0zLCBtNiwgbTEwLCBtMTEpIixzdWJzdGF0ZXMpKSAlPiUNCiAgbXV0YXRlKHN1YnN0YXRlcyA9IGlmZWxzZShFbnRlcm90eXBlc19pZCAlaW4lIGMoIjE1IiksICJMb3cgKG0xNSkiLHN1YnN0YXRlcykpICU+JQ0KICBtdXRhdGUoc3Vic3RhdGVzID0gc3Vic3RhdGVzICU+JSBmb3JjYXRzOjpmY3RfcmVsZXZlbCgiSGlnaCAobTIsIG00LCBtOCkiLGFmdGVyPTIgKSkgJT4lDQogIGdncGxvdCgpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9cmF0aW8seT1zaGFubm9uLCBjb2w9c3Vic3RhdGVzKSwgYWxwaGE9MC43KSAgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKCJGYWVjYWxpYmFjdGVyaXVtOkJhY3Rlcm9pZGVzIHJhdGlvXG4gZnJvbSBzYW1wbGVzIGNsYXNzaWZpZWQgaW5cbkJhY3Rlcm9pZGVzIGVucmljaGVkIGJyYW5jaCIsdHJhbnM9ImxvZzIiLCBsYWJlbHM9c2NhbGVzOjp0cmFuc19mb3JtYXQoImZyYWNfZnVuIixzY2FsZXM6OmxhYmVsX21hdGgoZXhwciA9IDEvLngsIGZvcm1hdCA9IGZvcmNlKSkpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS80LCBjb2w9ImJsYWNrIiwgbGluZXR5cGU9Miwgc2l6ZT0xLjUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS82NCwgY29sPSJibGFjayIsIGxpbmV0eXBlPTIsIHNpemU9MS41KSArDQogIHNjYWxlX2NvbG91cl9ncmV5KCJNaWNyb2Jpb3RhIERNTSBQYXJ0aXRpb25zXG5jbGFzc2lmaWVkIHRoYW5rIHRvXG5GYWVjYWxpYmFjdGVyaXVtOkJhY3Rlcm9pZGVzIHJhdGlvIikgKw0KICAjc2NhbGVfY29sb3JfYnJld2VyKCJNaWNyb2Jpb3RhIERNTSBQYXJ0aXRpb25zXG5jbGFzc2lmaWVkIHRoYW5rIHRvXG5GYWVjYWxpYmFjdGVyaXVtOkJhY3Rlcm9pZGVzIHJhdGlvIiwgcGFsZXR0ZSA9IDgsIHR5cGU9ImRpdiIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KDQoNCmBgYA0KDQoNCg0KDQojIyMgcHJldm90ZWxsYSBiYWN0ZXJvaWRlcyByYXRpbw0KDQpgYGB7cn0NCg0KDQpmX0dHID0gImtfX0JhY3RlcmlhO3BfX0Zpcm1pY3V0ZXM7Y19fQ2xvc3RyaWRpYTtvX19DbG9zdHJpZGlhbGVzO2ZfX1J1bWlub2NvY2NhY2VhZTtnX19GYWVjYWxpYmFjdGVyaXVtIg0KYl9HRyA9ICJrX19CYWN0ZXJpYTtwX19CYWN0ZXJvaWRldGVzO2NfX0JhY3Rlcm9pZGlhO29fX0JhY3Rlcm9pZGFsZXM7Zl9fQmFjdGVyb2lkYWNlYWU7Z19fQmFjdGVyb2lkZXMiDQpwX0dHID0gImtfX0JhY3RlcmlhO3BfX0JhY3Rlcm9pZGV0ZXM7Y19fQmFjdGVyb2lkaWE7b19fQmFjdGVyb2lkYWxlcztmX19QcmV2b3RlbGxhY2VhZTtnX19QcmV2b3RlbGxhIg0KDQpnZW51cyAlPiUNCiAgZmlsdGVyKHRheGEgJWluJSBjKGJfR0cscF9HRykpICU+JQ0KICB0aWJibGU6OmNvbHVtbl90b19yb3duYW1lcygidGF4YSIpICU+JQ0KICB0ICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIGRwbHlyOjpyZW5hbWUoUHJldm90ZWxsYT0yLEJhY3Rlcm9pZGVzPTEpICU+JQ0KICBtdXRhdGUocmF0aW89KFByZXZvdGVsbGErMSkvKEJhY3Rlcm9pZGVzKzEpKSAtPiBwX2JfcmF0aW8NCg0KDQpwX2JfcmF0aW8gJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLC4sIGJ5Lnk9InJvdy5uYW1lcyIsIGJ5Lng9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogICNmaWx0ZXIodmFsdWU+MC44MCkgJT4lDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXM9PSJQcmV2b3RlbGxhIERNTSB0eXBlcyIpICU+JSANCiAgI3B1bGwocmF0aW8pICU+JSBsb2cyKCkgJT4lIG1hZ3JpdHRyOjphZGQoMTAwKSAlPiUgZGlwdGVzdDo6ZGlwKCkNCiAgZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8pKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMiIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNCkgKyBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICB4bGFiKCJQcmV2b3RlbGxhIEJhY3Rlcm9pZGVzIHJhdGlvXG53aXRoaW4gUHJldm90ZWxsYSBlbnJpY2hlZCBicmFuY2giKQ0KDQoNCg0KcF9iX3JhdGlvICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywuLCBieS55PSJyb3cubmFtZXMiLCBieS54PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICAjZmlsdGVyKHZhbHVlPjAuODApICU+JQ0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzPT0iUHJldm90ZWxsYSBETU0gdHlwZXMiKSAlPiUgDQogICNwdWxsKHJhdGlvKSAlPiUgbG9nMiAlPiUgZGlwdGVzdDo6ZGlwLnRlc3QoKQ0KICBnZ3Bsb3QoKSArIGdlb21fZGVuc2l0eShhZXMoeD1yYXRpbykpICsgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSJsb2cyIikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAzKSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArDQogIHhsYWIoIlByZXZvdGVsbGEgQmFjdGVyb2lkZXMgcmF0aW9cbndpdGhpbiBCYWN0ZXJvaWRlcyBlbnJpY2hlZCBicmFuY2giKSAtPiBwX3ByZXZvdGVsbGFfZGVuc2l0eQ0KDQoNCiBwX2JfcmF0aW8gJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLC4sIGJ5Lnk9InJvdy5uYW1lcyIsIGJ5Lng9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogICNmaWx0ZXIodmFsdWU+MC44MCkgJT4lDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXM9PSJQcmV2b3RlbGxhIERNTSB0eXBlcyIpICU+JSANCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlcikgJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzX3RpbWVfc2VyaWVzX3N0YWJpbGl0eSwgYnk9IkVudGVyb3R5cGVzX2lkIikgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihzdGFiaWxpdHkpKSAlPiUNCiAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWQpICU+JQ0KICBtdXRhdGUoc3RhYmlsaXR5ID0gbWVkaWFuKHN0YWJpbGl0eSkpICU+JQ0KICAgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QoYWVzKHg9cmF0aW8seT1FbnRlcm90eXBlc19pZCwgZmlsbD1zdGFiaWxpdHkpKSArDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMiIpICsNCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKHR5cGU9InZpcmlkaXMiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDMpICsgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgeGxhYigiUHJldm90ZWxsYSBCYWN0ZXJvaWRlcyByYXRpbyIpICsNCiAgIHlsYWIoIlByZXZvdGVsbGEgRE1NIHR5cGVzIikgLT4gcF9wcmV2b3RlbGxhX3BhcnRpdGlvbg0KICANCiANCiANCiANCnBfcHJldm90ZWxsYV9kZW5zaXR5IC8gcF9wcmV2b3RlbGxhX3BhcnRpdGlvbg0KIA0KICBwX2JfcmF0aW8gJT4lDQogIG1lcmdlKGVudGVyb3R5cGVzLC4sIGJ5Lnk9InJvdy5uYW1lcyIsIGJ5Lng9InNhbXBsZV9uYW1lIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogICNmaWx0ZXIodmFsdWU+MC44MCkgJT4lDQogIG11dGF0ZShicmFuY2hlcyA9IGNhc2Vfd2hlbihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTgsMTQsMTYsMTcsNykgfiAiUHJldm90ZWxsYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDExLDE1LDYsOCwxMCwzLDQsMikgfiAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMiwxLDUsOSkgfiAiQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEzKSB+ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdXRsaWVycyIpDQogICAgICAgICApICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXM9PSJQcmV2b3RlbGxhIERNTSB0eXBlcyIpICU+JSBwdWxsKHJhdGlvKSAlPiUgbWVkaWFuDQogICAgDQogIA0KYGBgDQoNCiMjIGYvYiBwL2IgcmF0aW8gZmlndXJlDQpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0NCg0KcF9mcHJhdV9kZW5zaXR5IC8gcF9mcHJhdV9wYXJ0aXRpb258cF9wcmV2b3RlbGxhX2RlbnNpdHkgLyBwX3ByZXZvdGVsbGFfcGFydGl0aW9uDQoNCmBgYA0KDQoNCiMjIE0xNCBNMTgNCg0KDQoNCmBgYHtyfQ0KDQojY29tcHV0ZSBwcmV2b3RlbGxhL2JhY3Rlcm9pZGVzIHJhdGlvIGFuZCBtZXJnZQ0KDQpmX0dHID0gImtfX0JhY3RlcmlhO3BfX0Zpcm1pY3V0ZXM7Y19fQ2xvc3RyaWRpYTtvX19DbG9zdHJpZGlhbGVzO2ZfX1J1bWlub2NvY2NhY2VhZTtnX19GYWVjYWxpYmFjdGVyaXVtIg0KYl9HRyA9ICJrX19CYWN0ZXJpYTtwX19CYWN0ZXJvaWRldGVzO2NfX0JhY3Rlcm9pZGlhO29fX0JhY3Rlcm9pZGFsZXM7Zl9fQmFjdGVyb2lkYWNlYWU7Z19fQmFjdGVyb2lkZXMiDQpwX0dHID0gImtfX0JhY3RlcmlhO3BfX0JhY3Rlcm9pZGV0ZXM7Y19fQmFjdGVyb2lkaWE7b19fQmFjdGVyb2lkYWxlcztmX19QcmV2b3RlbGxhY2VhZTtnX19QcmV2b3RlbGxhIg0KDQoNCmdlbnVzICU+JQ0KICBmaWx0ZXIodGF4YSAlaW4lIGMoYl9HRyxwX0dHKSkgJT4lDQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJ0YXhhIikgJT4lDQogIHQgJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgZHBseXI6OnJlbmFtZShQcmV2b3RlbGxhPTIsQmFjdGVyb2lkZXM9MSkgJT4lDQogIG11dGF0ZShyYXRpbz0oUHJldm90ZWxsYSsxKS8oQmFjdGVyb2lkZXMrMSkpIC0+IHBfYl9yYXRpbw0KDQoNCiMgbWV0YWRhdGEgJT4lDQojICAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KIyAgIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiMgICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRldGltZSgpKSAlPiUNCiMgICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KIyAgIG1lcmdlKHNoYW5ub24sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQojICAgZmlsdGVyKHNldCAhPSAib3V0bGllcnMiKSAlPiUNCiMgICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KIyAgIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQojICAgbXV0YXRlKG1pbl9kYXRlID0gbWluKENPTExFQ1RJT05fVElNRVNUQU1QKSwgbj1uKCkpICU+JQ0KIyAgIGZpbHRlcihuPjEpICU+JQ0KIyAgIA0KIyAgIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiMgICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KIyAgIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiMgICBtdXRhdGUoc2FtcGxlX29yZGVyPW9yZGVyKENPTExFQ1RJT05fVElNRVNUQU1QKSkgJT4lDQojICAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICVpbiUgYygyLDYpKSAlPiUNCiMgICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD1kYXlzLHk9c2hhbm5vbixncm91cD1IT1NUX1NVQkpFQ1RfSUQsIGNvbD1hcy5jaGFyYWN0ZXIoRW50ZXJvdHlwZXNfaWQpKSkgDQogIA0KDQptZXRhZGF0YSAlPiUNCiAgZmlsdGVyKFNBTVBMRV9UWVBFID09ICJTdG9vbCIpICU+JQ0KICBzZWxlY3QoSE9TVF9TVUJKRUNUX0lELFNBTVBMRV9OQU1FLCBDT0xMRUNUSU9OX1RJTUVTVEFNUCkgJT4lDQogIA0KICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRldGltZSgpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMsIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0ic2FtcGxlX25hbWUiKSAlPiUNCiAgbWVyZ2Uoc2hhbm5vbiwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgbWVyZ2UocF9iX3JhdGlvLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQogIGZpbHRlcihuPjEpICU+JQ0KICANCiAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KICANCiAgDQogIGZpbHRlcihkYXlzID09IDAgfCBkYXlzID4gNjAqNjAqMjQpICU+JQ0KICANCiAgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lELCBkYXlzKSAlPiUNCiAgbXV0YXRlKHNhbXBsZV9vcmRlcj1vcmRlcihDT0xMRUNUSU9OX1RJTUVTVEFNUCkpICU+JSANCiAgDQoNCiAgbXV0YXRlKGJyYW5jaGVzID0gY2FzZV93aGVuKEVudGVyb3R5cGVzX2lkICVpbiUgYygxOCwxNCwxNiwxNyw3KSB+ICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTEsMTUsNiw4LDEwLDMsNCwyKSB+ICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50ZXJvdHlwZXNfaWQgJWluJSBjKDEyLDEsNSw5KSB+ICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTMpIH4gIkFra2VybWFuc2lhIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm91dGxpZXJzIikNCiAgICAgICAgICkgJT4lDQogIA0KICBtdXRhdGUoZGF5c18wPWJyYW5jaGVzW3doaWNoLm1pbihzYW1wbGVfb3JkZXIpXSkgJT4lDQogICNhcnJhbmdlKEhPU1RfU1VCSkVDVF9JRCkgICU+JSANCiAgI211dGF0ZShzYW1wbGVfb3JkZXI9cmFuayhkYXlzKSkgJT4lDQogIG11dGF0ZShkYXlzID0gYXMubnVtZXJpYyhkYXlzKSkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSwgSE9TVF9TVUJKRUNUX0lELCBkYXlzLCBzYW1wbGVfb3JkZXIsIGJyYW5jaGVzLCBFbnRlcm90eXBlc19pZCwgc2hhbm5vbiwgcmF0aW8pICU+JQ0KICBtdXRhdGUoRW50ZXJvdHlwZXNfaWQgPSBFbnRlcm90eXBlc19pZCAlPiUgYXMuY2hhcmFjdGVyICkgJT4lIA0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUoc2FtZV9icmFuY2hlc19sYWcgPSBpZmVsc2UoYnJhbmNoZXMgPT0gbGFnKGJyYW5jaGVzKSwgInllcyIsIm5vIiksIA0KICAgICAgICAgYnJhbmNoZXNfYmVmb3JlPWxhZyhicmFuY2hlcyksIGRheXNfZGVsdGE9IGRheXMgLSBsYWcoZGF5cyksIA0KICAgICAgICAgRW50ZXJvdHlwZXNfaWRfYmVmb3JlID0gbGFnKEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIpLA0KICAgICAgICAgc2hhbm5vbl9iZWZvcmUgPSBsYWcoc2hhbm5vbiksDQogICAgICAgICByYXRpb19iZWZvcmUgPSBsYWcocmF0aW8pKSAlPiUNCiAgZmlsdGVyKHNhbXBsZV9vcmRlciA+MSkgJT4lDQogIG11dGF0ZShicmFuY2hlc19wYWlycz1wYXN0ZTAoYnJhbmNoZXNfYmVmb3JlLCItIixicmFuY2hlcykpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE0LDE4KSwgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygxNCwxOCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLHJhdGlvLCBFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHJhdGlvX2JlZm9yZSkgJT4lDQogIG11dGF0ZShzd2l0Y2g9cGFzdGUoRW50ZXJvdHlwZXNfaWQsRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSkgLT4gZGYNCg0KZGYgJT4lDQogIG11dGF0ZShkZWx0YV9yYXRpbyA9IGFicyhsb2cyKHJhdGlvX2JlZm9yZSkgLSBsb2cyKHJhdGlvKSkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYm94cGxvdChhZXMoeD1zd2l0Y2gseT1kZWx0YV9yYXRpbykpICsgDQogIHlsYWIoIkZhZWNhbGliYWN0ZXJpdW0vQmFjdGVyb2lkZXNcbnJhdGlvIHZhcmlhdGlvbiIpICsgDQogIHhsYWIoIiIpICsgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsgDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWw9Yygid2l0aGluXG5wYXJ0aXRpb24gTTE0IiwiYmV0d2VlblxuZnJvbSBNMTQgdG8gTTE4IiwiYmV0d2VlblxuZnJvbSBNMTQgdG8gTTE4Iiwid2l0aGluXG5wYXJ0aXRpb24gTTE4IikpIC0+IGZpZzVIDQoNCmZpZzVIDQoNCmRmICU+JQ0KICBtdXRhdGUoZGVsdGFfcmF0aW8gPSBhYnMobG9nMihyYXRpb19iZWZvcmUpIC0gbG9nMihyYXRpbykpKSAlPiUNCiAgd2l0aCguLHBhaXJ3aXNlLndpbGNveC50ZXN0KGRlbHRhX3JhdGlvLHN3aXRjaCwgZGF0YT0uKSkNCg0KDQpyYmluZChkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCwgcmF0aW8pICwNCiAgICAgIGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub25fYmVmb3JlLCBzd2l0Y2gsIHJhdGlvX2JlZm9yZSkgJT4lIGRwbHlyOjpyZW5hbWUoRW50ZXJvdHlwZXNfaWQ9RW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub249c2hhbm5vbl9iZWZvcmUsIHJhdGlvPXJhdGlvX2JlZm9yZSkpICU+JSANCiAgICAgICAgbXV0YXRlKFNBTVBMRV9OQU1FID0gU0FNUExFX05BTUUgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCIxOCAxOCIpLCAic3RhYmxlIiwidW5zdGFibGUiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCIxNCAxNCIsIjE0IDE4IiksICJNMTQiLCJNMTgiKSAgKSAlPiUNCiAgI2FycmFuZ2Uoc3dpdGNoKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9cmF0aW8seT1TQU1QTEVfTkFNRSwgZ3JvdXA9U0FNUExFX05BTUUsIGNvbD1zdGFibGUpKSAgKyB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMiIpICsgDQogICNmYWNldF93cmFwKH5zd2l0Y2gsIG5jb2w9MSwgc2NhbGU9ImZyZWVfeSIpICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgeWxhYigiQUdQIHBhcnRpY2lwYW50cyIpICsgeGxhYigiRmFlY2FsaWJhY3Rlcml1bS9cbkJhY3Rlcm9pZGVzIHJhdGlvIikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwoIiIsIHZhbHVlcz1jKCJibGFjayIsInJlZCIpLCBsYWJlbD1jKCJzdGFibGUiLCJ1bnN0YWJsZSIpKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIGZhY2V0X2dyaWQoc3RhcnRfcGFydGl0aW9ufi4sIHNjYWxlcyA9ICJmcmVlX3kiKQ0KDQoNCnJiaW5kKGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoLCByYXRpbykgLA0KICAgICAgZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHN3aXRjaCwgcmF0aW9fYmVmb3JlKSAlPiUgZHBseXI6OnJlbmFtZShFbnRlcm90eXBlc19pZD1FbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbj1zaGFubm9uX2JlZm9yZSwgcmF0aW89cmF0aW9fYmVmb3JlKSkgJT4lIA0KICAgICAgICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoc2hhbm5vbikpICU+JQ0KICBtdXRhdGUoc3RhYmxlID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjE0IDE0IiwiMTggMTgiKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogICNmaWx0ZXIoc3RhYmxlID09ICJzdGFibGUiKSAlPiUNCiAgZ2dwbG90KCkgKyANCiAgZ2VvbV9wb2ludChhZXMoeD1yYXRpbyx5PXNoYW5ub24sY29sPXN3aXRjaCkpKyANCiAgZ2VvbV9saW5lKGFlcyh4PXJhdGlvLHk9c2hhbm5vbixncm91cD1TQU1QTEVfTkFNRSAsY29sPXN3aXRjaCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzIiKSArIGZhY2V0X3dyYXAofnN0YWJsZSkNCg0KDQoNCg0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBtZXJnZShwX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihFbnRlcm90eXBlc19pZCU+JWFzLm51bWVyaWMpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8sIGZpbGw9c3dpdGNoKSwgYWxwaGE9MC41KSAgKyB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMiIpDQoNCmRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgbWVyZ2UocF9iX3JhdGlvLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoRW50ZXJvdHlwZXNfaWQlPiVhcy5udW1lcmljKSkgJT4lDQogIGdncGxvdCgpICsgDQogICNnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8pLCBhbHBoYT0wLjUpICArIA0KICBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8sIGNvbG9yPXN3aXRjaCksIGFscGhhPTAuNSkgICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikNCg0KIyBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQojICAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjIgMiIsICIyIDYiKSkgJT4lDQojICAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiMgICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KIyAgIGdncGxvdCgpICsgZ2VvbV9ib3hwbG90KGFlcyh4PXN3aXRjaCwgeT12YWx1ZSkpICsgZmFjZXRfd3JhcCh+dmFyaWFibGUsIHNjYWxlPSJmcmVlIikNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIxNCAxNCIsICIxNCAxOCIpKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQ9YygiU0FNUExFX05BTUUiLCJFbnRlcm90eXBlc19pZCIsInN3aXRjaCIpKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICB0aWR5cjo6bmVzdCgpICAlPiUgDQogIG11dGF0ZSh3aWxjb3hfdGVzdD1wdXJycjo6bWFwKGRhdGEsfndpbGNveC50ZXN0KC54JHZhbHVlfi54JHN3aXRjaCkpLA0KICAgICAgICB0aWR5PXB1cnJyOjptYXAod2lsY294X3Rlc3QsIGJyb29tOjp0aWR5KSkgJT4lIA0KICAgICAgdGlkeXI6OnVubmVzdCh0aWR5LC5kcm9wPVRSVUUpICU+JQ0KICBhcnJhbmdlKHAudmFsdWUpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogICNtdXRhdGUocC52YWx1ZT1wLmFkanVzdChwLnZhbHVlLCBtZXRob2Q9ImZkciIpKSAlPiUNCiAgZmlsdGVyKHAudmFsdWU8MC4wNSkgJT4lIHNlbGVjdCh2YXJpYWJsZSxwLnZhbHVlKSAlPiUgd3JpdGUuY3N2MihmaWxlPSJtZXRhZGF0YV9saW5rXzE0MTR2czE0MTguY3N2IikNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIxOCAxOCIsICIxOCAxNCIpKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQ9YygiU0FNUExFX05BTUUiLCJFbnRlcm90eXBlc19pZCIsInN3aXRjaCIpKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICB0aWR5cjo6bmVzdCgpICAlPiUgDQogIG11dGF0ZSh3aWxjb3hfdGVzdD1wdXJycjo6bWFwKGRhdGEsfndpbGNveC50ZXN0KC54JHZhbHVlfi54JHN3aXRjaCkpLA0KICAgICAgICB0aWR5PXB1cnJyOjptYXAod2lsY294X3Rlc3QsIGJyb29tOjp0aWR5KSkgJT4lIA0KICAgICAgdGlkeXI6OnVubmVzdCh0aWR5LC5kcm9wPVRSVUUpICU+JQ0KICBhcnJhbmdlKHAudmFsdWUpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogICNtdXRhdGUocC52YWx1ZT1wLmFkanVzdChwLnZhbHVlLCBtZXRob2Q9ImZkciIpKSU+JQ0KICBmaWx0ZXIocC52YWx1ZTwwLjA1KSAlPiUgc2VsZWN0KHZhcmlhYmxlLHAudmFsdWUpICU+JSB3cml0ZS5jc3YyKGZpbGU9Im1ldGFkYXRhX2xpbmtfMTgxOHZzMTgxNC5jc3YiKQ0KDQoNCmRmICU+JQ0KICBtdXRhdGUoZGVsdGFfcmF0aW8gPSBhYnMobG9nMihyYXRpb19iZWZvcmUpIC0gbG9nMihyYXRpbykpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyh4PWxvZzIocmF0aW9fYmVmb3JlKSAtIGxvZzIocmF0aW8pLHk9bG9nMihzaGFubm9uX2JlZm9yZS9zaGFubm9uKSwgY29sb3I9c3dpdGNoKSkgKw0KICB4bGltKC00LDQpICsgeWxpbSgtMC41LCAwLjUpICsgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsgc2NhbGVfY29sb3JfYnJld2VyKCIiLCB0eXBlPSJxdWFsIiwgcGFsZXR0ZSA9IDIpICsNCiAgeGxhYigiUHJldm90ZWxsYS9CYWN0ZXJvaWRlcyB2YXJpYXRpb24iKSArIHlsYWIoImFscGhhLWRpdmVyc2l0eSB2YXJpYXRpb24iKSAtPiBmaWdTMTFBDQoNCg0KDQoNCnJiaW5kKGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoLCByYXRpbykgLA0KICAgICAgZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHN3aXRjaCwgcmF0aW9fYmVmb3JlKSAlPiUgZHBseXI6OnJlbmFtZShFbnRlcm90eXBlc19pZD1FbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbj1zaGFubm9uX2JlZm9yZSwgcmF0aW89cmF0aW9fYmVmb3JlKSkgJT4lIA0KICAgICAgICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8pKSAlPiUNCiAgbXV0YXRlKHN0YWJsZSA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCIxNCAxNCIsIjE4IDE4IiksICJzdGFibGUiLCJ1bnN0YWJsZSIpICApICU+JQ0KICBtdXRhdGUoc3RhcnRfcGFydGl0aW9uID0gaWZlbHNlKHN3aXRjaCAlaW4lIGMoIjE0IDE0IiwiMTQgMTgiKSwgIk0xNCIsIk0xOCIpICApICU+JQ0KICBtdXRhdGUoc3RhcnRfcGFydGl0aW9uID0gc3RhcnRfcGFydGl0aW9uICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihyYXRpbywgLmRlc2M9VFJVRSkpICU+JQ0KICAjYXJyYW5nZShzd2l0Y2gpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD1yYXRpbyx5PVNBTVBMRV9OQU1FLCBncm91cD1TQU1QTEVfTkFNRSwgY29sPXN0YWJsZSkpICArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikgKyANCiAgI2ZhY2V0X3dyYXAofnN3aXRjaCwgbmNvbD0xLCBzY2FsZT0iZnJlZV95IikgKw0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICB5bGFiKCJBR1AgcGFydGljaXBhbnRzIikgKyB4bGFiKCJQcmV2b3RlbGxhL1xuQmFjdGVyb2lkZXMgcmF0aW8iKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgiIiwgdmFsdWVzPWMoImJsYWNrIiwicmVkIiksIGxhYmVsPWMoInN0YWJsZSIsInVuc3RhYmxlIikpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgZmFjZXRfZ3JpZChzdGFydF9wYXJ0aXRpb25+Liwgc2NhbGVzID0gImZyZWVfeSIpIC0+IGZpZzVIX2Z1bGwNCg0KDQpkZiAlPiUNCiAgbXV0YXRlKGRlbHRhX3JhdGlvID0gYWJzKGxvZzIocmF0aW9fYmVmb3JlKSAtIGxvZzIocmF0aW8pKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCIxOCAxOCIpLCAic3RhYmxlIiwidW5zdGFibGUiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IGlmZWxzZShzd2l0Y2ggJWluJSBjKCIxNCAxNCIsIjE0IDE4IiksICJNMTQiLCJNMTgiKSAgKSAlPiUNCiAgbXV0YXRlKHN0YXJ0X3BhcnRpdGlvbiA9IHN0YXJ0X3BhcnRpdGlvbiAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocmF0aW8sIC5kZXNjPVRSVUUpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QoYWVzKHg9c3RhcnRfcGFydGl0aW9uLHk9ZGVsdGFfcmF0aW8sIGNvbD1zdGFibGUpKSArIA0KICB5bGFiKCJQcmV2b3RlbGxhL0JhY3Rlcm9pZGVzXG5yYXRpbyB2YXJpYXRpb24iKSArIA0KICAjc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSJsb2cyIikgKw0KICB4bGFiKCIiKSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArIHNjYWxlX2NvbG9yX21hbnVhbCgiIix2YWx1ZXM9YygiYmxhY2siLCJyZWQiKSkgLT4gZmlnNUhpbnNldA0KDQoNCmZpZzVIID0gZmlnNUhfZnVsbCArIGluc2V0X2VsZW1lbnQoZmlnNUhpbnNldCt5bGFiKCJ2YXJpYXRpb24iKStndWlkZXMoY29sb3I9RkFMU0UpLCAwLjY1LC0wLjEsMSwwLjMsIGlnbm9yZV90YWcgPSBUUlVFKQ0KDQpmaWc1SA0KDQoNCg0KDQpgYGANCg0KDQojIyBNNyBNMTQNCg0KDQoNCg0KYGBge3J9DQoNCiNjb21wdXRlIHByZXZvdGVsbGEvYmFjdGVyb2lkZXMgcmF0aW8gYW5kIG1lcmdlDQoNCmZfR0cgPSAia19fQmFjdGVyaWE7cF9fRmlybWljdXRlcztjX19DbG9zdHJpZGlhO29fX0Nsb3N0cmlkaWFsZXM7Zl9fUnVtaW5vY29jY2FjZWFlO2dfX0ZhZWNhbGliYWN0ZXJpdW0iDQpiX0dHID0gImtfX0JhY3RlcmlhO3BfX0JhY3Rlcm9pZGV0ZXM7Y19fQmFjdGVyb2lkaWE7b19fQmFjdGVyb2lkYWxlcztmX19CYWN0ZXJvaWRhY2VhZTtnX19CYWN0ZXJvaWRlcyINCnBfR0cgPSAia19fQmFjdGVyaWE7cF9fQmFjdGVyb2lkZXRlcztjX19CYWN0ZXJvaWRpYTtvX19CYWN0ZXJvaWRhbGVzO2ZfX1ByZXZvdGVsbGFjZWFlO2dfX1ByZXZvdGVsbGEiDQoNCg0KZ2VudXMgJT4lDQogIGZpbHRlcih0YXhhICVpbiUgYyhiX0dHLHBfR0cpKSAlPiUNCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoInRheGEiKSAlPiUNCiAgdCAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICBkcGx5cjo6cmVuYW1lKFByZXZvdGVsbGE9MixCYWN0ZXJvaWRlcz0xKSAlPiUNCiAgbXV0YXRlKHJhdGlvPShQcmV2b3RlbGxhKzEpLyhCYWN0ZXJvaWRlcysxKSkgLT4gcF9iX3JhdGlvDQoNCg0KIyBtZXRhZGF0YSAlPiUNCiMgICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQojICAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KIyAgIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KIyAgIG1lcmdlKGVudGVyb3R5cGVzLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InNhbXBsZV9uYW1lIikgJT4lDQojICAgbWVyZ2Uoc2hhbm5vbiwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiMgICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KIyAgIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQojICAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiMgICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQojICAgZmlsdGVyKG4+MSkgJT4lDQojICAgDQojICAgbXV0YXRlKGRheXM9Q09MTEVDVElPTl9USU1FU1RBTVAgLSBtaW5fZGF0ZSkgJT4lIA0KIyAgIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQojICAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQsIGRheXMpICU+JQ0KIyAgIG11dGF0ZShzYW1wbGVfb3JkZXI9b3JkZXIoQ09MTEVDVElPTl9USU1FU1RBTVApKSAlPiUNCiMgICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgJWluJSBjKDIsNikpICU+JQ0KIyAgIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PWRheXMseT1zaGFubm9uLGdyb3VwPUhPU1RfU1VCSkVDVF9JRCwgY29sPWFzLmNoYXJhY3RlcihFbnRlcm90eXBlc19pZCkpKSANCiAgDQoNCm1ldGFkYXRhICU+JQ0KICBmaWx0ZXIoU0FNUExFX1RZUEUgPT0gIlN0b29sIikgJT4lDQogIHNlbGVjdChIT1NUX1NVQkpFQ1RfSUQsU0FNUExFX05BTUUsIENPTExFQ1RJT05fVElNRVNUQU1QKSAlPiUNCiAgDQogIG11dGF0ZShDT0xMRUNUSU9OX1RJTUVTVEFNUCA9IENPTExFQ1RJT05fVElNRVNUQU1QICU+JSBsdWJyaWRhdGU6OmFzX2RhdGV0aW1lKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBtZXJnZShzaGFubm9uLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBtZXJnZShwX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIGZpbHRlcihzZXQgIT0gIm91dGxpZXJzIikgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAhPSAxOSkgJT4lDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShtaW5fZGF0ZSA9IG1pbihDT0xMRUNUSU9OX1RJTUVTVEFNUCksIG49bigpKSAlPiUNCiAgZmlsdGVyKG4+MSkgJT4lDQogIA0KICBtdXRhdGUoZGF5cz1DT0xMRUNUSU9OX1RJTUVTVEFNUCAtIG1pbl9kYXRlKSAlPiUgDQogIA0KICANCiAgZmlsdGVyKGRheXMgPT0gMCB8IGRheXMgPiA2MCo2MCoyNCkgJT4lDQogIA0KICANCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQsIGRheXMpICU+JQ0KICBtdXRhdGUoc2FtcGxlX29yZGVyPW9yZGVyKENPTExFQ1RJT05fVElNRVNUQU1QKSkgJT4lIA0KICANCg0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzXzA9YnJhbmNoZXNbd2hpY2gubWluKHNhbXBsZV9vcmRlcildKSAlPiUNCiAgI2FycmFuZ2UoSE9TVF9TVUJKRUNUX0lEKSAgJT4lIA0KICAjbXV0YXRlKHNhbXBsZV9vcmRlcj1yYW5rKGRheXMpKSAlPiUNCiAgbXV0YXRlKGRheXMgPSBhcy5udW1lcmljKGRheXMpKSAlPiUNCiAgc2VsZWN0KFNBTVBMRV9OQU1FLCBIT1NUX1NVQkpFQ1RfSUQsIGRheXMsIHNhbXBsZV9vcmRlciwgYnJhbmNoZXMsIEVudGVyb3R5cGVzX2lkLCBzaGFubm9uLCByYXRpbykgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIgKSAlPiUgDQogIGdyb3VwX2J5KEhPU1RfU1VCSkVDVF9JRCkgJT4lDQogIG11dGF0ZShzYW1lX2JyYW5jaGVzX2xhZyA9IGlmZWxzZShicmFuY2hlcyA9PSBsYWcoYnJhbmNoZXMpLCAieWVzIiwibm8iKSwgDQogICAgICAgICBicmFuY2hlc19iZWZvcmU9bGFnKGJyYW5jaGVzKSwgZGF5c19kZWx0YT0gZGF5cyAtIGxhZyhkYXlzKSwgDQogICAgICAgICBFbnRlcm90eXBlc19pZF9iZWZvcmUgPSBsYWcoRW50ZXJvdHlwZXNfaWQgJT4lIGFzLmNoYXJhY3RlciksDQogICAgICAgICBzaGFubm9uX2JlZm9yZSA9IGxhZyhzaGFubm9uKSwNCiAgICAgICAgIHJhdGlvX2JlZm9yZSA9IGxhZyhyYXRpbykpICU+JQ0KICBmaWx0ZXIoc2FtcGxlX29yZGVyID4xKSAlPiUNCiAgbXV0YXRlKGJyYW5jaGVzX3BhaXJzPXBhc3RlMChicmFuY2hlc19iZWZvcmUsIi0iLGJyYW5jaGVzKSkgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAlaW4lIGMoMTQsNyksIEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoMTQsNykpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLHJhdGlvLCBFbnRlcm90eXBlc19pZF9iZWZvcmUsc2hhbm5vbl9iZWZvcmUsIHJhdGlvX2JlZm9yZSkgJT4lDQogIG11dGF0ZShzd2l0Y2g9cGFzdGUoRW50ZXJvdHlwZXNfaWQsRW50ZXJvdHlwZXNfaWRfYmVmb3JlKSkgLT4gZGYNCg0KZGYgJT4lDQogIG11dGF0ZShkZWx0YV9yYXRpbyA9IGFicyhsb2cyKHJhdGlvX2JlZm9yZSkgLSBsb2cyKHJhdGlvKSkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYm94cGxvdChhZXMoeD1zd2l0Y2gseT1kZWx0YV9yYXRpbykpICsgDQogIHlsYWIoIlByZXZvdGVsbGEvQmFjdGVyb2lkZXNcbnJhdGlvIHZhcmlhdGlvbiIpICsgDQogIHhsYWIoIiIpICsgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsgDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWw9Yygid2l0aGluXG5wYXJ0aXRpb24gTTE0IiwiYmV0d2VlblxuZnJvbSBNMTQgdG8gTTciLCJiZXR3ZWVuXG5mcm9tIE0xNCB0byBNNyIsIndpdGhpblxucGFydGl0aW9uIE03IikpIC0+IGZpZzVJDQoNCmZpZzVJDQoNCmRmICU+JQ0KICBtdXRhdGUoZGVsdGFfcmF0aW8gPSBhYnMobG9nMihyYXRpb19iZWZvcmUpIC0gbG9nMihyYXRpbykpKSAlPiUNCiAgd2l0aCguLHBhaXJ3aXNlLndpbGNveC50ZXN0KGRlbHRhX3JhdGlvLHN3aXRjaCwgZGF0YT0uKSkNCg0KDQpyYmluZChkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCwgcmF0aW8pICwNCiAgICAgIGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub25fYmVmb3JlLCBzd2l0Y2gsIHJhdGlvX2JlZm9yZSkgJT4lIGRwbHlyOjpyZW5hbWUoRW50ZXJvdHlwZXNfaWQ9RW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub249c2hhbm5vbl9iZWZvcmUsIHJhdGlvPXJhdGlvX2JlZm9yZSkpICU+JSANCiAgICAgICAgbXV0YXRlKFNBTVBMRV9OQU1FID0gU0FNUExFX05BTUUgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCI3IDciKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCIxNCA3IiksICJNMTQiLCJNNyIpICApICU+JQ0KICAjYXJyYW5nZShzd2l0Y2gpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD1yYXRpbyx5PVNBTVBMRV9OQU1FLCBncm91cD1TQU1QTEVfTkFNRSwgY29sPXN0YWJsZSkpICArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikgKyANCiAgI2ZhY2V0X3dyYXAofnN3aXRjaCwgbmNvbD0xLCBzY2FsZT0iZnJlZV95IikgKw0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICB5bGFiKCJBR1AgcGFydGljaXBhbnRzIikgKyB4bGFiKCJGYWVjYWxpYmFjdGVyaXVtL1xuQmFjdGVyb2lkZXMgcmF0aW8iKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgiIiwgdmFsdWVzPWMoImJsYWNrIiwicmVkIiksIGxhYmVsPWMoInN0YWJsZSIsInVuc3RhYmxlIikpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgZmFjZXRfZ3JpZChzdGFydF9wYXJ0aXRpb25+Liwgc2NhbGVzID0gImZyZWVfeSIpDQoNCg0KcmJpbmQoZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gsIHJhdGlvKSAsDQogICAgICBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uX2JlZm9yZSwgc3dpdGNoLCByYXRpb19iZWZvcmUpICU+JSBkcGx5cjo6cmVuYW1lKEVudGVyb3R5cGVzX2lkPUVudGVyb3R5cGVzX2lkX2JlZm9yZSxzaGFubm9uPXNoYW5ub25fYmVmb3JlLCByYXRpbz1yYXRpb19iZWZvcmUpKSAlPiUgDQogICAgICAgIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihzaGFubm9uKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCI3IDciKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogICNmaWx0ZXIoc3RhYmxlID09ICJzdGFibGUiKSAlPiUNCiAgZ2dwbG90KCkgKyANCiAgZ2VvbV9wb2ludChhZXMoeD1yYXRpbyx5PXNoYW5ub24sY29sPXN3aXRjaCkpKyANCiAgZ2VvbV9saW5lKGFlcyh4PXJhdGlvLHk9c2hhbm5vbixncm91cD1TQU1QTEVfTkFNRSAsY29sPXN3aXRjaCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzIiKSArIGZhY2V0X3dyYXAofnN0YWJsZSkNCg0KDQoNCg0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBtZXJnZShwX2JfcmF0aW8sIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIG11dGF0ZShTQU1QTEVfTkFNRSA9IFNBTVBMRV9OQU1FICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihFbnRlcm90eXBlc19pZCU+JWFzLm51bWVyaWMpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8sIGZpbGw9c3dpdGNoKSwgYWxwaGE9MC41KSAgKyB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMiIpDQoNCmRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWQsc2hhbm5vbiwgc3dpdGNoKSAlPiUNCiAgbWVyZ2UocF9iX3JhdGlvLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICBtdXRhdGUoU0FNUExFX05BTUUgPSBTQU1QTEVfTkFNRSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoRW50ZXJvdHlwZXNfaWQlPiVhcy5udW1lcmljKSkgJT4lDQogIGdncGxvdCgpICsgDQogICNnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8pLCBhbHBoYT0wLjUpICArIA0KICBnZW9tX2RlbnNpdHkoYWVzKHg9cmF0aW8sIGNvbG9yPXN3aXRjaCksIGFscGhhPTAuNSkgICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikNCg0KIyBkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQojICAgZmlsdGVyKHN3aXRjaCAlaW4lIGMoIjIgMiIsICIyIDYiKSkgJT4lDQojICAgbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JSBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKSwgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiMgICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KIyAgIGdncGxvdCgpICsgZ2VvbV9ib3hwbG90KGFlcyh4PXN3aXRjaCwgeT12YWx1ZSkpICsgZmFjZXRfd3JhcCh+dmFyaWFibGUsIHNjYWxlPSJmcmVlIikNCg0KDQpkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCkgJT4lDQogIGZpbHRlcihzd2l0Y2ggJWluJSBjKCIxNCAxNCIsICIxNCA3IikpICU+JQ0KICBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLCBieS54PSJTQU1QTEVfTkFNRSIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZD1jKCJTQU1QTEVfTkFNRSIsIkVudGVyb3R5cGVzX2lkIiwic3dpdGNoIikpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIHRpZHlyOjpuZXN0KCkgICU+JSANCiAgbXV0YXRlKHdpbGNveF90ZXN0PXB1cnJyOjptYXAoZGF0YSx+d2lsY294LnRlc3QoLngkdmFsdWV+Lngkc3dpdGNoKSksDQogICAgICAgIHRpZHk9cHVycnI6Om1hcCh3aWxjb3hfdGVzdCwgYnJvb206OnRpZHkpKSAlPiUgDQogICAgICB0aWR5cjo6dW5uZXN0KHRpZHksLmRyb3A9VFJVRSkgJT4lDQogIGFycmFuZ2UocC52YWx1ZSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgI211dGF0ZShwLnZhbHVlPXAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIikpICU+JQ0KICBmaWx0ZXIocC52YWx1ZTwwLjA1KSAlPiUgc2VsZWN0KHZhcmlhYmxlLHAudmFsdWUpICU+JSB3cml0ZS5jc3YyKGZpbGU9Im1ldGFkYXRhX2xpbmtfMTQxNHZzMTQ3LmNzdiIpDQoNCg0KZGYgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxFbnRlcm90eXBlc19pZCxzaGFubm9uLCBzd2l0Y2gpICU+JQ0KICBmaWx0ZXIoc3dpdGNoICVpbiUgYygiNyA3IiwgIjcgMTQiKSkgJT4lDQogIG1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYyksIGJ5Lng9IlNBTVBMRV9OQU1FIiwgYnkueT0icm93Lm5hbWVzIikgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkPWMoIlNBTVBMRV9OQU1FIiwiRW50ZXJvdHlwZXNfaWQiLCJzd2l0Y2giKSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgdGlkeXI6Om5lc3QoKSAgJT4lIA0KICBtdXRhdGUod2lsY294X3Rlc3Q9cHVycnI6Om1hcChkYXRhLH53aWxjb3gudGVzdCgueCR2YWx1ZX4ueCRzd2l0Y2gpKSwNCiAgICAgICAgdGlkeT1wdXJycjo6bWFwKHdpbGNveF90ZXN0LCBicm9vbTo6dGlkeSkpICU+JSANCiAgICAgIHRpZHlyOjp1bm5lc3QodGlkeSwuZHJvcD1UUlVFKSAlPiUNCiAgYXJyYW5nZShwLnZhbHVlKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICAjbXV0YXRlKHAudmFsdWU9cC5hZGp1c3QocC52YWx1ZSwgbWV0aG9kPSJmZHIiKSklPiUNCiAgZmlsdGVyKHAudmFsdWU8MC4wNSkgJT4lIHNlbGVjdCh2YXJpYWJsZSxwLnZhbHVlKSAlPiUgd3JpdGUuY3N2MihmaWxlPSJtZXRhZGF0YV9saW5rXzc3dnM3MTQuY3N2IikNCg0KDQpkZiAlPiUNCiAgbXV0YXRlKGRlbHRhX3JhdGlvID0gYWJzKGxvZzIocmF0aW9fYmVmb3JlKSAtIGxvZzIocmF0aW8pKSkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoeD1sb2cyKHJhdGlvX2JlZm9yZSkgLSBsb2cyKHJhdGlvKSx5PWxvZzIoc2hhbm5vbl9iZWZvcmUvc2hhbm5vbiksIGNvbG9yPXN3aXRjaCkpICsNCiAgeGxpbSgtNCw0KSArIHlsaW0oLTAuNSwgMC41KSArIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArIHNjYWxlX2NvbG9yX2JyZXdlcigiIiwgdHlwZT0icXVhbCIsIHBhbGV0dGUgPSAyKSArDQogIHhsYWIoIlByZXZvdGVsbGEvQmFjdGVyb2lkZXMgdmFyaWF0aW9uIikgKyB5bGFiKCJhbHBoYS1kaXZlcnNpdHkgdmFyaWF0aW9uIikgLT4gZmlnUzExQg0KDQoNCg0KDQpyYmluZChkZiAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEVudGVyb3R5cGVzX2lkLHNoYW5ub24sIHN3aXRjaCwgcmF0aW8pICwNCiAgICAgIGRmICU+JSBzZWxlY3QoU0FNUExFX05BTUUsRW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub25fYmVmb3JlLCBzd2l0Y2gsIHJhdGlvX2JlZm9yZSkgJT4lIGRwbHlyOjpyZW5hbWUoRW50ZXJvdHlwZXNfaWQ9RW50ZXJvdHlwZXNfaWRfYmVmb3JlLHNoYW5ub249c2hhbm5vbl9iZWZvcmUsIHJhdGlvPXJhdGlvX2JlZm9yZSkpICU+JSANCiAgICAgICAgbXV0YXRlKFNBTVBMRV9OQU1FID0gU0FNUExFX05BTUUgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHJhdGlvKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCI3IDciKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCIxNCA3IiksICJNMTQiLCJNNyIpICApICU+JQ0KICBtdXRhdGUoc3RhcnRfcGFydGl0aW9uID0gc3RhcnRfcGFydGl0aW9uICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihyYXRpbywgLmRlc2M9VFJVRSkpICU+JQ0KICAjYXJyYW5nZShzd2l0Y2gpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD1yYXRpbyx5PVNBTVBMRV9OQU1FLCBncm91cD1TQU1QTEVfTkFNRSwgY29sPXN0YWJsZSkpICArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cyIikgKyANCiAgI2ZhY2V0X3dyYXAofnN3aXRjaCwgbmNvbD0xLCBzY2FsZT0iZnJlZV95IikgKw0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICB5bGFiKCJBR1AgcGFydGljaXBhbnRzIikgKyB4bGFiKCJQcmV2b3RlbGxhL1xuQmFjdGVyb2lkZXMgcmF0aW8iKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgiIiwgdmFsdWVzPWMoImJsYWNrIiwicmVkIiksIGxhYmVsPWMoInN0YWJsZSIsInVuc3RhYmxlIikpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgZmFjZXRfZ3JpZChzdGFydF9wYXJ0aXRpb25+Liwgc2NhbGVzID0gImZyZWVfeSIpIC0+IGZpZzVJX2Z1bGwNCg0KDQpkZiAlPiUNCiAgbXV0YXRlKGRlbHRhX3JhdGlvID0gYWJzKGxvZzIocmF0aW9fYmVmb3JlKSAtIGxvZzIocmF0aW8pKSkgJT4lDQogIG11dGF0ZShzdGFibGUgPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCI3IDciKSwgInN0YWJsZSIsInVuc3RhYmxlIikgICkgJT4lDQogIG11dGF0ZShzdGFydF9wYXJ0aXRpb24gPSBpZmVsc2Uoc3dpdGNoICVpbiUgYygiMTQgMTQiLCIxNCA3IiksICJNMTQiLCJNNyIpICApICU+JQ0KICBtdXRhdGUoc3RhcnRfcGFydGl0aW9uID0gc3RhcnRfcGFydGl0aW9uICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihyYXRpbywgLmRlc2M9VFJVRSkpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYm94cGxvdChhZXMoeD1zdGFydF9wYXJ0aXRpb24seT1kZWx0YV9yYXRpbywgY29sPXN0YWJsZSkpICsgDQogIHlsYWIoIlByZXZvdGVsbGEvQmFjdGVyb2lkZXNcbnJhdGlvIHZhcmlhdGlvbiIpICsgDQogICNzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZzIiKSArDQogIHhsYWIoIiIpICsgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsgc2NhbGVfY29sb3JfbWFudWFsKCIiLHZhbHVlcz1jKCJibGFjayIsInJlZCIpKSAtPiBmaWc1SWluc2V0DQoNCg0KZmlnNUkgPSBmaWc1SV9mdWxsICsgaW5zZXRfZWxlbWVudChmaWc1SWluc2V0K3lsYWIoInZhcmlhdGlvbiIpK2d1aWRlcyhjb2xvcj1GQUxTRSksIDAuNjUsLTAuMSwxLDAuMywgaWdub3JlX3RhZyA9IEZBTFNFKQ0KDQpmaWc1SQ0KDQoNCg0KDQpgYGANCg0KIyBGdWxsIGZpZ3VyZQ0KDQoNCg0KYGBge3IgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9MTZ9DQoNCigoZmlnNUEpIHwgKGZpZzVCX2Z1bGwvZmlnNUNfZnVsbCkpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiYSIpICsgcGxvdF9sYXlvdXQod2lkdGhzID0gYygyLDEuNSkpDQoNCnBfZnByYXVfZGVuc2l0eSAvIHBfZnByYXVfcGFydGl0aW9ufHBfcHJldm90ZWxsYV9kZW5zaXR5IC8gcF9wcmV2b3RlbGxhX3BhcnRpdGlvbg0KDQpmaWc1SV9mdWxsDQoNCg0KDQoNCigNCiAgKGZpZzVBICsgdGhlbWUocGxvdC50YWcgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpKSB8IA0KICAgIA0KICAoKHBfZnByYXVfZGVuc2l0eSAvIHBfZnByYXVfcGFydGl0aW9uICsgeWxhYigiQmFjdGVyb2lkZXNcbkRNTSB0eXBlcyIpKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMikpICkgfA0KICAgIA0KICAoKChwX3ByZXZvdGVsbGFfZGVuc2l0eSArIHhsYWIoIlByZXZvdGVsbGEgQmFjdGVyb2lkZXMgcmF0aW9cbndpdGhpbiBQcmV2b3RlbGxhIGVucmljaGVkIGJyYW5jaCIpKSAvIChwX3ByZXZvdGVsbGFfcGFydGl0aW9uICsgeWxhYigiUHJldm90ZWxsYVxuRE1NIHR5cGVzIikpKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMikpICkgKyANCiAgICBwbG90X2xheW91dCh3aWR0aHMgPSBjKDQsMSwxKSkNCiAgDQogICkgLw0KICANCihmaWc1Ql9mdWxsfGZpZzVDX2Z1bGx8ZmlnNUlfZnVsbCkgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJhIikNCg0KDQoNCg0KDQpgYGANCg0KIyMjIGZpZ3VyZSBmb3IgcHVibGljYXRpb24NCmBgYHtyIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0NCg0KZmlnNUJfZnVsbF9zY2FsZWQgPQ0KZmlnNUJfZnVsbCArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEvNCkgKw0Kc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSJsb2cyIiwgbGFiZWxzPXNjYWxlczo6dHJhbnNfZm9ybWF0KCJmcmFjX2Z1biIsc2NhbGVzOjpsYWJlbF9tYXRoKGV4cHIgPSAxLy54LCBmb3JtYXQgPSBmb3JjZSkpLCBsaW1pdHMgPSBjKDEvNjQsMy8yKSkNCg0KZmlnNUNfZnVsbF9zY2FsZWQgPSANCmZpZzVDX2Z1bGwgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLzQpICsNCnNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMiIsIGxhYmVscz1zY2FsZXM6OnRyYW5zX2Zvcm1hdCgiZnJhY19mdW4iLHNjYWxlczo6bGFiZWxfbWF0aChleHByID0gMS8ueCwgZm9ybWF0ID0gZm9yY2UpKSwgbGltaXRzID0gYygxLzY0LDMvMikpDQoNCmZpZzVKX2VsbGlzcHNlX3NjYWxlZCA9DQpmaWc1Sl9lbGxpc3BzZSsNCiAgeGxhYigiRiBCIHJhdGlvIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZzIiLCBsYWJlbHM9c2NhbGVzOjp0cmFuc19mb3JtYXQoImZyYWNfZnVuIixzY2FsZXM6OmxhYmVsX21hdGgoZXhwciA9IDEvLngsIGZvcm1hdCA9IGZvcmNlKSksIGxpbWl0cyA9IGMoMS82NCwzLzIpKSsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpDQoNCg0KZmlnNUtfZWxsaXNwc2Vfc2NhbGVkID0NCmZpZzVLX2VsbGlzcHNlKw0KICB4bGFiKCJGIEIgcmF0aW8iKSArDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMiIsIGxhYmVscz1zY2FsZXM6OnRyYW5zX2Zvcm1hdCgiZnJhY19mdW4iLHNjYWxlczo6bGFiZWxfbWF0aChleHByID0gMS8ueCwgZm9ybWF0ID0gZm9yY2UpKSwgbGltaXRzID0gYygxLzY0LDMvMikpKw0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkNCg0KDQoNCigoKChmaWc1QSArIHRoZW1lKHBsb3QudGFnID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSkgL2ZpZzVNX3N0YWJpbGl0eSApICsgIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMS41KSkgKSAgfA0KDQogICAgKCgoZmlnNUJpbnNldCt5bGFiKCJGIEIgcmF0aW8gdmFyaWF0aW9uIikpLyhmaWc1Q2luc2V0K3lsYWIoIkYgQiByYXRpbyB2YXJpYXRpb24iKSkvcGxvdF9zcGFjZXIoKS9wbG90X3NwYWNlcigpKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDAuOCwwLjgsMSwxKSkgKSB8DQogIA0KKChmaWc1Ql9mdWxsX3NjYWxlZC9maWc1Q19mdWxsX3NjYWxlZC8ocF9mcHJhdV9kZW5zaXR5K2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDEvNCkpLyhwX2ZwcmF1X3BhcnRpdGlvbisgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEvNCkpKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMSwwLjUsMS41KSkgICkNCiAgICMoKGZpZzVKX2VsbGlzcHNlX3NjYWxlZCkvKGZpZzVLX2VsbGlzcHNlX3NjYWxlZCkvcGxvdF9zcGFjZXIoKS9wbG90X3NwYWNlcigpKSB8DQogDQogICkgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEuNSwwLjUsMSkpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiYSIpDQogICANCg0KZ2dzYXZlKGZpbGU9ImZpZ3VyZV9uZXR3b3JrX3RpbWVfc2VyaWVzLnBkZiIpDQoNCg0KDQooDQogICgNCiAgICAoDQogICAgICAoZmlnNUEgKyANCiAgICAgICAgIHRoZW1lKHBsb3QudGFnID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKQ0KICAgICAgICkgLw0KICAgICAgICAoZmlnNU1fc3RhYmlsaXR5KQ0KICAgICAgKSArICANCiAgICAgIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEuNSwxLjUpKSANCiAgICApICB8DQogICAgKA0KICAgICAgKA0KICAgICAgICAoDQogICAgICAgICAgKGZpZzVCaW5zZXQreWxhYigiRiBCIHJhdGlvIHZhcmlhdGlvbiIpKS8NCiAgICAgICAgICAgIChmaWc1Q2luc2V0K3lsYWIoIkYgQiByYXRpbyB2YXJpYXRpb24iKSkgfA0KICAgICAgICAgICAgKGZpZzVCX2Z1bGxfc2NhbGVkKS8NCiAgICAgICAgICAgIChmaWc1Q19mdWxsX3NjYWxlZCkpLw0KICAgICAgICAgICgNCiAgICAgICAgICAgIChwX2ZwcmF1X2RlbnNpdHkrZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS80KSkvDQogICAgICAgICAgICAgIChwX2ZwcmF1X3BhcnRpdGlvbisgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEvNCkpICsgDQogICAgICAgICAgICAgIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMikpIA0KICAgICAgICAgICAgKSANCiAgICAgICAgKSArIA0KICAgICAgICBwbG90X2xheW91dChoZWlnaHRzID0gYygxLjUsMS4yNSkpDQogICAgICApDQogICkgKyANCiAgcGxvdF9sYXlvdXQod2lkdGhzID0gYygxLjUsMS41KSkgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJhIikNCg0KDQpnZ3NhdmUoZmlsZT0iZmlndXJlX25ldHdvcmtfdGltZV9zZXJpZXMucGRmIikNCg0KDQoNCmBgYA0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTl9DQoNCg0KZmlnNUpfZWxsaXNwc2Vfc2NhbGVkICsgZmlnNUtfZWxsaXNwc2Vfc2NhbGVkICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiYSIpDQoNCmdnc2F2ZShmaWxlPSJmaWd1cmVTOV9iaXMucGRmIikNCg0KYGBgDQoNCg0KDQojIGJpbW9kYWxpdHkgYW5kIHN0YWJpbGl0eQ0KDQpgYGB7cn0NCg0KbWV0YWRhdGEgJT4lDQogIGZpbHRlcihTQU1QTEVfVFlQRSA9PSAiU3Rvb2wiKSAlPiUNCiAgc2VsZWN0KEhPU1RfU1VCSkVDVF9JRCxTQU1QTEVfTkFNRSwgQ09MTEVDVElPTl9USU1FU1RBTVApICU+JQ0KICBtdXRhdGUoQ09MTEVDVElPTl9USU1FU1RBTVAgPSBDT0xMRUNUSU9OX1RJTUVTVEFNUCAlPiUgbHVicmlkYXRlOjphc19kYXRlKCkpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcywgYnkueD0iU0FNUExFX05BTUUiLCBieS55PSJzYW1wbGVfbmFtZSIpICU+JQ0KICBmaWx0ZXIoc2V0ICE9ICJvdXRsaWVycyIpICU+JQ0KICBmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgIT0gMTkpICU+JQ0KICBncm91cF9ieShIT1NUX1NVQkpFQ1RfSUQpICU+JQ0KICBtdXRhdGUobWluX2RhdGUgPSBtaW4oQ09MTEVDVElPTl9USU1FU1RBTVApLCBuPW4oKSkgJT4lDQogICNmaWx0ZXIobj4xKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzPUNPTExFQ1RJT05fVElNRVNUQU1QIC0gbWluX2RhdGUpICU+JSANCiAgZ3JvdXBfYnkoSE9TVF9TVUJKRUNUX0lEKSAlPiUNCiAgYXJyYW5nZShIT1NUX1NVQkpFQ1RfSUQsIGRheXMpICU+JQ0KICBtdXRhdGUoc2FtcGxlX29yZGVyPW9yZGVyKENPTExFQ1RJT05fVElNRVNUQU1QKSkgJT4lIA0KICANCg0KICBtdXRhdGUoYnJhbmNoZXMgPSBjYXNlX3doZW4oRW50ZXJvdHlwZXNfaWQgJWluJSBjKDE4LDE0LDE2LDE3LDcpIH4gIlByZXZvdGVsbGEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMSwxNSw2LDgsMTAsMyw0LDIpIH4gIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRlcm90eXBlc19pZCAlaW4lIGMoMTIsMSw1LDkpIH4gIkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGVyb3R5cGVzX2lkICVpbiUgYygxMykgfiAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAib3V0bGllcnMiKQ0KICAgICAgICAgKSAlPiUNCiAgDQogIG11dGF0ZShkYXlzXzA9YnJhbmNoZXNbd2hpY2gubWluKHNhbXBsZV9vcmRlcildKSAlPiUgDQogIGFycmFuZ2UoSE9TVF9TVUJKRUNUX0lEKSAgJT4lIA0KICAjbXV0YXRlKHNhbXBsZV9vcmRlcj1yYW5rKGRheXMpKSAlPiUNCiAgbXV0YXRlKGRheXMgPSBhcy5udW1lcmljKGRheXMpKSAlPiUNCiAgc2VsZWN0KFNBTVBMRV9OQU1FLEhPU1RfU1VCSkVDVF9JRCxkYXlzLHZhbHVlLEVudGVyb3R5cGVzX2lkLGJyYW5jaGVzKSAlPiUNCiAgZHBseXI6OnJlbmFtZSh0aW1lPWRheXMsc3ViamVjdD1IT1NUX1NVQkpFQ1RfSUQpICU+JSBtdXRhdGUoc2FtcGxlPVNBTVBMRV9OQU1FKSAlPiUgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoIlNBTVBMRV9OQU1FIiktPiBtZXRhZGF0YV9mb3JfcGh5c2VxDQoNCg0KZ2VudXMgJT4lIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJ0YXhhIikgJT4lIHBoeWxvc2VxOjpvdHVfdGFibGUodGF4YV9hcmVfcm93cz1UUlVFKSAtPiBnZW51c19mb3JfcGh5bG9zZXENCg0KZ2VudXMgJT4lDQogIHNlbGVjdCh0YXhhKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlKHRheGEsIGludG89YygiayIsInAiLCJjIiwibyIsImYiLCJnIikscmVtb3ZlID0gRkFMU0UsIHNlcCA9ICI7IikgJT4lDQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJ0YXhhIikgJT4lIGFzLm1hdHJpeCAlPiUgcGh5bG9zZXE6OnRheF90YWJsZSgpIC0+IHRheGFfZm9yX3BoeWxvc2VxDQoNCg0KcHNlcT1waHlsb3NlcTo6cGh5bG9zZXEoT1RVPWdlbnVzX2Zvcl9waHlsb3NlcSwgcGh5bG9zZXE6OnNhbXBsZV9kYXRhKG1ldGFkYXRhX2Zvcl9waHlzZXEpLCBUQVg9dGF4YV9mb3JfcGh5bG9zZXEgKQ0KDQoNCg0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQoNCg0KcHNlcT1waHlsb3NlcShPVFU9Z2VudXNfZm9yX3BoeWxvc2VxLCBzYW1wbGVfZGF0YShtZXRhZGF0YV9mb3JfcGh5c2VxKSwgVEFYPXRheGFfZm9yX3BoeWxvc2VxICkNCg0KI3BzZXEgPC0gcHNlcSAlPiUgc3Vic2V0X3NhbXBsZXModmFsdWU+MC44MCkNCnBzZXEgPC0gcHNlcSAlPiUgc3Vic2V0X3NhbXBsZXMoRW50ZXJvdHlwZXNfaWQgJWluJSBjKCIxNSIsIjEiKSkNCnBzZXEgPC0gbWljcm9iaW9tZTo6dHJhbnNmb3JtKHBzZXEsICJjb21wb3NpdGlvbmFsIikNCnBzZXEgPC0gYWdncmVnYXRlX3JhcmUocHNlcSwgbGV2ZWw9ImciLCBkZXRlY3Rpb24gPSAuMS8xMDAsIHByZXZhbGVuY2UgPSA1LzEwMCkNCnBzZXEwIDwtIGJhc2VsaW5lKHBzZXEpDQoNCm90dV90YWJsZShwc2VxKSAlPiUgZGltDQoNCmBgYA0KDQojIyBpbnRlcm1lZGlhdGUgc3RhYmlsaXR5IHF1YW50aWZpY2F0aW9uDQpgYGB7cn0NCg0KaW50ZXJtZWRpYXRlX3N0YWJpbGl0eV9hbHIgPSBmdW5jdGlvbiAoeCwgcmVmZXJlbmNlLnBvaW50ID0gTlVMTCwgbWV0aG9kID0gImNvcnJlbGF0aW9uIiwgDQogICAgb3V0cHV0ID0gInNjb3JlcyIpew0KICAgIHgwIDwtIHgNCiAgICBpZiAobGVuZ3RoKHJlZmVyZW5jZS5wb2ludCkgPiAxICYmIG91dHB1dCA9PSAic2NvcmVzIikgew0KICAgICAgICBzY29yZXMgPC0gYygpDQogICAgICAgIGZvciAoaSBpbiBzZXFfbGVuKGxlbmd0aChyZWZlcmVuY2UucG9pbnQpKSkgew0KICAgICAgICAgICAgc2NvcmVzW1tpXV0gPC0gaW50ZXJtZWRpYXRlX3N0YWJpbGl0eSh4LCByZWZlcmVuY2UucG9pbnQgPSByZWZlcmVuY2UucG9pbnRbW2ldXSwgDQogICAgICAgICAgICAgICAgbWV0aG9kID0gbWV0aG9kLCBvdXRwdXQgPSBvdXRwdXQpDQogICAgICAgIH0NCiAgICAgICAgaWYgKG50YXhhKHgpID4gMSkgew0KICAgICAgICAgICAgc2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzLCBucm93ID0gbnRheGEoeCkpDQogICAgICAgIH0NCiAgICAgICAgZWxzZSB7DQogICAgICAgICAgICBzY29yZXMgPC0gYXMuZGF0YS5mcmFtZSh0KGFzLm1hdHJpeChzY29yZXMsIG5jb2wgPSBsZW5ndGgocmVmZXJlbmNlLnBvaW50KSkpKQ0KICAgICAgICB9DQogICAgICAgIGNvbG5hbWVzKHNjb3JlcykgPC0gYXMuY2hhcmFjdGVyKHJlZmVyZW5jZS5wb2ludCkNCiAgICAgICAgcm93bmFtZXMoc2NvcmVzKSA8LSB0YXhhKHgpDQogICAgICAgIHJldHVybihzY29yZXMpDQogICAgfQ0KICAgIHggPC0gYWJ1bmRhbmNlcyh0cmFuc2Zvcm0oeDAsICJpZGVudGl0eSIpKQ0KICAgIGIgPC0gYWJ1bmRhbmNlcyh0cmFuc2Zvcm0oeDAsICJpZGVudGl0eSIpKVsiZ19fQmFjdGVyb2lkZXMiXQ0KICAgIHggPSBsb2cyKCh4KzEpLyhiKzEpKQ0KICAgIG1ldGEgPC0gc2FtcGxlX2RhdGEoeDApDQogICAgc3RhYmlsaXR5IDwtIGxpc3QoKQ0KICAgIGRmIDwtIG1ldGENCiAgICBkZiR0aW1lIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRmJHRpbWUpKQ0KICAgIGRmIDwtIGRmW2RmJHN1YmplY3QgJWluJSBuYW1lcyh3aGljaCh0YWJsZShkZiRzdWJqZWN0KSA+IA0KICAgICAgICAxKSksIF0NCiAgICBzcGwgPC0gc3BsaXQoZGYsIGFzLmNoYXJhY3RlcihkZiRzdWJqZWN0KSkNCiAgICBzcGwubGlzdCA8LSBsaXN0KCkNCiAgICBmb3IgKGkgaW4gc2VxX2xlbihsZW5ndGgoc3BsKSkpIHsNCiAgICAgICAgc3BsLmxpc3RbW2ldXSA8LSBsaXN0KHNwbCA9IHNwbFtbaV1dW29yZGVyKHNwbFtbaV1dJHRpbWUpLCANCiAgICAgICAgICAgIF0sIHRpbWUuZGlmcyA9IGRpZmYoc3BsW1tpXV0kdGltZSkpDQogICAgfQ0KICAgIGZvciAodGF4IGluIHJvd25hbWVzKHgpKSB7DQogICAgICAgIGRmJGRhdGEgPC0geFt0YXgsIHJvd25hbWVzKGRmKV0NCiAgICAgICAgc3RhYmlsaXR5W1t0YXhdXSA8LSBlc3RpbWF0ZV9zdGFiaWxpdHkoZGYsIHJlZmVyZW5jZS5wb2ludCA9IHJlZmVyZW5jZS5wb2ludCwgDQogICAgICAgICAgICBtZXRob2QgPSBtZXRob2QsIHNwbC5saXN0KQ0KICAgIH0NCiAgICBpZiAob3V0cHV0ID09ICJmdWxsIikgew0KICAgICAgICByZXR1cm4oc3RhYmlsaXR5KQ0KICAgIH0NCiAgICBlbHNlIGlmIChvdXRwdXQgPT0gInNjb3JlcyIpIHsNCiAgICAgICAgaW50ZXJtZWRpYXRlLnN0YWJpbGl0eSA8LSB2YXBwbHkoc3RhYmlsaXR5LCBmdW5jdGlvbih4KSB7DQogICAgICAgICAgICB4JHN0YWJpbGl0eQ0KICAgICAgICB9LCAxKQ0KICAgICAgICByZXR1cm4oaW50ZXJtZWRpYXRlLnN0YWJpbGl0eSkNCiAgICB9DQp9DQoNCg0KIyBIZXJlIHdlIHVzZSB0aGUgKG5vbi1iYXNlbGluZSkgcGh5bG9zZXEgb2JqZWN0IHRoYXQgY29udGFpbnMgdGltZSBzZXJpZXMuDQppbnRlcm1lZGlhdGUuc3RhYmlsaXR5IDwtIGludGVybWVkaWF0ZV9zdGFiaWxpdHlfYWxyKHBzZXEsIG91dHB1dCA9ICJzY29yZXMiLCBtZXRob2QgPSAiY29ycmVsYXRpb25zIikgI2NsciB0cmFuc2ZvIGluY2x1ZGVkDQoNCmludGVybWVkaWF0ZS5zdGFiaWxpdHkgJT4lIHNvcnQgJT4lIHJvdW5kKDMpDQpgYGANCg0KDQoNCiMjIGJpbW9kYWxpdHkgcXVhbnRpZnljYXRpb24NCg0KYGBge3J9DQojIEJpbW9kYWxpdHkgaXMgYmV0dGVyIGVzdGltYXRlZCBmcm9tIGFidW5kYW5jZXMgYXQgbG9nIHNjYWxlIChzdWNoIGFzIENMUikNCnBzZXEwLmNsciA8LSBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0ocHNlcTAsICJjbHIiKQ0KDQpzZXQuc2VlZCg0NDMzKQ0KDQoNCg0KYmltb2RhbGl0eS5zY29yZSA8LSBiaW1vZGFsaXR5KHBzZXEwLmNsciwgbWV0aG9kID0gInBvdGVudGlhbF9hbmFseXNpcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnMuaXRlciA9IDEwMCwgcGVhay50aHJlc2hvbGQgPSAxMCwNCiAgICAgICAgICAgICAgICAgICBtaW4uZGVuc2l0eSA9IDEwKQ0KDQpiaW1vZGFsaXR5LnNjb3JlICU+JSBzb3J0ICU+JSByb3VuZCgzKQ0KDQpgYGANCg0KDQojIyBDb21wYXJpbmcgYmltb2RhbGl0eSBhbmQgaW50ZXJtZWRpYXRlIHN0YWJpbGl0eQ0KDQpgYGB7cn0NCg0KdGF4YSA8LSB0YXhhKHBzZXEwKQ0KZGYgPC0gZGF0YS5mcmFtZShncm91cCA9IGFzLmNoYXJhY3Rlcih0YXhhKSAlPiUgZ3N1YigiZ19fIiwiIiwuKSwNCmludGVybWVkaWF0ZS5zdGFiaWxpdHkgPSBpbnRlcm1lZGlhdGUuc3RhYmlsaXR5W3RheGFdLA0KYmltb2RhbGl0eSA9IGJpbW9kYWxpdHkuc2NvcmVbdGF4YV0pDQp0aGVtZV9zZXQodGhlbWVfYncoMjApKQ0KDQpkZiA9IGRmICU+JQ0KICBtdXRhdGUoZ3JvdXAgPSBncm91cCAlPiUgYXMuY2hhcmFjdGVyKCkpICU+JQ0KICBtdXRhdGUobGFiZWwgPSBpZmVsc2UoYmltb2RhbGl0eSA+IDAuNiAmIGludGVybWVkaWF0ZS5zdGFiaWxpdHkgPCAwLCBncm91cCwgJycpKQ0KDQpkZiAlPiUNCiAgZmlsdGVyKGJpbW9kYWxpdHkgPiAwLjYgJiBpbnRlcm1lZGlhdGUuc3RhYmlsaXR5IDwgLTAuMSkgJT4lDQogIGFycmFuZ2UoaW50ZXJtZWRpYXRlLnN0YWJpbGl0eSkNCg0KDQpsaWJyYXJ5KGdncmVwZWwpDQoNCnAgPC0gZ2dwbG90KGRmLA0KICBhZXMoeCA9IGludGVybWVkaWF0ZS5zdGFiaWxpdHksIHkgPSBiaW1vZGFsaXR5LCBsYWJlbCA9ICcnKSkgKyAjRG9lc24ndCBhZGQgbGFiZWxzIHRvIHBvaW50cw0KICBnZW9tX3RleHRfcmVwZWwoKSArDQogIGdlb21fcG9pbnQoKQ0KDQojTGFiZWxzIG9ubHkgdGhvc2UgdGhhdCBoYXZlIGJpbW9kYWxpdHkgPiAwLjQgYW5kIGludGVybWVkaWF0ZSBzdGFiaWxpdHkgPCAwLCBhZGp1c3RzIHRoZSBwbGFjZW1lbnQgb2YgbGFiZWxzDQpwIDwtIHAgKyBnZW9tX3RleHQoYWVzKGxhYmVsID0gaWZlbHNlKGJpbW9kYWxpdHkgPiAwLjYgJiBpbnRlcm1lZGlhdGUuc3RhYmlsaXR5IDwgLTAuMjUsIGdyb3VwLCAnJykpLCB2anVzdCA9ICJpbndhcmQiLCBoanVzdCA9ICJpbndhcmQiKQ0KDQpwcmludChwKQ0KDQoNCmBgYA0KDQoNCiMjIFRpcHBpbmcgcG9pbnQNCg0KYGBge3J9DQoNCiMgTG9nMTAgYWJ1bmRhbmNlIGZvciBhIHNlbGVjdGVkIHRheG9ub21pYyBncm91cA0KIyBQaWNrIHRoZSBtb3N0IGJpbW9kYWwgdGF4YSBhcyBhbiBleGFtcGxlDQojdGF4ICA8LSBuYW1lcyh3aGljaC5tYXgoYmltb2RhbGl0eS5zY29yZSkpDQp0YXggPSAiZ19fQmFjaWxsdXMiDQoNCiMgRGV0ZWN0IHRpcHBpbmcgcG9pbnRzIGF0IGxvZzEwIGFidW5kYW5jZXMNCnggPC0gYWJ1bmRhbmNlcyhtaWNyb2Jpb21lOjp0cmFuc2Zvcm0ocHNlcSwgImNsciIpKVt0YXgsXQ0KDQogZiA8LSBhYnVuZGFuY2VzKG1pY3JvYmlvbWU6OnRyYW5zZm9ybShwc2VxLCAiaWRlbnRpdHkiKSlbdGF4LF0NCiBiIDwtIGFidW5kYW5jZXMobWljcm9iaW9tZTo6dHJhbnNmb3JtKHBzZXEsICJpZGVudGl0eSIpKVsiZ19fQmFjdGVyb2lkZXMiLF0NCiB4PWxvZzIoKGYrMSkvKGIrMSkpDQoNCiMgQm9vdHN0cmFwcGVkIHBvdGVudGlhbCBhbmFseXNpcyB0byBpZGVudGlmeSBwb3RlbnRpYWwgbWluaW1hDQojIGluIHByYWN0aWNlLCB1c2UgbW9yZSBib290c3RyYXAgaXRlcmF0aW9ucw0KcG90ZW50aWFsLm1pbmltYSA8LSBwb3RlbnRpYWxfYW5hbHlzaXMoeCwgYnMuaXRlciA9IDEwKSRtaW5pbWENCg0KIyBTYW1lIHdpdGggZWFybHl3YXJuaW5ncyBwYWNrYWdlICh3aXRob3V0IGJvb3RzdHJhcCBpZS4gbGVzcyByb2J1c3QpDQojIGxpYnJhcnkoZWFybHl3YXJuaW5ncykNCiMgcmVzIDwtIGxpdnBvdGVudGlhbF9ld3MoeCkkbWluLnBvaW50cw0KDQojIElkZW50aWZ5IHRoZSBwb3RlbnRpYWwgbWluaW11bSBsb2NhdGlvbnMgYXMgdGlwcGluZyBwb2ludCBjYW5kaWRhdGVzDQp0aXBwaW5nLnNhbXBsZXMgPC0gc2FwcGx5KHBvdGVudGlhbC5taW5pbWEsIGZ1bmN0aW9uIChtKSB7bmFtZXMod2hpY2gubWluKGFicyhzb3J0KHgpIC0gbSkpKX0pDQp0aXBwaW5nLnBvaW50IDwtIGFidW5kYW5jZXMocHNlcSlbdGF4LCB0aXBwaW5nLnNhbXBsZXNdDQpwcmludCh0aXBwaW5nLnBvaW50KQ0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIGYgPC0gYWJ1bmRhbmNlcyhtaWNyb2Jpb21lOjp0cmFuc2Zvcm0ocHNlcSwgImlkZW50aXR5IikpW3RheCxdDQogYiA8LSBhYnVuZGFuY2VzKG1pY3JvYmlvbWU6OnRyYW5zZm9ybShwc2VxLCAiaWRlbnRpdHkiKSlbImdfX0JhY3Rlcm9pZGVzIixdDQogeD1sb2cyKChmKzEpLyhiKzEpKQ0KDQojIElsbHVzdHJhdGUgdGhlIGRldGVjdGVkIHRpcHBpbmcgcG9pbnQNCnBsb3QoZGVuc2l0eSh4KSwgbWFpbiA9IHRheCkNCmFibGluZSh2ID0geFt0aXBwaW5nLnNhbXBsZXNdKQ0KaGlzdCh4LCBtYWluID0gdGF4KQ0KYWJsaW5lKHYgPSB4W3RpcHBpbmcuc2FtcGxlc10pDQoNCg0KDQoNCmBgYA0KDQpgYGB7cn0NCg0KZGF0YS5mcmFtZSh4KSAlPiUNCiAgbWVyZ2Uoc2FtcGxlX2RhdGEocHNlcSksIGJ5PSJyb3cubmFtZXMiKSAlPiUNCiAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICVpbiUgYygiMTUiLCIxIikpICU+JQ0KICBkcGx5cjo6cmVuYW1lKHRlc3Q9eCkgJT4lDQogIG11dGF0ZSh0aXA9aWZlbHNlKHRlc3QgPCB4W3RpcHBpbmcuc2FtcGxlc11bMV0sICJsb3ciLCAiaGlnaCIpKSAlPiUNCiAgd2l0aCguLHh0YWJzKH50aXArRW50ZXJvdHlwZXNfaWQsIGRhdGE9LikpICMlPiUgY2hpc3EudGVzdCgpDQoNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCiMjIGJ5IGJyYW5jaA0KDQoNCmBgYHtyfQ0KYnJhbmNoZXMgPSBjKCJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLCJQcmV2b3RlbGxhIERNTSB0eXBlcyIsICJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIsICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiKQ0KcmVzPU5VTEwNCmZvcihicmFuY2ggaW4gYnJhbmNoZXMpIHsNCiAgDQogIHNldC5zZWVkKDY2NikNCiAgcHNlcT1waHlsb3NlcShPVFU9Z2VudXNfZm9yX3BoeWxvc2VxLCBzYW1wbGVfZGF0YShtZXRhZGF0YV9mb3JfcGh5c2VxKSwgVEFYPXRheGFfZm9yX3BoeWxvc2VxICkNCiAgcHNlcSA8LSBwc2VxICU+JSBzdWJzZXRfc2FtcGxlcyh2YWx1ZT4wLjgwKQ0KICBwc2VxIDwtIHBzZXEgJT4lIHN1YnNldF9zYW1wbGVzKGJyYW5jaGVzID09IGJyYW5jaCkNCiAgcHNlcSA8LSBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0ocHNlcSwgImNvbXBvc2l0aW9uYWwiKQ0KICBwc2VxIDwtIGFnZ3JlZ2F0ZV9yYXJlKHBzZXEsIGxldmVsPSJnIiwgZGV0ZWN0aW9uID0gLjEvMTAwLCBwcmV2YWxlbmNlID0gNS8xMDApDQogIHBzZXEwIDwtIGJhc2VsaW5lKHBzZXEpDQogIGludGVybWVkaWF0ZS5zdGFiaWxpdHkgPC0gaW50ZXJtZWRpYXRlX3N0YWJpbGl0eShwc2VxLCBvdXRwdXQgPSAic2NvcmVzIikNCiAgcHNlcTAuY2xyIDwtIG1pY3JvYmlvbWU6OnRyYW5zZm9ybShwc2VxMCwgImNsciIpDQogIGJpbW9kYWxpdHkuc2NvcmUgPC0gYmltb2RhbGl0eShwc2VxMC5jbHIsIG1ldGhvZCA9ICJwb3RlbnRpYWxfYW5hbHlzaXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJzLml0ZXIgPSAxMDAsIHBlYWsudGhyZXNob2xkID0gMTAsDQogICAgICAgICAgICAgICAgICAgbWluLmRlbnNpdHkgPSAxMCkNCiAgDQogIHJlcz1yYmluZCgNCiAgYXNfdGliYmxlKGRhdGEuZnJhbWUoYmltb2RhbGl0eS5zY29yZSxpbnRlcm1lZGlhdGUuc3RhYmlsaXR5LCBicmFuY2hlcz1icmFuY2gpICU+JSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigidGF4YSIpKSwNCiAgcmVzDQogICkNCiAgDQp9DQpgYGANCg0KDQpgYGB7cn0NCm1lcmdlKHJlcywNCmRhdGEuZnJhbWUoYmltb2RhbGl0eV9zY29yZV9hbGw9Ymltb2RhbGl0eS5zY29yZSxpbnRlcm1lZGlhdGVfc3RhYmlsaXR5X2FsbD1pbnRlcm1lZGlhdGUuc3RhYmlsaXR5KSwNCmJ5Lnk9InJvdy5uYW1lcyIsIGJ5Lng9InRheGEiKSAlPiUNCiAgZmlsdGVyKGJyYW5jaGVzICE9ICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiKSAlPiUNCiAgZ2dwbG90ICsgZ2VvbV9wb2ludChhZXMoeD1pbnRlcm1lZGlhdGVfc3RhYmlsaXR5X2FsbCwgeT1pbnRlcm1lZGlhdGUuc3RhYmlsaXR5LCBjb2w9YnJhbmNoZXMpKSArDQogIGdlb21fYWJsaW5lKHNsb3BlPTEpDQogIA0KDQptZXJnZShyZXMsDQpkYXRhLmZyYW1lKGJpbW9kYWxpdHlfc2NvcmVfYWxsPWJpbW9kYWxpdHkuc2NvcmUsaW50ZXJtZWRpYXRlX3N0YWJpbGl0eV9hbGw9aW50ZXJtZWRpYXRlLnN0YWJpbGl0eSksDQpieS55PSJyb3cubmFtZXMiLCBieS54PSJ0YXhhIikgJT4lDQogIGZpbHRlcihicmFuY2hlcyAhPSAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIikgJT4lDQogIGZpbHRlcihpbnRlcm1lZGlhdGVfc3RhYmlsaXR5X2FsbD4wLGludGVybWVkaWF0ZS5zdGFiaWxpdHk8IC0wLjEsIGJpbW9kYWxpdHkuc2NvcmU+MC42KSAlPiUNCiAgYXJyYW5nZShicmFuY2hlcykgJT4lIHB1bGwodGF4YSkgJT4lIHVuaXF1ZSAtPiB0YXhhX2Jpc3RhYmxlX2JyYW5jaA0KICANCg0KbWVyZ2UocmVzLA0KZGF0YS5mcmFtZShiaW1vZGFsaXR5X3Njb3JlX2FsbD1iaW1vZGFsaXR5LnNjb3JlLGludGVybWVkaWF0ZV9zdGFiaWxpdHlfYWxsPWludGVybWVkaWF0ZS5zdGFiaWxpdHkpLA0KYnkueT0icm93Lm5hbWVzIiwgYnkueD0idGF4YSIpICU+JQ0KICBmaWx0ZXIoYnJhbmNoZXMgIT0gIkFra2VybWFuc2lhIERNTSB0eXBlcyIpICU+JQ0KICBmaWx0ZXIoaW50ZXJtZWRpYXRlX3N0YWJpbGl0eV9hbGw8IC0wLjEsaW50ZXJtZWRpYXRlLnN0YWJpbGl0eT4wLCBiaW1vZGFsaXR5X3Njb3JlX2FsbD4wLjYpICU+JQ0KICBhcnJhbmdlKGJyYW5jaGVzKSAlPiUgcHVsbCh0YXhhKSAlPiUgdW5pcXVlDQoNCg0KZGF0YS5mcmFtZShiaW1vZGFsaXR5X3Njb3JlX2FsbD1iaW1vZGFsaXR5LnNjb3JlLGludGVybWVkaWF0ZV9zdGFiaWxpdHlfYWxsPWludGVybWVkaWF0ZS5zdGFiaWxpdHkpICU+JQ0KICBmaWx0ZXIoaW50ZXJtZWRpYXRlX3N0YWJpbGl0eV9hbGw8IC0wLjEsIGJpbW9kYWxpdHlfc2NvcmVfYWxsPjAuNikgJT4lDQogIHJvdy5uYW1lcygpIC0+IHRheGFfYmlzdGFibGVfYWxsDQoNCg0KDQoNCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQoNCnBzZXE9cGh5bG9zZXEoT1RVPWdlbnVzX2Zvcl9waHlsb3NlcSwgc2FtcGxlX2RhdGEobWV0YWRhdGFfZm9yX3BoeXNlcSksIFRBWD10YXhhX2Zvcl9waHlsb3NlcSApDQoNCnBzZXEwIDwtIGJhc2VsaW5lKHBzZXEpDQoNCnNhbXBsZV9kYXRhKHBzZXEpICU+JQ0KICBhc190aWJibGUoKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gYXMuY2hhcmFjdGVyKEVudGVyb3R5cGVzX2lkKSkgJT4lDQogIGdyb3VwX2J5KHN1YmplY3QpICU+JQ0KICBhcnJhbmdlKHN1YmplY3QpICU+JQ0KICBtdXRhdGUobj1uKCkpICU+JQ0KICBmaWx0ZXIobj4xKSAlPiUNCiAgYXJyYW5nZShzdWJqZWN0LHRpbWUpICU+JQ0KICBtdXRhdGUoc2FtcGxlX2JlZm9yZSA9IGxhZyhzYW1wbGUpLCB0aW1lX2JlZm9yZT1sYWcodGltZSksIEVudGVyb3R5cGVzX2lkX2JlZm9yZT1sYWcoRW50ZXJvdHlwZXNfaWQpKSAlPiUNCiAgZmlsdGVyKCEodGltZV9iZWZvcmU9PXRpbWUpKSAlPiUNCiAgc2VsZWN0KHN1YmplY3QsdGltZSx0aW1lX2JlZm9yZSxzYW1wbGUsc2FtcGxlX2JlZm9yZSxFbnRlcm90eXBlc19pZCxFbnRlcm90eXBlc19pZF9iZWZvcmUpICU+JQ0KICBtdXRhdGUocGFydGl0aW9uX3N0YWJpbGl0eT1pZmVsc2UoRW50ZXJvdHlwZXNfaWRfYmVmb3JlPT1FbnRlcm90eXBlc19pZCwic3RhYmxlIiwidW5zdGFibGUiKSkgLT4gbWV0YWRhdGFfdGltZV9sYWcNCiAgDQpzYW1wbGVzX3RpbWVfc2VyaWVzID0gc2FtcGxlX2RhdGEocHNlcSkgJT4lIGFzX3RpYmJsZSgpICU+JSBncm91cF9ieShzdWJqZWN0KSAlPiUgbXV0YXRlKG49bigpKSAlPiUgZmlsdGVyKG4+MSkgJT4lIHB1bGwoc2FtcGxlKQ0KDQoNCg0KcHNlcSAlPiUNCiAgYWdncmVnYXRlX3JhcmUobGV2ZWw9ImciLCBkZXRlY3Rpb24gPSAuMS8xMDAsIHByZXZhbGVuY2UgPSA1LzEwMCkgJT4lDQogIG1pY3JvYmlvbWU6OnRyYW5zZm9ybSgiY2xyIikgJT4lDQogIG90dV90YWJsZSgpICU+JQ0KICBkYXRhLmZyYW1lKGNoZWNrLm5hbWVzID0gRkFMU0UpICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigidGF4YSIpICU+JQ0KICBhc190aWJibGUoKSAlPiUNCiAgZmlsdGVyKHRheGEgJWluJSBjKHRheGFfYmlzdGFibGVfYnJhbmNoLHRheGFfYmlzdGFibGVfYWxsKSkgLT4gZGZfdG1wDQogIA0KZGZfdG1wICU+JSANCiAgc2VsZWN0KHRheGEsIGFsbF9vZihzYW1wbGVzX3RpbWVfc2VyaWVzKSkgJT4lDQogIHJlc2hhcGUyOjptZWx0KCkgLT4gdGF4YV90aW1lX21lbHQNCg0KDQptZXRhZGF0YV90aW1lX2xhZyAlPiUNCiAgbWVyZ2UodGF4YV90aW1lX21lbHQsIGJ5Lng9InNhbXBsZSIsIGJ5Lnk9InZhcmlhYmxlIikgJT4lDQogIG1lcmdlKHRheGFfdGltZV9tZWx0LCBieS54PWMoInRheGEiLCJzYW1wbGVfYmVmb3JlIiksIGJ5Lnk9YygidGF4YSIsInZhcmlhYmxlIikpIC0+IG1ldGFkYXRhX3RheGFfdGltZV9sYWcNCg0KDQoNCg0KYGBgDQoNCg0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTd9DQptZXRhZGF0YV90YXhhX3RpbWVfbGFnICU+JQ0KICBmaWx0ZXIodGF4YSAlaW4lIGMoImdfX0xhY3RvYmFjaWxsdXMiLCJnX19EZXN1bGZvdmlicmlvIikpICU+JQ0KICBtdXRhdGUodmFsdWVfYWJzPWlmZWxzZSh2YWx1ZS54PHZhbHVlLnksIHZhbHVlLngsIHZhbHVlLnkpKSAlPiUNCiAgbXV0YXRlKGRlbHRhID0gYWJzKHZhbHVlLngtdmFsdWUueSkpICU+JQ0KICBtdXRhdGUoc3dpdGNoID0gcGFzdGUoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLEVudGVyb3R5cGVzX2lkLCBzZXA9Il8iKSkgJT4lDQogIGdyb3VwX2J5KHN3aXRjaCkgJT4lDQogIG11dGF0ZShuX3N3aXRjaCA9IG4oKSkgJT4lDQogIGZpbHRlcihuX3N3aXRjaCA+IDE1KSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBncm91cF9ieSh0YXhhKSAlPiUNCiAgbXV0YXRlKHNhbXBsZSA9IHNhbXBsZSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIodmFsdWVfYWJzLCAuZGVzYz1UUlVFKSkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9zZWdtZW50KGFlcyh4PXZhbHVlLngsIHhlbmQ9dmFsdWUueSx5PXNhbXBsZSx5ZW5kPXNhbXBsZSwgY29sPXBhcnRpdGlvbl9zdGFiaWxpdHkpKSArIA0KICBmYWNldF9ncmlkKHN3aXRjaH50YXhhLCBzY2FsZXMgPSAiZnJlZSIpICsgDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JleSIsInBpbmsiKSkgKw0KICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkNCg0KDQptZXRhZGF0YV90YXhhX3RpbWVfbGFnICU+JQ0KICBmaWx0ZXIodGF4YSAlaW4lIGMoImdfX01ldGhhbm9icmV2aWJhY3RlciIsImdfX0Rlc3VsZm92aWJyaW8iKSkgJT4lDQogIG11dGF0ZSh2YWx1ZV9hYnM9aWZlbHNlKHZhbHVlLng8dmFsdWUueSwgdmFsdWUueCwgdmFsdWUueSkpICU+JQ0KICBtdXRhdGUoZGVsdGEgPSBhYnMoKHZhbHVlLngrdmFsdWUueSkvMikpICU+JQ0KICBtdXRhdGUoc3dpdGNoID0gcGFzdGUoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLEVudGVyb3R5cGVzX2lkLCBzZXA9Il8iKSkgJT4lDQogIGdyb3VwX2J5KHN3aXRjaCkgJT4lDQogIG11dGF0ZShuX3N3aXRjaCA9IG4oKSkgJT4lDQogIGZpbHRlcihuX3N3aXRjaCA+IDYpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9ib3hwbG90KGFlcyh4PXN3aXRjaCx5PWRlbHRhKSkgKyANCiAgZmFjZXRfZ3JpZChwYXJ0aXRpb25fc3RhYmlsaXR5fnRheGEsIHNjYWxlPSJmcmVlIiwgc3BhY2UgPSAiZnJlZV95IiApICsNCiAgY29vcmRfZmxpcCgpDQoNCg0KbWV0YWRhdGFfdGF4YV90aW1lX2xhZyAlPiUNCiAgZmlsdGVyKHRheGEgJWluJSBjKCJnX19QcmV2b3RlbGxhIiwiZ19fT2RvcmliYWN0ZXIiKSkgJT4lDQogIG11dGF0ZSh2YWx1ZV9hYnM9aWZlbHNlKHZhbHVlLng8dmFsdWUueSwgdmFsdWUueCwgdmFsdWUueSkpICU+JQ0KICBtdXRhdGUodmFsdWVfbSA9ICgodmFsdWUueCt2YWx1ZS55KS8yKSkgJT4lDQogIG11dGF0ZShkZWx0YSA9IGFicyh2YWx1ZS54LXZhbHVlLnkpKSAlPiUNCiAgbXV0YXRlKHN3aXRjaCA9IHBhc3RlKEVudGVyb3R5cGVzX2lkX2JlZm9yZSxFbnRlcm90eXBlc19pZCwgc2VwPSJfIikpICU+JQ0KICBncm91cF9ieShzd2l0Y2gpICU+JQ0KICBtdXRhdGUobl9zd2l0Y2ggPSBuKCkpICU+JQ0KICAjZmlsdGVyKG5fc3dpdGNoID4gMTUpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogICNmaWx0ZXIocGFydGl0aW9uX3N0YWJpbGl0eT09InVuc3RhYmxlIikgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoeD12YWx1ZV9tLHk9ZGVsdGEsY29sPXBhcnRpdGlvbl9zdGFiaWxpdHkpKSArIA0KICBmYWNldF9ncmlkKHBhcnRpdGlvbl9zdGFiaWxpdHl+dGF4YSkNCg0KDQptZXRhZGF0YV90YXhhX3RpbWVfbGFnICU+JQ0KICBmaWx0ZXIodGF4YSAlaW4lIGMoImdfX1ByZXZvdGVsbGEiLCJnX19CYWNpbGx1cyIpKSAlPiUNCiAgbXV0YXRlKHZhbHVlX2Ficz1pZmVsc2UodmFsdWUueDx2YWx1ZS55LCB2YWx1ZS54LCB2YWx1ZS55KSkgJT4lDQogIG11dGF0ZSh2YWx1ZV9tID0gYWJzKCh2YWx1ZS54K3ZhbHVlLnkpLzIpKSAlPiUNCiAgbXV0YXRlKGRlbHRhID0gYWJzKHZhbHVlLngtdmFsdWUueSkpICU+JQ0KICBtdXRhdGUoc3dpdGNoID0gcGFzdGUoRW50ZXJvdHlwZXNfaWRfYmVmb3JlLEVudGVyb3R5cGVzX2lkLCBzZXA9Il8iKSkgJT4lDQogIGdyb3VwX2J5KHN3aXRjaCkgJT4lDQogIG11dGF0ZShuX3N3aXRjaCA9IG4oKSkgJT4lDQogICNmaWx0ZXIobl9zd2l0Y2ggPiAxNSkgJT4lDQogIHVuZ3JvdXAoKQ0KYGBgDQoNCg0KYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9N30NCnJlcz1OVUxMDQoNCmZvcihpIGluIDE6MTcpew0KICANCiAgZm9yKGogaW4gaToxOCkgew0KICANCiAgICBpZihpPT1qKSBuZXh0DQogICAgDQppPWFzLmNoYXJhY3RlcihpKSAgICANCmo9YXMuY2hhcmFjdGVyKGopDQoNCnN3aXRjaD1wYXN0ZShpLGosIHNlcD0iXyIpDQogICAgDQptZXRhZGF0YV90YXhhX3RpbWVfbGFnICU+JQ0KICAjZmlsdGVyKHRheGEgJWluJSBjKCJnX19QcmV2b3RlbGxhIiwiZ19fT2RvcmliYWN0ZXIiKSkgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAlaW4lIGMoaSxqKSwgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYyhpLGopKSAlPiUNCiAgbXV0YXRlKGRlbHRhPSBhYnModmFsdWUueC12YWx1ZS55KSkgLT4gdG1wMQ0KDQppZihsZW5ndGgobmFtZXModGFibGUodG1wMSRwYXJ0aXRpb25fc3RhYmlsaXR5KSkpID09IDEpIHtuZXh0fQ0KDQp0bXAxICU+JQ0KICBncm91cF9ieSh0YXhhKSAlPiUNCiAgZG8od2l0aCguLHdpbGNveC50ZXN0KGRlbHRhfnBhcnRpdGlvbl9zdGFiaWxpdHksIGRhdGE9LikgJT4lIGJyb29tOjp0aWR5KCkpKSAlPiUNCiAgZmlsdGVyKHAudmFsdWU8MC4wNSkgJT4lDQogIG11dGF0ZShzd2l0Y2g9c3dpdGNoKSAtPiB0bXAyDQogIA0KcmVzPXJiaW5kKHRtcDIscmVzKQ0KDQogIA0KICB9IH0NCg0KcmVzICU+JSBzZWxlY3QodGF4YSxzd2l0Y2gpDQpgYGANCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD03fQ0KcmVzMj1OVUxMDQoNCmZvcihpIGluIDE6MTcpew0KICANCiAgZm9yKGogaW4gaToxOCkgew0KICANCiAgICBpZihpPT1qKSBuZXh0DQogICAgDQppPWFzLmNoYXJhY3RlcihpKSAgICANCmo9YXMuY2hhcmFjdGVyKGopDQoNCnN3aXRjaD1wYXN0ZShpLGosIHNlcD0iXyIpDQoNCm1ldGFkYXRhX3RheGFfdGltZV9sYWcgJT4lDQogICNmaWx0ZXIodGF4YSAlaW4lIGMoImdfX1ByZXZvdGVsbGEiLCJnX19PZG9yaWJhY3RlciIpKSAlPiUNCiAgZmlsdGVyKEVudGVyb3R5cGVzX2lkICVpbiUgYyhpLGopLCBFbnRlcm90eXBlc19pZF9iZWZvcmUgJWluJSBjKGksaikpICU+JQ0KICBtdXRhdGUodmFsdWVfbT0odmFsdWUueCt2YWx1ZS55LzIpKSAlPiUNCiAgI2ZpbHRlcihwYXJ0aXRpb25fc3RhYmlsaXR5ID09ICJ1bnN0YWJsZSIpICU+JQ0KICBncm91cF9ieSh0YXhhKSAlPiUNCiAgZG8od2l0aCguLHdpbGNveC50ZXN0KHZhbHVlLnh+RW50ZXJvdHlwZXNfaWQsIGRhdGE9LikgJT4lIGJyb29tOjp0aWR5KCkpKSAlPiUNCiAgZmlsdGVyKHAudmFsdWU8MC4wNSkgJT4lDQogIG11dGF0ZShzd2l0Y2g9c3dpdGNoKSAtPiB0bXANCg0KDQoNCnJlczI9cmJpbmQodG1wLHJlczIpDQoNCiAgDQogIH0gfQ0KDQpyZXMyDQoNCg0KDQoNCmBgYA0KDQpgYGB7cn0NCg0KbWVyZ2UocmVzICU+JSBzZWxlY3QodGF4YSwgc3dpdGNoKSwNCnJlczIgJT4lIHNlbGVjdCh0YXhhLCBzd2l0Y2gpLCBieT1jKCJ0YXhhIiwic3dpdGNoIikpDQoNCg0KDQpgYGANCg0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTd9DQptZXRhZGF0YV90YXhhX3RpbWVfbGFnICU+JQ0KICAjZmlsdGVyKHRheGEgJWluJSBjKCJnX19QcmV2b3RlbGxhIiwiZ19fT2RvcmliYWN0ZXIiKSkgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAlaW4lIGMoIjMiLCI1IiksIEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoIjMiLCI1IikpICU+JQ0KICBtdXRhdGUodmFsdWVfbT0odmFsdWUueCt2YWx1ZS55LzIpKSAlPiUNCiAgI2ZpbHRlcihwYXJ0aXRpb25fc3RhYmlsaXR5ID09ICJ1bnN0YWJsZSIpICU+JQ0KICBncm91cF9ieSh0YXhhKSAlPiUNCiAgZG8od2l0aCguLHdpbGNveC50ZXN0KHZhbHVlLnh+RW50ZXJvdHlwZXNfaWQsIGRhdGE9LikgJT4lIGJyb29tOjp0aWR5KCkpKSAlPiUNCiAgZmlsdGVyKHAudmFsdWU8MC4wNSkNCg0KDQoNCg0KbWV0YWRhdGFfdGF4YV90aW1lX2xhZyAlPiUNCiAgZmlsdGVyKHRheGEgJWluJSBjKCJnX19QcmV2b3RlbGxhIiwiZ19fT2RvcmliYWN0ZXIiKSkgJT4lDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCAlaW4lIGMoIjMiLCI1IiksIEVudGVyb3R5cGVzX2lkX2JlZm9yZSAlaW4lIGMoIjMiLCI1IikpICU+JQ0KICBmaWx0ZXIocGFydGl0aW9uX3N0YWJpbGl0eSA9PSAidW5zdGFibGUiKSAlPiUNCiAgbXV0YXRlKHZhbHVlX209KHZhbHVlLngrdmFsdWUueS8yKSkgJT4lDQogIGdncGxvdCgpICsgZ2dmb3JjZTo6Z2VvbV9zaW5hKGFlcyh4PUVudGVyb3R5cGVzX2lkLCB5PXZhbHVlX20pKQ0KDQoNCg0KDQptZXRhZGF0YV90YXhhX3RpbWVfbGFnICU+JQ0KICBmaWx0ZXIodGF4YSAlaW4lIGMoImdfX0Fra2VybWFuc2lhIikpICU+JQ0KICAjZmlsdGVyKEVudGVyb3R5cGVzX2lkICVpbiUgYygiMSIsIjUiLCI5IiwiMTIiKSwgRW50ZXJvdHlwZXNfaWRfYmVmb3JlICVpbiUgYygiMSIsIjUiLCI5IiwiMTIiKSkgJT4lDQogIG11dGF0ZShzd2l0Y2ggPSBwYXN0ZShFbnRlcm90eXBlc19pZF9iZWZvcmUsRW50ZXJvdHlwZXNfaWQsIHNlcD0iXyIpKSAlPiUNCiAgbXV0YXRlKHZhbHVlX209KHZhbHVlLngrdmFsdWUueS8yKSkgJT4lDQogIG11dGF0ZShzYW1wbGUgPSBzYW1wbGUgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHZhbHVlX20sIC5kZXNjPVRSVUUpKSAlPiUNCiAgI2ZpbHRlcihwYXJ0aXRpb25fc3RhYmlsaXR5PT0ic3RhYmxlIikgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9zZWdtZW50KGFlcyh4PXZhbHVlLngsIHhlbmQ9dmFsdWUueSx5PXNhbXBsZSx5ZW5kPXNhbXBsZSkpICsgDQogIGZhY2V0X2dyaWQocGFydGl0aW9uX3N0YWJpbGl0eX50YXhhLCBzY2FsZXMgPSAiZnJlZSIpICsgDQogICNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImdyZXkiLCJwaW5rIikpICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpDQoNCg0KYGBgDQoNCg0K