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
    
  

f/b p/b ratio figure


p_fprau_density / p_fprau_partition|p_prevotella_density / p_prevotella_partition

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

Full figure


((fig5A) | (fig5B_full/fig5C_full)) + plot_annotation(tag_levels = "a") + plot_layout(widths = c(2,1.5))


p_fprau_density / p_fprau_partition|p_prevotella_density / p_prevotella_partition


fig5I_full





(
  (fig5A + theme(plot.tag = element_text(face = "bold"))) | 
    
  ((p_fprau_density / p_fprau_partition + ylab("Bacteroides\nDMM types")) + plot_layout(heights = c(1,2)) ) |
    
  (((p_prevotella_density + xlab("Prevotella Bacteroides ratio\nwithin Prevotella enriched branch")) / (p_prevotella_partition + ylab("Prevotella\nDMM types"))) + plot_layout(heights = c(1,2)) ) + 
    plot_layout(widths = c(4,1,1))
  
  ) /
  
(fig5B_full|fig5C_full|fig5I_full) + plot_annotation(tag_levels = "a")

NA
NA
NA
NA
NA

figure for publication

(p_fprau_density+geom_vline(xintercept = 1/4))/
              (p_fprau_partition+  geom_vline(xintercept = 1/4)) + 
              plot_layout(heights = c(1,2)) 
Error: object 'p_fprau_density' not found


fig5J_ellispse_scaled + fig5K_ellispse_scaled + plot_annotation(tag_levels = "a")

ggsave(file="figureS9_bis.pdf")

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

intermediate stability quantification


intermediate_stability_alr = function (x, reference.point = NULL, method = "correlation", 
    output = "scores"){
    x0 <- x
    if (length(reference.point) > 1 && output == "scores") {
        scores <- c()
        for (i in seq_len(length(reference.point))) {
            scores[[i]] <- intermediate_stability(x, reference.point = reference.point[[i]], 
                method = method, output = output)
        }
        if (ntaxa(x) > 1) {
            scores <- as.data.frame(scores, nrow = ntaxa(x))
        }
        else {
            scores <- as.data.frame(t(as.matrix(scores, ncol = length(reference.point))))
        }
        colnames(scores) <- as.character(reference.point)
        rownames(scores) <- taxa(x)
        return(scores)
    }
    x <- abundances(transform(x0, "identity"))
    b <- abundances(transform(x0, "identity"))["g__Bacteroides"]
    x = log2((x+1)/(b+1))
    meta <- sample_data(x0)
    stability <- list()
    df <- meta
    df$time <- as.numeric(as.character(df$time))
    df <- df[df$subject %in% names(which(table(df$subject) > 
        1)), ]
    spl <- split(df, as.character(df$subject))
    spl.list <- list()
    for (i in seq_len(length(spl))) {
        spl.list[[i]] <- list(spl = spl[[i]][order(spl[[i]]$time), 
            ], time.difs = diff(spl[[i]]$time))
    }
    for (tax in rownames(x)) {
        df$data <- x[tax, rownames(df)]
        stability[[tax]] <- estimate_stability(df, reference.point = reference.point, 
            method = method, spl.list)
    }
    if (output == "full") {
        return(stability)
    }
    else if (output == "scores") {
        intermediate.stability <- vapply(stability, function(x) {
            x$stability
        }, 1)
        return(intermediate.stability)
    }
}


# Here we use the (non-baseline) phyloseq object that contains time series.
intermediate.stability <- intermediate_stability_alr(pseq, output = "scores", method = "correlations") #clr transfo included

intermediate.stability %>% sort %>% round(3)

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)

Comparing bimodality and intermediate stability


taxa <- taxa(pseq0)
df <- data.frame(group = as.character(taxa) %>% gsub("g__","",.),
intermediate.stability = intermediate.stability[taxa],
bimodality = bimodality.score[taxa])
theme_set(theme_bw(20))

df = df %>%
  mutate(group = group %>% as.character()) %>%
  mutate(label = ifelse(bimodality > 0.6 & intermediate.stability < 0, group, ''))

df %>%
  filter(bimodality > 0.6 & intermediate.stability < -0.1) %>%
  arrange(intermediate.stability)


library(ggrepel)

p <- ggplot(df,
  aes(x = intermediate.stability, y = bimodality, label = '')) + #Doesn't add labels to points
  geom_text_repel() +
  geom_point()

#Labels only those that have bimodality > 0.4 and intermediate stability < 0, adjusts the placement of labels
p <- p + geom_text(aes(label = ifelse(bimodality > 0.6 & intermediate.stability < -0.25, group, '')), vjust = "inward", hjust = "inward")

print(p)

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