enterotypes = readr::read_csv2("enterotypes_prediction_outliers.csv")[,-1] %>% filter(!is.na(Enterotypes_id))
ℹ 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,"")

metadata %>% .[1:5,1:5]


data("UNSD_countries")

metadata <- metadata %>% 
  #select(SAMPLE_NAME, COUNTRY_OF_BIRTH) %>%
  merge(UNSD_countries %>% 
          select(`Country or Area`, `Sub-region Name`, `Region Name`) %>% 
          mutate(`Country or Area` =  gsub("United Kingdom of Great Britain and Northern Ireland", "United Kingdom", `Country or Area`)) %>% 
          mutate(`Country or Area` =  gsub("United States of America", "USA", `Country or Area`)) %>%
          mutate(`Sub-region Name` =  ifelse(`Sub-region Name` %in% c("Central Asia", "Southern Asia"), "Central and Southern Asia",`Sub-region Name`)) %>%
          mutate(`Sub-region Name` =  ifelse(`Sub-region Name` %in% c("Melanesia", "Micronesia","Polynesia"), "Oceania (others)",`Sub-region Name`)), 
        by.x="COUNTRY_OF_BIRTH", by.y="Country or Area", all.x = TRUE)




variable_to_remove= c("HEIGHT_CM", 
"WEIGHT_KG",
"SAMPLE_TYPE",
"BMI_CAT",
"HOST_SUBJECT_ID",
"ANONYMIZED_NAME",
"ASSIGNED_FROM_GEO",
"BIRTH_YEAR",
"DESCRIPTION",
"DNA_EXTRACTED",
"HEIGHT_UNITS",
"WEIGHT_UNITS",
"SCIENTIFIC_NAME",
"SURVEY_ID",
"TAXON_ID",
"WEIGHT_UNITS",
"VIOSCREEN_STATUS","VIOSCREEN_SURVEYID","PUBLIC","TITLE","GEO_LOC_NAME")




health_metadata = c("BMI_CAT",
"ANTIBIOTIC_HISTORY" ,
"ALZHEIMERS",
"AUTOIMMUNE",
"CANCER",
"DIABETES",
"IBD",
"IBS",
"KIDNEY_DISEASE",
"ACID_REFLUX",
"ALLERGIC_TO_I_HAVE_NO_FOOD_ALLERGIES_THAT_I_KNOW_OF",
"CARDIOVASCULAR_DISEASE",
"CDIFF",
"DEPRESSION_BIPOLAR_SCHIZOPHRENIA",
"EPILEPSY_OR_SEIZURE_DISORDER",
"FUNGAL_OVERGROWTH",
"GLUTEN",
"LACTOSE",
"LIVER_DISEASE",
"LUNG_DISEASE",
"MENTAL_ILLNESS",
"MIGRAINE",
"PKU",
"SIBO",
"THYROID")

diet_variables =
  c("TYPES_OF_PLANTS",
  "DIET_TYPE",
  "ALCOHOL_FREQUENCY",
  "RED_MEAT_FREQUENCY",
  "WHOLE_GRAIN_FREQUENCY",
  "VEGETABLE_FREQUENCY",
  "MEAT_EGGS_FREQUENCY",
  "PREPARED_MEALS_FREQUENCY",
  "FRUIT_FREQUENCY",
  "ONE_LITER_OF_WATER_A_DAY_FREQUENCY",
  "SEAFOOD_FREQUENCY",
  "HOMECOOKED_MEALS_FREQUENCY",
  "HIGH_FAT_RED_MEAT_FREQUENCY",
  "READY_TO_EAT_MEALS_FREQUENCY",
  "SUGAR_SWEETENED_DRINK_FREQUENCY",
  "SUGARY_SWEETS_FREQUENCY",
  "SALTED_SNACKS_FREQUENCY",
  "SPECIALIZED_DIET_FODMAP",
  "SPECIALIZED_DIET_EXCLUDE_DAIRY",
  "SPECIALIZED_DIET_EXCLUDE_NIGHTSHADES",
  "SPECIALIZED_DIET_MODIFIED_PALEO_DIET",
  "SPECIALIZED_DIET_PALEODIET_OR_PRIMAL_DIET",
  "OLIVE_OIL")

enterotypes %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% select(SAMPLE_NAME,ANTIBIOTIC_HISTORY),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(ANTIBIOTIC_HISTORY = dplyr::recode_factor(ANTIBIOTIC_HISTORY,   
                             `I have not taken antibiotics in the past year.`="I have not taken antibiotics in the past year.",
                             `Year`="Year", `6 months`="6 months",  
                             `Month`="Month", `Week` = "Week",  
                             .ordered = TRUE)  ) %>%
  select(-SAMPLE_NAME,-`19`) -> df_test
  
polr_model = MASS::polr(ANTIBIOTIC_HISTORY ~ ., data = df_test, Hess=TRUE)

summary(polr_model)
Call:
MASS::polr(formula = ANTIBIOTIC_HISTORY ~ ., data = df_test, 
    Hess = TRUE)

Coefficients:
       Value Std. Error t value
`1`  -1.3385     0.1255 -10.667
`2`  -0.9025     0.1180  -7.649
`3`  -1.0740     0.1198  -8.966
`4`  -0.8686     0.1207  -7.197
`5`  -1.3373     0.1234 -10.838
`6`  -0.7667     0.1188  -6.452
`7`  -1.2953     0.1295 -10.005
`8`  -0.6436     0.1216  -5.295
`9`  -0.6512     0.1220  -5.338
`10` -0.2498     0.1181  -2.115
`11` -0.2414     0.1246  -1.938
`12` -0.9527     0.1318  -7.228
`13` -0.6256     0.1247  -5.017
`14` -1.4279     0.1598  -8.938
`15`  0.4592     0.1242   3.698
`16` -0.6848     0.1524  -4.494
`17` -0.9662     0.1637  -5.903
`18` -0.9273     0.1786  -5.191

Intercepts:
                                                    Value    Std. Error t value 
I have not taken antibiotics in the past year.|Year  -0.0475   0.1025    -0.4633
Year|6 months                                         0.7979   0.1027     7.7659
6 months|Month                                        2.1292   0.1062    20.0430
Month|Week                                            3.1388   0.1147    27.3689

Residual Deviance: 30339.40 
AIC: 30383.40 
exp(coef(polr_model))
      `1`       `2`       `3`       `4`       `5`       `6`       `7`       `8`       `9`      `10`      `11` 
0.2622394 0.4055686 0.3416509 0.4195224 0.2625527 0.4645654 0.2738110 0.5253882 0.5214126 0.7789634 0.7854937 
     `12`      `13`      `14`      `15`      `16`      `17`      `18` 
0.3857055 0.5349344 0.2398110 1.5828795 0.5041748 0.3805119 0.3956386 
ctable <- coef(summary(polr_model))

p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
ctable <- cbind(ctable, "p value" = p)

ci <- confint(polr_model)
Attente de la réalisation du profilage...
metadata$TYPES_OF_PLANTS %>% table


enterotypes %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% select(SAMPLE_NAME,TYPES_OF_PLANTS),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(TYPES_OF_PLANTS = dplyr::recode_factor(TYPES_OF_PLANTS,   
                             `Less than 5`="Less than 5",
                             `6 to 10`="6 to 10", `11 to 20`="11 to 20",  
                             `21 to 30`="21 to 30", `More than 30` = "More than 30",  
                             .ordered = TRUE)  ) %>%
  select(-SAMPLE_NAME,-`19`) -> df_test
  
polr_model = MASS::polr(TYPES_OF_PLANTS ~ ., data = df_test, Hess=TRUE)

summary(polr_model)

exp(coef(polr_model))

ctable <- coef(summary(polr_model))

p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
ctable <- cbind(ctable, "p value" = p)

ci <- confint(polr_model)

exp(cbind(OR = coef(polr_model), ci))
ctable

metadata$ONE_LITER_OF_WATER_A_DAY_FREQUENCY %>% table

enterotypes %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% select(SAMPLE_NAME,ONE_LITER_OF_WATER_A_DAY_FREQUENCY),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(ONE_LITER_OF_WATER_A_DAY_FREQUENCY = dplyr::recode_factor(ONE_LITER_OF_WATER_A_DAY_FREQUENCY,   
                             `Never`="Never",
                             `Rarely`="Rarely (less than once/week)",
                             `Occasionally`="Occasionally (1-2 times/week)",  
                             `Regularly`="Regularly (3-5 times/week)", 
                             `Daily` = "Daily",  
                             .ordered = TRUE)  ) %>%
  select(-SAMPLE_NAME,-`19`) -> df_test
  
polr_model = MASS::polr(ONE_LITER_OF_WATER_A_DAY_FREQUENCY ~ ., data = df_test, Hess=TRUE)

summary(polr_model)

exp(coef(polr_model))

ctable <- coef(summary(polr_model))

p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
ctable <- cbind(ctable, "p value" = p)

ci <- confint(polr_model)

exp(cbind(OR = coef(polr_model), ci))
ctable

diet_variables =
  c("TYPES_OF_PLANTS",
  "DIET_TYPE",
  "ALCOHOL_FREQUENCY",
  "RED_MEAT_FREQUENCY",
  "WHOLE_GRAIN_FREQUENCY",
  "VEGETABLE_FREQUENCY",
  "MEAT_EGGS_FREQUENCY",
  "PREPARED_MEALS_FREQUENCY",
  "FRUIT_FREQUENCY",
  "ONE_LITER_OF_WATER_A_DAY_FREQUENCY",
  "SEAFOOD_FREQUENCY",
  "HOMECOOKED_MEALS_FREQUENCY",
  "HIGH_FAT_RED_MEAT_FREQUENCY",
  "READY_TO_EAT_MEALS_FREQUENCY",
  "SUGAR_SWEETENED_DRINK_FREQUENCY",
  "SUGARY_SWEETS_FREQUENCY",
  "SALTED_SNACKS_FREQUENCY",
  "SPECIALIZED_DIET_FODMAP",
  "SPECIALIZED_DIET_EXCLUDE_DAIRY",
  "SPECIALIZED_DIET_EXCLUDE_NIGHTSHADES",
  "SPECIALIZED_DIET_MODIFIED_PALEO_DIET",
  "SPECIALIZED_DIET_PALEODIET_OR_PRIMAL_DIET",
  "OLIVE_OIL")



prepare_data_for_modeling = function(target, levels_set, order_levels) {

  target <- enquo(target)
  #levels_set <- enquo(levels_set)
  
  levels_set=levels_set[levels_set %in% (metadata %>% select(SAMPLE_NAME,!!target) %>% pull(2) %>% unique())]
  
  
  enterotypes %>%
    reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
    merge(metadata %>% select(SAMPLE_NAME,!!target),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
    na.omit() %>%
    dplyr::rename(x := !!target) %>%
    mutate(x = forcats::fct_recode(x, !!!levels_set) %>% 
             factor(levels = order_levels , ordered = TRUE) )  %>%
    select(-SAMPLE_NAME,-`19`) -> df_test
  
return(df_test)
    
}



  
polr_modeling = function(data) {
  
  df_test=data
  
  polr_model = MASS::polr(x ~ ., data = df_test, Hess=TRUE)
  
  #summary(polr_model)
  
  #exp(coef(polr_model))
  
  ctable <- coef(summary(polr_model))
  p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
  ctable <- cbind(ctable, "p value" = p)
  suppressMessages(ci <- confint(polr_model))
  #exp(cbind(OR = coef(polr_model), ci))
  #ctable
  
  res=merge(exp(cbind(OR = coef(polr_model), ci)),ctable,by="row.names", all=TRUE)
  return(res)
}
    

target =
  c("RED_MEAT_FREQUENCY",
  "WHOLE_GRAIN_FREQUENCY",
  "VEGETABLE_FREQUENCY",
  "MEAT_EGGS_FREQUENCY",
  "PREPARED_MEALS_FREQUENCY",
  "FRUIT_FREQUENCY",
  "ONE_LITER_OF_WATER_A_DAY_FREQUENCY",
  "SEAFOOD_FREQUENCY",
  "HOMECOOKED_MEALS_FREQUENCY",
  "HIGH_FAT_RED_MEAT_FREQUENCY",
  "READY_TO_EAT_MEALS_FREQUENCY",
  "SUGAR_SWEETENED_DRINK_FREQUENCY",
  "SUGARY_SWEETS_FREQUENCY",
  "SALTED_SNACKS_FREQUENCY",
  "OLIVE_OIL")


#target = c("RED_MEAT_FREQUENCY","WHOLE_GRAIN_FREQUENCY")




levels_set = c(`Never`="Never",
                             `Rarely`="Rarely (less than once/week)",
                             `Occasionally`="Occasionally (1-2 times/week)",  
                             `Regularly`="Regularly (3-5 times/week)", 
                             `Daily` = "Daily")

order_levels = c("Never","Rarely","Occasionally","Regularly","Daily")


combine_polr_model_result = function(target,levels_set, order_levels){

  final_res = NULL
  
for(i in seq_along(target)) {
  
  cat("modeling",target[i],"...")
  
  res= prepare_data_for_modeling(target = target[i], levels_set=levels_set, order_levels=order_levels) %>% 
  polr_modeling()
  
  tmp=data.frame(target=target[i],res)
  
  final_res = rbind(final_res,tmp)
  
  cat(". done\n") }

  return(final_res) 
    
}


diet_final_res = combine_polr_model_result(target = target, levels_set=levels_set, order_levels=order_levels)

save(diet_final_res, file="diet_final_res.rda")


diet_final_res %>%
  mutate(Row.names = Row.names %>% as.character()) %>% 
  mutate(OR = cut(OR, breaks = c(0,1/4,1/2,1,2,4,100)) %>% as.character()) %>%
  filter(!is.na(OR)) %>% #pull(OR)
  mutate(OR = ifelse(p.value>0.05,"NS",OR)) %>% #pull(OR) %>% factor()
  mutate(OR = factor(OR, levels=c("(0.25,0.5]", "(0.5,1]", "NS", "(1,2]", "(2,4]", "(4,100]" )  )) %>% 
  filter(Row.names %in% paste0("`",as.character(1:20),"`")   ) %>%
  ggplot() + geom_tile(aes(x=Row.names%>%as.character, y=target, fill=OR)) + 
  scale_fill_manual("OR", labels=c("0.25-0.5","0.5-1","NS","1-2","2-4",">4"), 
                    values = c("#d8b365","#f6e8c3","#f5f5f5","#c7eae5","#5ab4ac","#01665e")) + cowplot::theme_cowplot()


diet_final_res %>%
  mutate(Row.names = Row.names %>% as.character()) %>%
  filter(!is.na(OR)) %>%
  mutate(OR=log(OR)) %>%
  reshape2::dcast(Row.names~target, value.var = "OR") %>%
  tibble::column_to_rownames("Row.names") %>%
  as.matrix() %>%
  t() %>%
  heatmap()



diet_final_res %>%
  mutate(Row.names = Row.names %>% as.character()) %>%
  filter(!is.na(OR)) %>%
  mutate(OR=log(OR)) %>%
  group_by(target) %>%
  mutate(OR=scale(OR)) %>%
  ggplot() + geom_tile(aes(x=Row.names%>%as.character, y=target, fill=OR)) + scale_fill_distiller("log\nOdds",type="div")

metadata %>% 
  select(contains("_FREQUENCY"), -OTHER_SUPPLEMENT_FREQUENCY, -FERMENTED_FREQUENCY, OLIVE_OIL) %>%
  colnames() -> target

levels_set = c(A = "Never",
               B = "Rarely (less than once/week)",
               B = "Rarely (less than once/week)",              
               C = "Occasionally (1-2 times/week)",  
               D = "Regularly (3-5 times/week)", 
               E = "Daily")

order_levels=LETTERS[1:5]

#order_levels = c("Never","Rarely","Occasionally","Regularly","Daily")

global_final_res = combine_polr_model_result(target = target[1:3], levels_set=levels_set, order_levels=order_levels)


#prepare_data_for_modeling(target = target[1], levels_set=levels_set, order_levels=order_levels)

metadata$`Sub-region Name` %>% table
metadata$`Region Name` %>% table

enterotypes %>%
  mutate(Enterotypes_id=paste0("et",Enterotypes_id)) %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% filter(COUNTRY %in% c("USA","Canada")) %>% select(SAMPLE_NAME,`Sub-region Name`),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(`Sub-region Name` = forcats::fct_relevel(`Sub-region Name`, ref = "Northern America")) %>%
  dplyr::rename(region=`Sub-region Name`) %>%
  select(-SAMPLE_NAME,-et19) -> df_region
  nnet::multinom(region ~ ., data = df_region) -> region_birth_model


region_birth_model_effects = ggeffects::ggeffect(region_birth_model)

save(region_birth_model, file="region_birth_model.rda")

region_birth_model_summary = summary(region_birth_model)

ci = confint(region_birth_model)

zvalues <- region_birth_model_summary$coefficients / region_birth_model_summary$standard.errors
pnorm(abs(zvalues), lower.tail=FALSE)*2


(100*(exp(coef(region_birth_model))-1)) %>% .[,-1] %>%  heatmap()


coef(region_birth_model) %>% .[,-1] %>% heatmap()

zvalues %>% .[,-1] %>% .[,-13]%>%  heatmap()

coef(region_birth_model) %>% .[,-1] %>% as.data.frame() %>%
  tibble::rownames_to_column("region") %>%
  reshape2::melt(id.vars="region") %>%
  group_by(region) %>%
  mutate(value=scale(value)) %>%
  ggplot() + geom_tile(aes(y=region,x=variable,fill=value)) + scale_fill_distiller(type="div")

rbind(coef(region_birth_model) %>% .[,-1] %>% as.data.frame() %>%
  tibble::rownames_to_column("region") %>%
  reshape2::melt(id.vars="region") %>%
  group_by(region) %>%
  mutate(value=scale(value)) %>% dplyr::rename(target=1,partition=2,OR=3) %>% select(1:3),


diet_final_res %>%
  mutate(Row.names = Row.names %>% as.character()) %>%
  filter(!is.na(OR)) %>%
  mutate(OR=log(OR)) %>%
  group_by(target) %>%
  mutate(OR=scale(OR))  %>% dplyr::rename(target=1,partition=2,OR=3) %>% select(1:3) ) %>%
  
  reshape2::dcast(partition~target, value.var = "OR") %>%
  tibble::column_to_rownames("partition") %>%
  as.matrix() %>%
  t() %>%
  heatmap(col = hcl.colors(12, "BrBG", rev = TRUE))


metadata$GLUTEN %>% table

enterotypes %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% select(SAMPLE_NAME,GLUTEN),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(GLUTEN = forcats::fct_recode(GLUTEN,   
                             `No`="No",
                             `Yes`="I do not eat gluten because it makes me feel bad",
                             `Yes`="I was diagnosed with celiac disease",  
                             `medium`="I was diagnosed with gluten allergy (anti-gluten IgG), but not celiac disease") %>% 
           factor(levels = c("No","medium","Yes") , ordered = TRUE) )  %>%
  select(-SAMPLE_NAME,-`19`) -> df_test
  
polr_model = MASS::polr(GLUTEN ~ ., data = df_test, Hess=TRUE)

summary(polr_model)

exp(coef(polr_model))

ctable <- coef(summary(polr_model))

p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
ctable <- cbind(ctable, "p value" = p)

ci <- confint(polr_model)

exp(cbind(OR = coef(polr_model), ci))
ctable


metadata$GLUTEN %>% table

enterotypes %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% select(SAMPLE_NAME,GLUTEN),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(GLUTEN = forcats::fct_recode(GLUTEN,   
                             `No`="No",
                             `Yes`="I do not eat gluten because it makes me feel bad",
                             `Yes`="I was diagnosed with celiac disease",  
                             `Yes`="I was diagnosed with gluten allergy (anti-gluten IgG), but not celiac disease") %>% 
           factor(levels = c("No","Yes") , ordered = TRUE) )  %>%
  select(-SAMPLE_NAME,-`19`) -> df_test
  
polr_model = glm(GLUTEN ~ ., data = df_test, family=binomial)

summary(polr_model)

exp(coef(polr_model))

ctable <- coef(summary(polr_model))

#p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
#ctable <- cbind(ctable, "p value" = p)

ci <- confint(polr_model)

exp(cbind(OR = coef(polr_model), ci))
ctable


metadata$SPECIALIZED_DIET_EXCLUDE_NIGHTSHADES %>% table

enterotypes %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% select(SAMPLE_NAME,SPECIALIZED_DIET_EXCLUDE_DAIRY),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(SPECIALIZED_DIET_EXCLUDE_DAIRY = forcats::fct_recode(SPECIALIZED_DIET_EXCLUDE_DAIRY,   
                             `No`="No",
                             `Yes`="Yes",
                             `Yes`="true",  
                             `No`="false") %>% 
           factor(levels = c("No","Yes") , ordered = TRUE) )  %>%
  select(-SAMPLE_NAME,-`19`) -> df_test
  
polr_model = glm(SPECIALIZED_DIET_EXCLUDE_DAIRY ~ ., data = df_test, family=binomial)

summary(polr_model)

exp(coef(polr_model))

ctable <- coef(summary(polr_model))

#p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
#ctable <- cbind(ctable, "p value" = p)

ci <- confint(polr_model)

exp(cbind(OR = coef(polr_model), ci))
ctable



metadata$DIABETES %>% table

enterotypes %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% select(SAMPLE_NAME,DIABETES),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(DIABETES = forcats::fct_recode(DIABETES,   
                             `No`="I do not have this condition",
                             `Yes`="Diagnosed by a medical professional (doctor, physician assistant)",
                             `medium`="Diagnosed by an alternative medicine practitioner",  
                             `medium`="Self-diagnosed") %>% 
           factor(levels = c("No","medium","Yes") , ordered = TRUE) )  %>%
  filter(DIABETES != "medium") %>%
  select(-SAMPLE_NAME,-`19`) -> df_test
  
polr_model = glm(DIABETES ~ ., data = df_test, family=binomial)

summary(polr_model)

exp(coef(polr_model))

ctable <- coef(summary(polr_model))

#p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
#ctable <- cbind(ctable, "p value" = p)

ci <- confint(polr_model)

exp(cbind(OR = coef(polr_model), ci))
ctable


metadata$BMI_CAT %>% table

enterotypes %>%
  reshape2::dcast(`sample_name` ~ `Enterotypes_id`, length) %>%
  merge(metadata %>% select(SAMPLE_NAME,BMI_CAT),., by.y="sample_name", by.x="SAMPLE_NAME") %>%
  na.omit() %>%
  mutate(BMI_CAT = forcats::fct_recode(BMI_CAT,   
                             `Underweight`="Underweight",
                             `Normal`="Normal",
                             `Overweight`="Overweight",  
                             `Obese`="Obese") %>% 
           factor(levels = c("Underweight","Normal","Overweight","Obese") , ordered = TRUE) )  %>%
  filter(BMI_CAT != "Underweight") %>%
  mutate(BMI_CAT = factor(BMI_CAT, levels = c("Normal","Overweight","Obese") , ordered = TRUE)) %>%
  select(-SAMPLE_NAME,-`19`) -> df_test
  
polr_model = MASS::polr(BMI_CAT ~ ., data = df_test, Hess=TRUE)

summary(polr_model)

exp(coef(polr_model))

ctable <- coef(summary(polr_model))

p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
ctable <- cbind(ctable, "p value" = p)

ci <- confint(polr_model)

exp(cbind(OR = coef(polr_model), ci))
ctable

multinomial regression

we aimed here to predict microbiome partition from metadata. Partition #1, the most centroid in branch structure and highest diversity, will be used as reference

prepare data

import metadata and merge with UNSD regions

enterotypes = readr::read_csv2("enterotypes_prediction_outliers.csv")[,-1] %>% filter(!is.na(Enterotypes_id))
metadata=read.csv2(system.file("data-raw/Metadata_10317_20191022-112414_curatedv4_VSv1.csv", package = "gutzilla"), stringsAsFactors = FALSE, ) %>% mutate_all(na_if,"")

metadata %>% .[1:5,1:5]


data("UNSD_countries")

metadata <- metadata %>% 
  #select(SAMPLE_NAME, COUNTRY_OF_BIRTH) %>%
  merge(UNSD_countries %>% 
          select(`Country or Area`, `Sub-region Name`, `Region Name`) %>% 
          mutate(`Country or Area` =  gsub("United Kingdom of Great Britain and Northern Ireland", "United Kingdom", `Country or Area`)) %>% 
          mutate(`Country or Area` =  gsub("United States of America", "USA", `Country or Area`)) %>%
          mutate(`Sub-region Name` =  ifelse(`Sub-region Name` %in% c("Central Asia", "Southern Asia"), "Central and Southern Asia",`Sub-region Name`)) %>%
          mutate(`Sub-region Name` =  ifelse(`Sub-region Name` %in% c("Melanesia", "Micronesia","Polynesia"), "Oceania (others)",`Sub-region Name`)), 
        by.x="COUNTRY_OF_BIRTH", by.y="Country or Area", all.x = TRUE)

clean metadata enterotypes

metadata %>%
  select(SAMPLE_NAME, contains("_FREQUENCY"), 
         TYPES_OF_PLANTS, OLIVE_OIL, DIET_TYPE, 
         contains("SPECIALIZED_DIET_"),
         all_of(health_metadata), contains("ALCOHOL_TYPES_"), 
         AGE_YEARS, SEX, COLLECTION_SEASON, `Sub-region Name`) %>%
  select(-SPECIALIZED_DIET_WESTENPRICE_OR_OTHER_LOWGRAIN_LOW_PROCESSED_FO, -ALCOHOL_TYPES_UNSPECIFIED) %>%
  dplyr::rename(REGION_BIRTH=`Sub-region Name`) %>%
  reshape2::melt(id.vars="SAMPLE_NAME") %>% 
  filter(value!="LabControl test") %>%
  filter(value != "Self-diagnosed") %>%
  filter(value != "Diagnosed by an alternative medicine practitioner") %>%
  mutate(value = forcats::fct_recode(value, Never = "Never",
                                              Rarely = "Rarely (less than once/week)",
                                              Rarely = "Rarely (a few times/month)",              
                                              Occasionally = "Occasionally (1-2 times/week)",                 
                                              Regularly = "Regularly (3-5 times/week)", 
                                              Daily = "Daily",
                                              Yes = "true",
                                              No  = "false",
                                              Yes = "Diagnosed by a medical professional (doctor, physician assistant)",
                                              No  = "I do not have this condition" )) %>%
  mutate(value = forcats::fct_explicit_na(value, "Missing") ) %>%
  filter(!is.na(value)) %>%
  mutate(value= value %>% as.character) %>%
  reshape2::dcast(SAMPLE_NAME~variable, value.var = "value", fill="Missing") %>%
  mutate(AGE_YEARS = AGE_YEARS %>% as.character() %>% as.numeric) %>%
  mutate(BOWEL_MOVEMENT_FREQUENCY = forcats::fct_relevel(BOWEL_MOVEMENT_FREQUENCY,ref="One")) %>%
  mutate(REGION_BIRTH             = forcats::fct_relevel(REGION_BIRTH, ref = "Northern America")) %>%
  mutate(ANTIBIOTIC_HISTORY       = forcats::fct_relevel(ANTIBIOTIC_HISTORY, ref = "I have not taken antibiotics in the past year.")) %>%
  merge(enterotypes %>% select(sample_name, Enterotypes_id), by.y="sample_name", by.x="SAMPLE_NAME") %>%
  mutate(Enterotypes_id = paste0("m",Enterotypes_id)) %>% select(-SAMPLE_NAME) -> metadata_enterotypes
Avis : NAs introduced by coercion

clean metadata enterotypes numerical


range0_1 = function(x) {(x-min(x, na.rm = TRUE))/(max(x, na.rm="TRUE")-min(x,na.rm = TRUE))}

metadata %>%
  select(SAMPLE_NAME, contains("_FREQUENCY"), 
         TYPES_OF_PLANTS, OLIVE_OIL, DIET_TYPE, 
         contains("SPECIALIZED_DIET_"),
         all_of(health_metadata),BMI, contains("ALCOHOL_TYPES_"),
         AGE_YEARS, SEX, COLLECTION_SEASON, `Sub-region Name`) %>%
  select(-SPECIALIZED_DIET_WESTENPRICE_OR_OTHER_LOWGRAIN_LOW_PROCESSED_FO, -BMI_CAT, -ALCOHOL_TYPES_UNSPECIFIED) %>%
  dplyr::rename(REGION_BIRTH=`Sub-region Name`) %>% #select(-SAMPLE_NAME) %>% apply(2,table)
  tidyext::onehot(var = c("REGION_BIRTH","GLUTEN","COLLECTION_SEASON")) %>%
  select(-GLUTEN_No) %>%
  reshape2::melt(id.vars=c("SAMPLE_NAME")) %>% 
  mutate(value= ifelse(value %in% c("LabControl test",
                                    "other",
                                    "Self-diagnosed",
                                    "Diagnosed by an alternative medicine practitioner"),NA,value)) %>%
  mutate(value = forcats::fct_recode(value,   `0` = "Never",
                                              `0.25` = "Rarely (less than once/week)",
                                              `0.25` = "Rarely (a few times/month)",              
                                              `0.5` = "Occasionally (1-2 times/week)",                 
                                              `0.75` = "Regularly (3-5 times/week)", 
                                              `1` = "Daily",
                                              `1` = "true",
                                              `0` = "false",
                                              `1` = "Yes",
                                              `0` = "No",
                                              `1` = "Diagnosed by a medical professional (doctor, physician assistant)",
                                              `0` = "I do not have this condition",
                                              `0` = "female",
                                              `1` = "male",
                                              `0` = "I have not taken antibiotics in the past year.",
                                              `0.25` = "Year",
                                              `0.5` = "6 months",
                                              `0.75` = "Month",
                                              `1` = "Week",
                                              `0` = "Less than 5",
                                              `0.25` = "6 to 10",
                                              `0.5` = "11 to 20",              
                                              `0.75` = "21 to 30",                 
                                              `1` = "More than 30", 
                                              `0` = "Less than one",
                                              `0.2` = "One",
                                              `0.4` = "Two",
                                              `0.6` = "Three",              
                                              `0.6` = "Four",                 
                                              `1` = "Five or more",
                                              `0` = "Omnivore" ,
                                              `0.25` = "Omnivore but do not eat red meat",
                                              `0.5` = "Vegetarian but eat seafood",              
                                              `0.75` = "Vegetarian",                 
                                              `1` = "Vegan"
                                    
                                       
                                       
                                       )) %>%
  mutate(value= value %>% as.character %>% as.numeric) %>%
  group_by(variable) %>%
  mutate(value = ifelse(is.na(value),mean(value,na.rm = TRUE),value)) %>% #slice_sample(prop=0.1)
  reshape2::dcast(SAMPLE_NAME~variable, value.var = "value", fill="Missing") %>%
  mutate(AGE_YEARS = AGE_YEARS %>% as.character() %>% as.numeric %>% range0_1() ) %>%
  mutate(BMI = BMI %>% as.character() %>% as.numeric %>% range0_1() ) %>%
  #mutate(AGE_YEARS = ifelse(is.na(AGE_YEARS),mean(AGE_YEARS,na.rm = TRUE),value)) %>%
  #mutate(REGION_BIRTH             = forcats::fct_relevel(REGION_BIRTH, ref = "Northern America")) %>%
  merge(enterotypes %>% select(sample_name, Enterotypes_id), by.y="sample_name", by.x="SAMPLE_NAME") %>%
  mutate(Enterotypes_id = paste0("m",Enterotypes_id)) %>% tibble::column_to_rownames("SAMPLE_NAME") -> metadata_enterotypes_num

metadata_enterotypes_num %>%
  select(-Enterotypes_id) %>%
  mutate_all(as.numeric) %>% cor(method="spearman") %>%
  .^2 %>% sqrt() %>% heatmap

NA
NA

metadata enterotypes correspondance analysis


metadata_enterotypes_num %>%
  select(-Enterotypes_id) %>%
  mutate_all(as.numeric) %>%
  ade4::dudi.pca(scannf=F,nf=30) -> metadata_enterotypes_num_pca


cumsum(metadata_enterotypes_num_pca$eig/sum(metadata_enterotypes_num_pca$eig))

metadata_enterotypes_num_pca$co %>% .[1:30] %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata")  %>%
  ggplot() + geom_bar(aes(x=metadata,y=value), stat = "identity") + 
  facet_wrap(~variable, ncol = 10) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))



metadata_enterotypes_num_pca$co %>% .[1:30] %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata") %>%
  group_by(variable) %>%
  mutate(value_w=abs(value)) %>%
  group_by(variable) %>%
  mutate(value_tot = sum(value_w)) %>%
  group_by(variable) %>%
  mutate(value_w=value_w/value_tot) %>%
  group_by(variable) %>%
  mutate(value_tot = sum(value_tot)) %>%
  arrange(variable,desc(value_w)) %>%
  group_by(variable) %>%
  mutate(value_cum = cumsum(value_w)) %>%
  filter(value_cum < 0.25) %>%
  pull(metadata) %>% unique()
 
metadata_enterotypes_num_pca$co %>% .[1:30] %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata") %>%
  group_by(variable) %>%
  mutate(value_w=abs(value)) %>%
  group_by(variable) %>%
  mutate(value_tot = sum(value_w)) %>%
  group_by(variable) %>%
  mutate(value_w=value_w/value_tot) %>%
  group_by(variable) %>%
  mutate(value_tot = sum(value_tot)) %>%
  arrange(variable,desc(value_w)) %>%
  group_by(variable) %>%
  mutate(value_cum = cumsum(value_w)) %>%
  group_by(variable) %>%
  slice_max(abs(value), n = 2) %>%
  pull(metadata) %>% unique()




  metadata_enterotypes_num_bca= ade4::bca(metadata_enterotypes_num_pca, fac=metadata_enterotypes_num$Enterotypes_id %>% as.character() %>% as.factor(), scannf=F, n=30) 

  #ade4::randtest(metadata_enterotypes_num_bca)
  
  
  metadata_enterotypes_num_bca$co %>%
    tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata") %>%
  group_by(variable) %>%
  mutate(value_w=abs(value)) %>%
  group_by(variable) %>%
  mutate(value_tot = sum(value_w)) %>%
  group_by(variable) %>%
  mutate(value_w=value_w/value_tot) %>%
  group_by(variable) %>%
  mutate(value_tot = sum(value_tot)) %>%
  arrange(variable,desc(value_w)) %>%
  group_by(variable) %>%
  mutate(value_cum = cumsum(value_w)) %>%
  group_by(variable) %>%
  slice_max(abs(value), n = 5) %>%
  #filter(value_cum < 0.05) %>%   
  #filter(abs(value)> 0.1) %>%  
  pull(metadata) %>% unique()
    
  
dim(metadata_enterotypes_num)  

cbind(metadata_enterotypes_num %>%
  select(-DIET_TYPE,-COLLECTION_SEASON,-REGION_BIRTH,-Enterotypes_id,-GLUTEN) %>%
  mutate_all(as.numeric),

metadata_enterotypes_num %>%
  select(DIET_TYPE,COLLECTION_SEASON,REGION_BIRTH,Enterotypes_id,GLUTEN) %>%
  mutate_all(as.character) %>%
  mutate_all(function(x){ifelse(is.na(x),"Missing",x)}) %>%
  mutate_all(as.factor)) %>%
  select(-Enterotypes_id) %>%
  ade4::dudi.mix(scannf=FALSE, nf=32) -> metadata_enterotypes_coa

metadata_enterotypes_num %>%
  select(-DIET_TYPE,-COLLECTION_SEASON,-REGION_BIRTH,-Enterotypes_id,-GLUTEN) %>%
  mutate_all(as.numeric) %>%
  ade4::dudi.mix(scannf=FALSE, nf=30) -> metadata_enterotypes_pca


ade4::scatter(metadata_enterotypes_coa)


cumsum(metadata_enterotypes_coa$eig/sum(metadata_enterotypes_coa$eig))

ade4::s.corcircle(metadata_enterotypes_coa$co)


metadata_enterotypes_coa$co %>% .[1:4] %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata")  %>%
  ggplot() + geom_bar(aes(x=metadata,y=value), stat = "identity") + 
  facet_wrap(~variable, ncol = 4) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))



metadata_enterotypes_coa$li %>%
  cbind(metadata_enterotypes_num) %>%
  ggplot() + geom_point(aes(x=Axis1, y=Axis2, col=Enterotypes_id))


metadata_enterotypes_coa$co %>% .[1:32] %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata")  %>%
  filter(abs(value)>0.5)


cumsum(metadata_enterotypes_pca$eig/sum(metadata_enterotypes_pca$eig))

metadata_enterotypes_pca$c1 %>% .[1:24] %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata")  %>%
  mutate(type=NA) %>%
  mutate(type=ifelse(grepl("REGIO", metadata),"Region",type )) %>%
  mutate(type=ifelse(grepl("GLUTE", metadata),"Gluten",type )) %>%
  mutate(type=ifelse(grepl("COLLE", metadata),"Collection",type )) %>%
  mutate(type=ifelse(grepl("DIET", metadata),"Diet",type )) %>%
  filter(is.na(type)) %>%
  filter(abs(value)>0.25) %>%
  ggplot() + geom_bar(aes(x=metadata,y=value), stat = "identity") + 
  facet_wrap(~variable, ncol = 6, scales = "free_x") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))


metadata_enterotypes_pca$li %>%
  cbind(metadata_enterotypes_num) %>%
  ggplot() + geom_point(aes(x=Axis1, y=Axis2, col=Enterotypes_id))

metadata_enterotypes_pca$c1 %>% .[1:23] %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata")  %>%
  filter(abs(value)>0.25)


metadata_enterotypes_bca = ade4::bca(metadata_enterotypes_coa, fac=as.factor(metadata_enterotypes_num$Enterotypes_id), nf=18, scannf=FALSE)

metadata_enterotypes_bca_randtest = ade4::randtest(metadata_enterotypes_bca)

cumsum(metadata_enterotypes_bca$eig/sum(metadata_enterotypes_bca$eig))


metadata_enterotypes_bca$c1 %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata")  %>%
  mutate(type=NA) %>%
  mutate(type=ifelse(grepl("REGIO", metadata),"Region",type )) %>%
  mutate(type=ifelse(grepl("GLUTE", metadata),"Gluten",type )) %>%
  mutate(type=ifelse(grepl("COLLE", metadata),"Collection",type )) %>%
  mutate(type=ifelse(grepl("DIET", metadata),"Diet",type )) %>%
  filter(is.na(type)) %>%
  filter(abs(value)>0.25) %>%
  ggplot() + geom_bar(aes(x=metadata,y=value), stat = "identity") + 
  facet_wrap(~variable, ncol = 6, scales = "free_x") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

metadata_enterotypes_bca$c1 %>%
  tibble::rownames_to_column("metadata") %>%
  reshape2::melt(id.vars="metadata")  %>%
  mutate(type=NA) %>%
  mutate(type=ifelse(grepl("REGIO", metadata),"Region",type )) %>%
  mutate(type=ifelse(grepl("GLUTE", metadata),"Gluten",type )) %>%
  mutate(type=ifelse(grepl("COLLE", metadata),"Collection",type )) %>%
  mutate(type=ifelse(grepl("DIET", metadata),"Diet",type )) %>%
  filter(!is.na(type)) %>%
  filter(abs(value)>1)

ade4::s.class(metadata_enterotypes_bca$ls, fac=as.factor(metadata_enterotypes_num$Enterotypes_id))

ade4::s.label(metadata_enterotypes_bca$li)

alcool types explo


library(UpSetR)

alcohol_types_list = list(BEERCIDER   = metadata %>% filter(ALCOHOL_TYPES_BEERCIDER == "Yes") %>% pull(SAMPLE_NAME),
                          SPIRITSHARD = metadata %>% filter(ALCOHOL_TYPES_SPIRITSHARD_ALCOHOL == "Yes") %>% pull(SAMPLE_NAME),
                          RED_WINE    = metadata %>% filter(ALCOHOL_TYPES_RED_WINE == "Yes") %>% pull(SAMPLE_NAME),
                          SOUR_BEERS  = metadata %>% filter(ALCOHOL_TYPES_SOUR_BEERS == "Yes") %>% pull(SAMPLE_NAME),
                          WHITE_WINE  = metadata %>% filter(ALCOHOL_TYPES_WHITE_WINE == "Yes") %>% pull(SAMPLE_NAME),
                          UNSPECIFIED = metadata %>% filter(ALCOHOL_TYPES_UNSPECIFIED  == "Yes") %>% pull(SAMPLE_NAME))

upset(alcohol_types_list)

metadata %>%
  select(contains("ALCOHOL_TYPES_"), -ALCOHOL_TYPES_UNSPECIFIED) %>%
  mutate_all(function(x) ifelse(x=="Yes",1,0)) %>% 
upset(group.by = "sets",cutoff = 3)

build model


library(nnet)
library(GGally)
library(broom.helpers)

metadata_enterotypes_tmp =  
  metadata_enterotypes_num %>%
  mutate(ANTIBIOTIC_HISTORY = ANTIBIOTIC_HISTORY %>% as.numeric,
         BOWEL_MOVEMENT_FREQUENCY = BOWEL_MOVEMENT_FREQUENCY %>% as.numeric,
         AGE_YEARS = AGE_YEARS %>% as.numeric,
         SEX = SEX %>% as.numeric,
         TYPES_OF_PLANTS = TYPES_OF_PLANTS %>% as.numeric,
         VEGETABLE_FREQUENCY = VEGETABLE_FREQUENCY %>% as.numeric,
         IBD = IBD %>% as.numeric,
         FROZEN_DESSERT_FREQUENCY = FROZEN_DESSERT_FREQUENCY %>% as.numeric,
         TEETHBRUSHING_FREQUENCY = TEETHBRUSHING_FREQUENCY %>% as.numeric) %>%
  #slice_sample(n = 5000, replace = FALSE) %>%
  na.omit()
  


regm  <- multinom(Enterotypes_id ~ ANTIBIOTIC_HISTORY + BOWEL_MOVEMENT_FREQUENCY + 
                    AGE_YEARS + SEX + TYPES_OF_PLANTS + VEGETABLE_FREQUENCY + 
                    IBD + FROZEN_DESSERT_FREQUENCY +  TEETHBRUSHING_FREQUENCY + REGION_BIRTH + GLUTEN , data = metadata_enterotypes_tmp) #MaxNWts = 1026
regm2 <- step(regm)


save(regm, file="regm.rda")
save(regm2, file="regm2.rda")

#regm2_OR   <- Rfast::odds.ratio(regm2)
#save(regm2_OR, file="regm2_OR.rda")

regm2_tidy <- tidy_plus_plus(regm2, exponentiate = TRUE)
regm2_plot <- ggcoef_multinom(regm2,exponentiate = TRUE, type = "faceted")

save(regm2_tidy, file="regm2_tidy.rda")
save(regm2_plot, file="regm2_plot.rda")


#regm2_plot$data %>% ggcoef_plot(facet_col="y.level", exponentiate = TRUE)
library(nnet)
library(GGally)
library(broom.helpers)

metadata_enterotypes_tmp =  
  metadata_enterotypes_num %>%
  mutate(Enterotypes_id = Enterotypes_id %>% forcats::fct_relevel(ref = "m1")) %>%
  mutate_if(is.character, as.numeric) %>%
  na.omit()
  


regm  <- multinom(Enterotypes_id ~ . , data = metadata_enterotypes_tmp, MaxNWts = 1938) 

regm_tidy <- tidy_plus_plus(regm, exponentiate = TRUE)

save(regm_tidy, file="regm_tidy.rda")

# regm2 <- step(regm)
# 
# save(regm, file="regm.rda")
# save(regm2, file="regm2.rda")
# 
# 
# regm2_tidy <- tidy_plus_plus(regm2, exponentiate = TRUE)
# 
# save(regm2_tidy, file="regm2_tidy.rda")
# 
# 
# 
# exp(coef(regm))
# 
# ctable <- coef(summary(regm))
# 
# p <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
# ctable <- cbind(ctable, "p value" = p)
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

enterotypes = readr::read_csv2("enterotypes_prediction_outliers.csv")[,-1] %>% filter(!is.na(Enterotypes_id))
ℹ 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.
merge(enterotypes,shannon,by.x="sample_name", by.y="row.names") %>%
  group_by(Enterotypes_id) %>%
  summarise(shannon_median=median(shannon)) %>%
  mutate(Enterotypes_id = paste0("m",Enterotypes_id))-> enterotypes_shannon_median
coef(regm) %>% 
  reshape2::melt() %>% 
  filter(Var2 != "(Intercept)") %>% 
  merge(enterotypes_shannon_median, by.x="Var1", by.y="Enterotypes_id") %>%
  mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(Var1 %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(Var1 %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(Var1 %in% c("m13"), "Akkermansia DMM types",branch)) %>%
  mutate(Var1 = Var1 %>% forcats::fct_reorder(shannon_median)) %>% 
  ggplot() + geom_point(aes(x=Var1,y=10^value, col=branch)) + scale_y_log10() + facet_wrap(~Var2, scale="free_y")




regm_tidy %>% 
  merge(enterotypes_shannon_median, by.x="y.level", by.y="Enterotypes_id") %>%
  mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(y.level %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m13"), "Akkermansia DMM types",branch)) %>%
  mutate(y.level = y.level %>% forcats::fct_reorder(shannon_median)) %>%
  ggplot() + geom_point(aes(x=y.level,y=estimate, col=branch, alpha=p.value<0.05)) + scale_y_continuous(trans = "log") + facet_wrap(~term, scale="free_y")



regm_tidy %>% 
  merge(enterotypes_shannon_median, by.x="y.level", by.y="Enterotypes_id") %>%
  mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(y.level %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m13"), "Akkermansia DMM types",branch)) %>%
  mutate(y.level = y.level %>% forcats::fct_reorder(shannon_median)) %>%
  filter(p.value < 0.05) %>%
  ggplot() + geom_point(aes(x=term,y=log(estimate), col=branch)) + 
  #scale_y_continuous(trans = "log") + 
  facet_wrap(~y.level, scale="free_x", nrow=2) + coord_flip() + theme_classic() + geom_hline(yintercept = 0)

NA
NA

data viz


# regm_tidy %>% 
#   merge(enterotypes_shannon_median, by.x="y.level", by.y="Enterotypes_id") %>%
#   mutate(branch ="Clostridiales DMM types") %>%
#   mutate(branch = ifelse(y.level %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
#   mutate(branch = ifelse(y.level %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
#   mutate(branch = ifelse(y.level %in% c("m13"), "Akkermansia DMM types",branch)) %>%
#   mutate(estimate = log(estimate)) %>%
#   #mutate(estimate = ifelse(p.value>0.05,0,estimate)) %>%
#   group_by(variable) %>%
#   mutate(s=mean(abs(estimate))) %>% 
#   filter(s>0) %>%
#   mutate(y.level = y.level %>% forcats::fct_reorder(shannon_median)) %>%
#   mutate(variable = variable %>% forcats::fct_reorder(s)) %>%
#   ggplot() + geom_tile(aes(x=y.level, y=variable, fill=estimate)) + scale_fill_gradient2() + facet_grid(.~branch, scale="free_x", space = "free_x")

load("regm_tidy.rda")  
  
  regm_tidy %>%
    mutate(variable_group = "disease") %>%
    mutate(variable_group = 
             case_when(grepl("FREQUENCY", variable) ~ "Diet, demographic and lifestyle",
                       grepl("ALCOHOL", variable) ~ "Diet, demographic and lifestyle",
                       variable %in% c("AGE_YEARS","SEX","DIET_TYPE","TYPES_OF_PLANTS") ~ "Diet, demographic and lifestyle",
                       grepl("SPECIALIZED", variable) ~"Specialized Diet",
                       grepl("REGION", variable) ~ "Region of Birth",
                       TRUE ~ "Health associated"
                            )) %>%
    merge(enterotypes_shannon_median, by.x="y.level", by.y="Enterotypes_id") %>%
  mutate(branch ="Clostridiales DMM partitions") %>%
  mutate(branch = ifelse(y.level %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM partitions",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM partitions",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m13"), "Akk.",branch)) %>%
  mutate(estimate = log(estimate)) %>%
  mutate(estimate2 = ifelse(p.value>0.05,0,estimate)) %>%
  group_by(variable) %>%
  mutate(s=mean(abs(estimate2))) %>% 
  filter(s>0) %>%
  ungroup() %>%
  mutate(y.level = y.level %>% forcats::fct_reorder(shannon_median, .desc = FALSE)) %>%
  mutate(variable = variable %>% as.character %>% as.factor() %>% forcats::fct_reorder(s, .desc = FALSE)) %>% 
  ggplot() + 
    geom_tile(aes(x=y.level, y=variable, fill=estimate)) + 
    geom_point(aes(x=y.level, y=variable, alpha=p.value<0.05)) + 
    scale_fill_gradient2("Log OR", low=scales::muted("blue"), mid="white", high=scales::muted("red")) +
    facet_grid(variable_group~branch, scale="free", space = "free") + 
    cowplot::theme_cowplot() +
    theme(axis.title.x=element_blank(),
        axis.text.x=element_blank()) +
  ylab("Microbiome partition\nordered by branch and by alpha-diversity") + ylab("AGP questionnaire variable") -> fig4A
    fig4A

  ggsave("partitions_multinomial_logOR.pdf", height = 12, width = 14)
  
  
  # reshape2::dcast(y.level~variable, value.var = "estimate") %>%
  # tibble::column_to_rownames("y.level") %>%
  # as.matrix() %>%
  # t() %>%
  # heatmap(scale = "none", col = cm.colors(256))

  
regm_tidy %>%
    mutate(variable_group = "disease") %>%
    mutate(variable_group = 
             case_when(grepl("FREQUENCY", variable) ~ "Diet, demographic and lifestyle",
                       grepl("ALCOHOL", variable) ~ "Diet, demographic and lifestyle",
                       variable %in% c("AGE_YEARS","SEX","DIET_TYPE","TYPES_OF_PLANTS") ~ "Diet, demographic and lifestyle",
                       grepl("SPECIALIZED", variable) ~"Specialized Diet",
                       grepl("REGION", variable) ~ "Region of Birth",
                       TRUE ~ "Health associated"
                            )) %>%
    merge(enterotypes_shannon_median, by.x="y.level", by.y="Enterotypes_id") %>%
  mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(y.level %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m13"), "Akk.",branch)) %>%
  mutate(estimate = log(estimate)) %>%
  mutate(estimate2 = ifelse(p.value>0.05,0,estimate)) %>%
  group_by(variable) %>%
  mutate(s=mean(abs(estimate2))) %>% 
  filter(s>0) %>%
  ungroup() %>%
  mutate(y.level = y.level %>% forcats::fct_reorder(shannon_median, .desc = FALSE)) %>%
  mutate(variable = variable %>% as.character %>% as.factor() %>% forcats::fct_reorder(s, .desc = FALSE)) %>%  
  group_by(variable,variable_group,branch) %>%
  summarise(estimate=sum(abs(estimate2))) %>%
  ggplot() +
  geom_bar(aes(x=variable,y=estimate,fill=branch), stat="identity", position = "stack") +
  facet_grid(variable_group~., scale="free", space = "free") + coord_flip() + scale_fill_brewer(type="qual") +
  xlab("") + ylab("absolute cummulated Log OR") +
  cowplot::theme_cowplot() +
  theme(axis.title.y=element_blank(),
        axis.text.y=element_blank()) -> fig4B
`summarise()` has grouped output by 'variable', 'variable_group'. You can override using the `.groups` argument.
  





 regm_tidy %>%
    mutate(variable_group = "disease") %>%
    mutate(variable_group = 
             case_when(grepl("FREQUENCY", variable) ~ "Diet, demographic and lifestyle",
                       grepl("ALCOHOL", variable) ~ "Diet, demographic and lifestyle",
                       variable %in% c("AGE_YEARS","SEX","DIET_TYPE","TYPES_OF_PLANTS") ~ "Diet, demographic and lifestyle",
                       grepl("SPECIALIZED", variable) ~"Specialized Diet",
                       grepl("REGION", variable) ~ "Region of Birth",
                       TRUE ~ "Health associated"
                            )) %>%
    merge(enterotypes_shannon_median, by.x="y.level", by.y="Enterotypes_id") %>%
  mutate(branch ="Clostridiales DMM partitions") %>%
  mutate(branch = ifelse(y.level %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM partitions",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM partitions",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m13"), "Akk.",branch)) %>%
  mutate(estimate = log(estimate)) %>%
  mutate(estimate2 = ifelse(p.value>0.05,0,estimate)) %>%
  group_by(variable) %>%
  mutate(s=mean(abs(estimate2))) %>% 
  filter(s>0) %>%
  ungroup() %>%
  mutate(y.level = y.level %>% forcats::fct_reorder(shannon_median, .desc = FALSE)) %>%
  mutate(variable = variable %>% as.character %>% as.factor() %>% forcats::fct_reorder(s, .desc = FALSE)) %>%  
  group_by(y.level, variable_group, branch) %>%
  summarise(estimate=sum(abs(estimate2))) %>%
  ggplot() +
  geom_bar(aes(x=y.level,y=estimate,fill=variable_group), stat="identity", position = "stack") +
  facet_grid(.~branch, scale="free", space = "free") + scale_fill_brewer("",type="qual", palette = "Set2") +
  xlab("") + ylab("absolute cummulated Log OR") + 
   cowplot::theme_cowplot() -> fig4C
`summarise()` has grouped output by 'y.level', 'variable_group'. You can override using the `.groups` argument.

focus on Bacteroides branches

  regm_tidy %>%
  group_by(variable) %>% mutate(p.value = p.adjust(p.value, method="fdr")) %>%
    mutate(variable_group = "disease") %>%
   mutate(variable_group = 
             case_when(variable %in% c("AGE_YEARS","SEX","BMI","BOWEL_MOVEMENT_FREQUENCY") ~ "Intrinsic\nHost",
                       grepl("MEALS", variable) ~ "Lifestyle\n& hygiene",
                       variable %in% c("EXERCISE_FREQUENCY","POOL_FREQUENCY","COSMETICS_FREQUENCY","PREPARED_MEALS_FREQUENCY","TEETHBRUSHING_FREQUENCY","SMOKING_FREQUENCY") ~ "Lifestyle\n& hygiene",
                       grepl("FREQUENCY", variable) ~ "Diet",
                       grepl("ALCOHOL", variable) ~ "Diet",
                       variable %in% c("DIET_TYPE","TYPES_OF_PLANTS") ~ "Diet",
                       grepl("SPECIALIZED", variable) ~"Spec.\nDiet",
                       grepl("REGION", variable) ~ "Reg. of\nBirth",
                       TRUE ~ "Medical history"
                            )) %>%
    merge(enterotypes_shannon_median, by.x="y.level", by.y="Enterotypes_id") %>%
  mutate(branch ="Clostridiales DMM partitions") %>%
  mutate(branch = ifelse(y.level %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM partitions",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM partitions",branch)) %>%
  mutate(branch = ifelse(y.level %in% c("m13"), "Akk.",branch)) %>%
  mutate(substates = "High") %>%
  mutate(substates = ifelse(y.level %in% c("m11","m6","m10","m3"), "Medium",substates)) %>%
  mutate(substates = ifelse(y.level %in% c("m15"), "Low",substates)) %>%
  filter(branch == "Bacteroides DMM partitions") %>%
  mutate(substates = substates %>% forcats::fct_relevel("High",after=2 )) %>%
  mutate(estimate = log(estimate)) %>%
  mutate(estimate2 = ifelse(p.value>p_cut_off,0,estimate)) %>%
  group_by(variable) %>%
  mutate(s=mean(abs(estimate2))) %>% 
  filter(s>0) %>%
  ungroup() %>%
  mutate(y.level = y.level %>% stringr::str_to_upper() %>% forcats::fct_reorder(shannon_median, .desc = TRUE)) %>%
  
  mutate(branch = branch %>% gsub("DMM types", "\nDMM types",.)) %>% #pull(variable) %>% grep("COLL",.)
  filter(!(variable %in% grep("COLL", variable, value = TRUE) )) %>%
  
  mutate(variable = gsub("_FREQUENCY|SPECIALIZED_DIET_|ALCOHOL_TYPES_|REGION_BIRTH_","", variable)) %>%
  mutate(variable = 
           case_when(grepl("NO_FOOD", variable)~"No food allergy",
                     grepl("not.eat.gluten", variable)~"Gluten intolerance",
                     grepl("gluten.IgG", variable)~"Gluten allergy (IgG)",
                     grepl("WESTENPRICE", variable)~"Low processed",
                     grepl("OTHER_RESTRICTIONS", variable)~"Other restrictions",
                     grepl("SEX", variable)~"Sex (male)",
                     TRUE ~ variable)) %>%
  mutate(variable = gsub("_|\\."," ", variable)) %>%
  mutate(variable = variable %>% as.character %>% as.factor() %>% forcats::fct_reorder(s, .desc = TRUE)) %>% 
     mutate(branch = branch %>% gsub("DMM partitions", "\nDMM partitions",.)) %>%
  ggplot() + 
    geom_tile(aes(y=y.level, x=variable, fill=estimate)) + 
    geom_point(aes(y=y.level, x=variable, alpha=p.value<p_cut_off)) + 
    #scale_fill_gradient2("Log OR", low=scales::muted("blue"), mid="white", high=scales::muted("red")) +
    scale_fill_gradient("Log OR", low="white", high="#1a1a1a") +  
    facet_grid(variable_group~substates, scale="free", space = "free") + 
    cowplot::theme_cowplot() +
    scale_alpha_discrete("FDR < 10%") +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
    ylab("Microbiome Bacteroides partitions") + xlab("AGP questionnaire data") + coord_flip() 
Avis : Using alpha for a discrete variable is not advised.

NA
NA
NA
NA
NA
NA

to do: plot shannon vs cumulated model weight and make an id card for partition 1 (ref)


fig4A + coord_flip()


(fig4A+fig4B+ plot_layout(widths = c(2,1))) / (fig4C) + plot_layout(heights = c(3,1))


  
  Z = model.matrix(object)
    probs <- object$fitted # avoid napredict from fitted.default
    coefs <- coef(object)
    if (is.vector(coefs)){ # ie there are only 2 response categories
        coefs <- t(as.matrix(coefs))
        probs <- cbind(1 - probs, probs)
    }
    coefdim <- dim(coefs)
    p <- coefdim[2L]
    k <- coefdim[1L]
    ncoefs <- k * p
    kpees <- rep(p, k)
    n <- dim(Z)[1L]
##  Now compute the observed (= expected, in this case) information,
##  e.g. as in T Amemiya "Advanced Econometrics" (1985) pp295-6.
##  Here i and j are as in Amemiya, and x, xbar are vectors
##  specific to (i,j) and to i respectively.
    info <- matrix(0, ncoefs, ncoefs)
    Names <- dimnames(coefs)
    if (is.null(Names[[1L]])) {Names <- Names[[2L]] } else {
      Names <- as.vector(outer(Names[[2L]], Names[[1L]],
                             function(name2, name1)
                                 paste(name1, name2, sep = ":")))}
    dimnames(info) <- list(Names, Names)
    x0 <- matrix(0, p, k+1L)
    row.totals <- object$weights
    pb <- txtProgressBar(min=1,max=n)
    for (i in seq_len(n)) {
      
        Zi <- Z[i, ]
        xbar <- Zi * rep(probs[i, -1, drop = FALSE], kpees)
        for (j in seq_len(k+1)){
            x <- x0
            x[, j] <- Zi
            x <- x[, -1, drop = FALSE]
            x <- x - xbar
            dim(x) <- c(1, ncoefs)
            info <- info + (row.totals[i] * probs[i, j] * crossprod(x))
        }
        setTxtProgressBar(pb, i)
    }
    info

hysteresis exploration


metadata_enterotypes_num %>%
  mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m13"), "Akkermansia DMM types",branch)) %>%
  filter(branch=="Bacteroides DMM types" | Enterotypes_id =="m5") %>%
  select(SALTED_SNACKS_FREQUENCY,VEGETABLE_FREQUENCY,SUGARY_SWEETS_FREQUENCY,TYPES_OF_PLANTS,FRUIT_FREQUENCY,ANTIBIOTIC_HISTORY) %>%
  mutate_all(as.numeric) %>%
  ade4::dudi.pca(scannf=FALSE, nf=2) -> metadata_enterotypes_pca_branch
  


metadata_enterotypes_num_shannon = merge(metadata_enterotypes_num,shannon, by="row.names")
  

metadata_enterotypes_num_shannon %>%
  mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m13"), "Akkermansia DMM types",branch)) %>%
  filter(branch=="Bacteroides DMM types" | Enterotypes_id =="m5") %>%
  select(TYPES_OF_PLANTS, shannon, Enterotypes_id) %>%
  mutate(Enterotypes_id= forcats::fct_reorder(Enterotypes_id, shannon)) %>%
  #mutate(TYPES_OF_PLANTS=TYPES_OF_PLANTS%>% as.numeric()) %>%
  ggplot() + 
  geom_histogram(aes(x=TYPES_OF_PLANTS,fill=Enterotypes_id), stat="count", position="fill")


 merge(metadata_enterotypes_num_shannon,metadata_enterotypes_pca_branch$li, by.x="Row.names", by.y="row.names") %>% 
   mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m13"), "Akkermansia DMM types",branch)) %>%
  filter(branch=="Bacteroides DMM types" | Enterotypes_id =="m5") %>%
  mutate(Enterotypes_id= forcats::fct_reorder(Enterotypes_id, shannon)) %>%
   select(Axis1,shannon,Enterotypes_id) %>%
   ggplot() + 
  geom_point(aes(x=Axis1,y=shannon,col=Enterotypes_id), size=1,alpha=0.5)

merge(metadata_enterotypes_num_shannon,metadata_enterotypes_pca_branch$li, by.x="Row.names", by.y="row.names") %>% 
   mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m13"), "Akkermansia DMM types",branch)) %>%
  filter(branch=="Bacteroides DMM types" | Enterotypes_id =="m5") %>%
  mutate(Enterotypes_id= forcats::fct_reorder(Enterotypes_id, shannon)) %>%
   select(Axis1,shannon,Enterotypes_id) %>%
  ggplot() + 
  geom_histogram(aes(x=rank((-Axis1))+1,fill=Enterotypes_id), position="fill", bins=30) +
  scale_fill_viridis_d()  + scale_x_log10()


merge(metadata_enterotypes_num_shannon,metadata_enterotypes_pca_branch$li, by.x="Row.names", by.y="row.names") %>% 
   mutate(branch ="Clostridiales DMM types") %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m18","m14","m16","m17","m7"), "Prevotella DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m11","m15","m6","m8","m10","m3","m4","m2"), "Bacteroides DMM types",branch)) %>%
  mutate(branch = ifelse(Enterotypes_id %in% c("m13"), "Akkermansia DMM types",branch)) %>%
  filter(branch=="Bacteroides DMM types" | Enterotypes_id =="m5") %>%
  mutate(Enterotypes_id= forcats::fct_reorder(Enterotypes_id, shannon)) %>%
   select(Axis1,shannon,Enterotypes_id) %>%
  ggplot() + 
  geom_point(aes(x=rank((-Axis1))+1,y=shannon)) +
  scale_fill_viridis_d()
LS0tDQp0aXRsZTogInBhcnRpdGlvbnMgdnMgb3JkaW5hbCBtZXRhZGF0YSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpkZXZ0b29sczo6bG9hZF9hbGwoKQ0KDQoNCg0KYGBgDQoNCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCg0KDQplbnRlcm90eXBlcyA9IHJlYWRyOjpyZWFkX2NzdjIoImVudGVyb3R5cGVzX3ByZWRpY3Rpb25fb3V0bGllcnMuY3N2IilbLC0xXSAlPiUgZmlsdGVyKCFpcy5uYShFbnRlcm90eXBlc19pZCkpDQptZXRhZGF0YT1yZWFkLmNzdjIoc3lzdGVtLmZpbGUoImRhdGEtcmF3L01ldGFkYXRhXzEwMzE3XzIwMTkxMDIyLTExMjQxNF9jdXJhdGVkdjRfVlN2MS5jc3YiLCBwYWNrYWdlID0gImd1dHppbGxhIiksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwgKSAlPiUgbXV0YXRlX2FsbChuYV9pZiwiIikNCg0KbWV0YWRhdGEgJT4lIC5bMTo1LDE6NV0NCg0KDQpkYXRhKCJVTlNEX2NvdW50cmllcyIpDQoNCm1ldGFkYXRhIDwtIG1ldGFkYXRhICU+JSANCiAgI3NlbGVjdChTQU1QTEVfTkFNRSwgQ09VTlRSWV9PRl9CSVJUSCkgJT4lDQogIG1lcmdlKFVOU0RfY291bnRyaWVzICU+JSANCiAgICAgICAgICBzZWxlY3QoYENvdW50cnkgb3IgQXJlYWAsIGBTdWItcmVnaW9uIE5hbWVgLCBgUmVnaW9uIE5hbWVgKSAlPiUgDQogICAgICAgICAgbXV0YXRlKGBDb3VudHJ5IG9yIEFyZWFgID0gIGdzdWIoIlVuaXRlZCBLaW5nZG9tIG9mIEdyZWF0IEJyaXRhaW4gYW5kIE5vcnRoZXJuIElyZWxhbmQiLCAiVW5pdGVkIEtpbmdkb20iLCBgQ291bnRyeSBvciBBcmVhYCkpICU+JSANCiAgICAgICAgICBtdXRhdGUoYENvdW50cnkgb3IgQXJlYWAgPSAgZ3N1YigiVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhIiwgIlVTQSIsIGBDb3VudHJ5IG9yIEFyZWFgKSkgJT4lDQogICAgICAgICAgbXV0YXRlKGBTdWItcmVnaW9uIE5hbWVgID0gIGlmZWxzZShgU3ViLXJlZ2lvbiBOYW1lYCAlaW4lIGMoIkNlbnRyYWwgQXNpYSIsICJTb3V0aGVybiBBc2lhIiksICJDZW50cmFsIGFuZCBTb3V0aGVybiBBc2lhIixgU3ViLXJlZ2lvbiBOYW1lYCkpICU+JQ0KICAgICAgICAgIG11dGF0ZShgU3ViLXJlZ2lvbiBOYW1lYCA9ICBpZmVsc2UoYFN1Yi1yZWdpb24gTmFtZWAgJWluJSBjKCJNZWxhbmVzaWEiLCAiTWljcm9uZXNpYSIsIlBvbHluZXNpYSIpLCAiT2NlYW5pYSAob3RoZXJzKSIsYFN1Yi1yZWdpb24gTmFtZWApKSwgDQogICAgICAgIGJ5Lng9IkNPVU5UUllfT0ZfQklSVEgiLCBieS55PSJDb3VudHJ5IG9yIEFyZWEiLCBhbGwueCA9IFRSVUUpDQoNCg0KDQoNCnZhcmlhYmxlX3RvX3JlbW92ZT0gYygiSEVJR0hUX0NNIiwgDQoiV0VJR0hUX0tHIiwNCiJTQU1QTEVfVFlQRSIsDQoiQk1JX0NBVCIsDQoiSE9TVF9TVUJKRUNUX0lEIiwNCiJBTk9OWU1JWkVEX05BTUUiLA0KIkFTU0lHTkVEX0ZST01fR0VPIiwNCiJCSVJUSF9ZRUFSIiwNCiJERVNDUklQVElPTiIsDQoiRE5BX0VYVFJBQ1RFRCIsDQoiSEVJR0hUX1VOSVRTIiwNCiJXRUlHSFRfVU5JVFMiLA0KIlNDSUVOVElGSUNfTkFNRSIsDQoiU1VSVkVZX0lEIiwNCiJUQVhPTl9JRCIsDQoiV0VJR0hUX1VOSVRTIiwNCiJWSU9TQ1JFRU5fU1RBVFVTIiwiVklPU0NSRUVOX1NVUlZFWUlEIiwiUFVCTElDIiwiVElUTEUiLCJHRU9fTE9DX05BTUUiKQ0KDQoNCg0KDQpoZWFsdGhfbWV0YWRhdGEgPSBjKCJCTUlfQ0FUIiwNCiJBTlRJQklPVElDX0hJU1RPUlkiICwNCiJBTFpIRUlNRVJTIiwNCiJBVVRPSU1NVU5FIiwNCiJDQU5DRVIiLA0KIkRJQUJFVEVTIiwNCiJJQkQiLA0KIklCUyIsDQoiS0lETkVZX0RJU0VBU0UiLA0KIkFDSURfUkVGTFVYIiwNCiJBTExFUkdJQ19UT19JX0hBVkVfTk9fRk9PRF9BTExFUkdJRVNfVEhBVF9JX0tOT1dfT0YiLA0KIkNBUkRJT1ZBU0NVTEFSX0RJU0VBU0UiLA0KIkNESUZGIiwNCiJERVBSRVNTSU9OX0JJUE9MQVJfU0NISVpPUEhSRU5JQSIsDQoiRVBJTEVQU1lfT1JfU0VJWlVSRV9ESVNPUkRFUiIsDQoiRlVOR0FMX09WRVJHUk9XVEgiLA0KIkdMVVRFTiIsDQoiTEFDVE9TRSIsDQoiTElWRVJfRElTRUFTRSIsDQoiTFVOR19ESVNFQVNFIiwNCiJNRU5UQUxfSUxMTkVTUyIsDQoiTUlHUkFJTkUiLA0KIlBLVSIsDQoiU0lCTyIsDQoiVEhZUk9JRCIpDQoNCmRpZXRfdmFyaWFibGVzID0NCiAgYygiVFlQRVNfT0ZfUExBTlRTIiwNCiAgIkRJRVRfVFlQRSIsDQogICJBTENPSE9MX0ZSRVFVRU5DWSIsDQogICJSRURfTUVBVF9GUkVRVUVOQ1kiLA0KICAiV0hPTEVfR1JBSU5fRlJFUVVFTkNZIiwNCiAgIlZFR0VUQUJMRV9GUkVRVUVOQ1kiLA0KICAiTUVBVF9FR0dTX0ZSRVFVRU5DWSIsDQogICJQUkVQQVJFRF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiRlJVSVRfRlJFUVVFTkNZIiwNCiAgIk9ORV9MSVRFUl9PRl9XQVRFUl9BX0RBWV9GUkVRVUVOQ1kiLA0KICAiU0VBRk9PRF9GUkVRVUVOQ1kiLA0KICAiSE9NRUNPT0tFRF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiSElHSF9GQVRfUkVEX01FQVRfRlJFUVVFTkNZIiwNCiAgIlJFQURZX1RPX0VBVF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiU1VHQVJfU1dFRVRFTkVEX0RSSU5LX0ZSRVFVRU5DWSIsDQogICJTVUdBUllfU1dFRVRTX0ZSRVFVRU5DWSIsDQogICJTQUxURURfU05BQ0tTX0ZSRVFVRU5DWSIsDQogICJTUEVDSUFMSVpFRF9ESUVUX0ZPRE1BUCIsDQogICJTUEVDSUFMSVpFRF9ESUVUX0VYQ0xVREVfREFJUlkiLA0KICAiU1BFQ0lBTElaRURfRElFVF9FWENMVURFX05JR0hUU0hBREVTIiwNCiAgIlNQRUNJQUxJWkVEX0RJRVRfTU9ESUZJRURfUEFMRU9fRElFVCIsDQogICJTUEVDSUFMSVpFRF9ESUVUX1BBTEVPRElFVF9PUl9QUklNQUxfRElFVCIsDQogICJPTElWRV9PSUwiKQ0KDQoNCg0KDQoNCmBgYA0KDQpgYGB7cn0NCg0KZW50ZXJvdHlwZXMgJT4lDQogIHJlc2hhcGUyOjpkY2FzdChgc2FtcGxlX25hbWVgIH4gYEVudGVyb3R5cGVzX2lkYCwgbGVuZ3RoKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGEgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxBTlRJQklPVElDX0hJU1RPUlkpLC4sIGJ5Lnk9InNhbXBsZV9uYW1lIiwgYnkueD0iU0FNUExFX05BTUUiKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBtdXRhdGUoQU5USUJJT1RJQ19ISVNUT1JZID0gZHBseXI6OnJlY29kZV9mYWN0b3IoQU5USUJJT1RJQ19ISVNUT1JZLCAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgSSBoYXZlIG5vdCB0YWtlbiBhbnRpYmlvdGljcyBpbiB0aGUgcGFzdCB5ZWFyLmA9IkkgaGF2ZSBub3QgdGFrZW4gYW50aWJpb3RpY3MgaW4gdGhlIHBhc3QgeWVhci4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgWWVhcmA9IlllYXIiLCBgNiBtb250aHNgPSI2IG1vbnRocyIsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYE1vbnRoYD0iTW9udGgiLCBgV2Vla2AgPSAiV2VlayIsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLm9yZGVyZWQgPSBUUlVFKSAgKSAlPiUNCiAgc2VsZWN0KC1TQU1QTEVfTkFNRSwtYDE5YCkgLT4gZGZfdGVzdA0KICANCnBvbHJfbW9kZWwgPSBNQVNTOjpwb2xyKEFOVElCSU9USUNfSElTVE9SWSB+IC4sIGRhdGEgPSBkZl90ZXN0LCBIZXNzPVRSVUUpDQoNCnN1bW1hcnkocG9scl9tb2RlbCkNCg0KZXhwKGNvZWYocG9scl9tb2RlbCkpDQoNCmN0YWJsZSA8LSBjb2VmKHN1bW1hcnkocG9scl9tb2RlbCkpDQoNCnAgPC0gcG5vcm0oYWJzKGN0YWJsZVssICJ0IHZhbHVlIl0pLCBsb3dlci50YWlsID0gRkFMU0UpICogMg0KY3RhYmxlIDwtIGNiaW5kKGN0YWJsZSwgInAgdmFsdWUiID0gcCkNCg0KY2kgPC0gY29uZmludChwb2xyX21vZGVsKQ0KDQpleHAoY2JpbmQoT1IgPSBjb2VmKHBvbHJfbW9kZWwpLCBjaSkpDQpjdGFibGUNCg0KDQoNCmBgYA0KYGBge3J9DQptZXRhZGF0YSRUWVBFU19PRl9QTEFOVFMgJT4lIHRhYmxlDQoNCg0KYGBgDQoNCg0KYGBge3J9DQoNCg0KZW50ZXJvdHlwZXMgJT4lDQogIHJlc2hhcGUyOjpkY2FzdChgc2FtcGxlX25hbWVgIH4gYEVudGVyb3R5cGVzX2lkYCwgbGVuZ3RoKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGEgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxUWVBFU19PRl9QTEFOVFMpLC4sIGJ5Lnk9InNhbXBsZV9uYW1lIiwgYnkueD0iU0FNUExFX05BTUUiKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBtdXRhdGUoVFlQRVNfT0ZfUExBTlRTID0gZHBseXI6OnJlY29kZV9mYWN0b3IoVFlQRVNfT0ZfUExBTlRTLCAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgTGVzcyB0aGFuIDVgPSJMZXNzIHRoYW4gNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGA2IHRvIDEwYD0iNiB0byAxMCIsIGAxMSB0byAyMGA9IjExIHRvIDIwIiwgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMjEgdG8gMzBgPSIyMSB0byAzMCIsIGBNb3JlIHRoYW4gMzBgID0gIk1vcmUgdGhhbiAzMCIsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLm9yZGVyZWQgPSBUUlVFKSAgKSAlPiUNCiAgc2VsZWN0KC1TQU1QTEVfTkFNRSwtYDE5YCkgLT4gZGZfdGVzdA0KICANCnBvbHJfbW9kZWwgPSBNQVNTOjpwb2xyKFRZUEVTX09GX1BMQU5UUyB+IC4sIGRhdGEgPSBkZl90ZXN0LCBIZXNzPVRSVUUpDQoNCnN1bW1hcnkocG9scl9tb2RlbCkNCg0KZXhwKGNvZWYocG9scl9tb2RlbCkpDQoNCmN0YWJsZSA8LSBjb2VmKHN1bW1hcnkocG9scl9tb2RlbCkpDQoNCnAgPC0gcG5vcm0oYWJzKGN0YWJsZVssICJ0IHZhbHVlIl0pLCBsb3dlci50YWlsID0gRkFMU0UpICogMg0KY3RhYmxlIDwtIGNiaW5kKGN0YWJsZSwgInAgdmFsdWUiID0gcCkNCg0KY2kgPC0gY29uZmludChwb2xyX21vZGVsKQ0KDQpleHAoY2JpbmQoT1IgPSBjb2VmKHBvbHJfbW9kZWwpLCBjaSkpDQpjdGFibGUNCg0KDQoNCg0KDQpgYGANCg0KYGBge3J9DQoNCm1ldGFkYXRhJE9ORV9MSVRFUl9PRl9XQVRFUl9BX0RBWV9GUkVRVUVOQ1kgJT4lIHRhYmxlDQoNCmVudGVyb3R5cGVzICU+JQ0KICByZXNoYXBlMjo6ZGNhc3QoYHNhbXBsZV9uYW1lYCB+IGBFbnRlcm90eXBlc19pZGAsIGxlbmd0aCkgJT4lDQogIG1lcmdlKG1ldGFkYXRhICU+JSBzZWxlY3QoU0FNUExFX05BTUUsT05FX0xJVEVSX09GX1dBVEVSX0FfREFZX0ZSRVFVRU5DWSksLiwgYnkueT0ic2FtcGxlX25hbWUiLCBieS54PSJTQU1QTEVfTkFNRSIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShPTkVfTElURVJfT0ZfV0FURVJfQV9EQVlfRlJFUVVFTkNZID0gZHBseXI6OnJlY29kZV9mYWN0b3IoT05FX0xJVEVSX09GX1dBVEVSX0FfREFZX0ZSRVFVRU5DWSwgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYE5ldmVyYD0iTmV2ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgUmFyZWx5YD0iUmFyZWx5IChsZXNzIHRoYW4gb25jZS93ZWVrKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBPY2Nhc2lvbmFsbHlgPSJPY2Nhc2lvbmFsbHkgKDEtMiB0aW1lcy93ZWVrKSIsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFJlZ3VsYXJseWA9IlJlZ3VsYXJseSAoMy01IHRpbWVzL3dlZWspIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBEYWlseWAgPSAiRGFpbHkiLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5vcmRlcmVkID0gVFJVRSkgICkgJT4lDQogIHNlbGVjdCgtU0FNUExFX05BTUUsLWAxOWApIC0+IGRmX3Rlc3QNCiAgDQpwb2xyX21vZGVsID0gTUFTUzo6cG9scihPTkVfTElURVJfT0ZfV0FURVJfQV9EQVlfRlJFUVVFTkNZIH4gLiwgZGF0YSA9IGRmX3Rlc3QsIEhlc3M9VFJVRSkNCg0Kc3VtbWFyeShwb2xyX21vZGVsKQ0KDQpleHAoY29lZihwb2xyX21vZGVsKSkNCg0KY3RhYmxlIDwtIGNvZWYoc3VtbWFyeShwb2xyX21vZGVsKSkNCg0KcCA8LSBwbm9ybShhYnMoY3RhYmxlWywgInQgdmFsdWUiXSksIGxvd2VyLnRhaWwgPSBGQUxTRSkgKiAyDQpjdGFibGUgPC0gY2JpbmQoY3RhYmxlLCAicCB2YWx1ZSIgPSBwKQ0KDQpjaSA8LSBjb25maW50KHBvbHJfbW9kZWwpDQoNCmV4cChjYmluZChPUiA9IGNvZWYocG9scl9tb2RlbCksIGNpKSkNCmN0YWJsZQ0KDQoNCg0KDQoNCg0KYGBgDQoNCmBgYHtyfQ0KDQpkaWV0X3ZhcmlhYmxlcyA9DQogIGMoIlRZUEVTX09GX1BMQU5UUyIsDQogICJESUVUX1RZUEUiLA0KICAiQUxDT0hPTF9GUkVRVUVOQ1kiLA0KICAiUkVEX01FQVRfRlJFUVVFTkNZIiwNCiAgIldIT0xFX0dSQUlOX0ZSRVFVRU5DWSIsDQogICJWRUdFVEFCTEVfRlJFUVVFTkNZIiwNCiAgIk1FQVRfRUdHU19GUkVRVUVOQ1kiLA0KICAiUFJFUEFSRURfTUVBTFNfRlJFUVVFTkNZIiwNCiAgIkZSVUlUX0ZSRVFVRU5DWSIsDQogICJPTkVfTElURVJfT0ZfV0FURVJfQV9EQVlfRlJFUVVFTkNZIiwNCiAgIlNFQUZPT0RfRlJFUVVFTkNZIiwNCiAgIkhPTUVDT09LRURfTUVBTFNfRlJFUVVFTkNZIiwNCiAgIkhJR0hfRkFUX1JFRF9NRUFUX0ZSRVFVRU5DWSIsDQogICJSRUFEWV9UT19FQVRfTUVBTFNfRlJFUVVFTkNZIiwNCiAgIlNVR0FSX1NXRUVURU5FRF9EUklOS19GUkVRVUVOQ1kiLA0KICAiU1VHQVJZX1NXRUVUU19GUkVRVUVOQ1kiLA0KICAiU0FMVEVEX1NOQUNLU19GUkVRVUVOQ1kiLA0KICAiU1BFQ0lBTElaRURfRElFVF9GT0RNQVAiLA0KICAiU1BFQ0lBTElaRURfRElFVF9FWENMVURFX0RBSVJZIiwNCiAgIlNQRUNJQUxJWkVEX0RJRVRfRVhDTFVERV9OSUdIVFNIQURFUyIsDQogICJTUEVDSUFMSVpFRF9ESUVUX01PRElGSUVEX1BBTEVPX0RJRVQiLA0KICAiU1BFQ0lBTElaRURfRElFVF9QQUxFT0RJRVRfT1JfUFJJTUFMX0RJRVQiLA0KICAiT0xJVkVfT0lMIikNCg0KDQoNCnByZXBhcmVfZGF0YV9mb3JfbW9kZWxpbmcgPSBmdW5jdGlvbih0YXJnZXQsIGxldmVsc19zZXQsIG9yZGVyX2xldmVscykgew0KDQogIHRhcmdldCA8LSBlbnF1byh0YXJnZXQpDQogICNsZXZlbHNfc2V0IDwtIGVucXVvKGxldmVsc19zZXQpDQogIA0KICBsZXZlbHNfc2V0PWxldmVsc19zZXRbbGV2ZWxzX3NldCAlaW4lIChtZXRhZGF0YSAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLCEhdGFyZ2V0KSAlPiUgcHVsbCgyKSAlPiUgdW5pcXVlKCkpXQ0KICANCiAgDQogIGVudGVyb3R5cGVzICU+JQ0KICAgIHJlc2hhcGUyOjpkY2FzdChgc2FtcGxlX25hbWVgIH4gYEVudGVyb3R5cGVzX2lkYCwgbGVuZ3RoKSAlPiUNCiAgICBtZXJnZShtZXRhZGF0YSAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLCEhdGFyZ2V0KSwuLCBieS55PSJzYW1wbGVfbmFtZSIsIGJ5Lng9IlNBTVBMRV9OQU1FIikgJT4lDQogICAgbmEub21pdCgpICU+JQ0KICAgIGRwbHlyOjpyZW5hbWUoeCA6PSAhIXRhcmdldCkgJT4lDQogICAgbXV0YXRlKHggPSBmb3JjYXRzOjpmY3RfcmVjb2RlKHgsICEhIWxldmVsc19zZXQpICU+JSANCiAgICAgICAgICAgICBmYWN0b3IobGV2ZWxzID0gb3JkZXJfbGV2ZWxzICwgb3JkZXJlZCA9IFRSVUUpICkgICU+JQ0KICAgIHNlbGVjdCgtU0FNUExFX05BTUUsLWAxOWApIC0+IGRmX3Rlc3QNCiAgDQpyZXR1cm4oZGZfdGVzdCkNCiAgICANCn0NCg0KDQoNCiAgDQpwb2xyX21vZGVsaW5nID0gZnVuY3Rpb24oZGF0YSkgew0KICANCiAgZGZfdGVzdD1kYXRhDQogIA0KICBwb2xyX21vZGVsID0gTUFTUzo6cG9scih4IH4gLiwgZGF0YSA9IGRmX3Rlc3QsIEhlc3M9VFJVRSkNCiAgDQogICNzdW1tYXJ5KHBvbHJfbW9kZWwpDQogIA0KICAjZXhwKGNvZWYocG9scl9tb2RlbCkpDQogIA0KICBjdGFibGUgPC0gY29lZihzdW1tYXJ5KHBvbHJfbW9kZWwpKQ0KICBwIDwtIHBub3JtKGFicyhjdGFibGVbLCAidCB2YWx1ZSJdKSwgbG93ZXIudGFpbCA9IEZBTFNFKSAqIDINCiAgY3RhYmxlIDwtIGNiaW5kKGN0YWJsZSwgInAgdmFsdWUiID0gcCkNCiAgc3VwcHJlc3NNZXNzYWdlcyhjaSA8LSBjb25maW50KHBvbHJfbW9kZWwpKQ0KICAjZXhwKGNiaW5kKE9SID0gY29lZihwb2xyX21vZGVsKSwgY2kpKQ0KICAjY3RhYmxlDQogIA0KICByZXM9bWVyZ2UoZXhwKGNiaW5kKE9SID0gY29lZihwb2xyX21vZGVsKSwgY2kpKSxjdGFibGUsYnk9InJvdy5uYW1lcyIsIGFsbD1UUlVFKQ0KICByZXR1cm4ocmVzKQ0KfQ0KICAgIA0KDQp0YXJnZXQgPQ0KICBjKCJSRURfTUVBVF9GUkVRVUVOQ1kiLA0KICAiV0hPTEVfR1JBSU5fRlJFUVVFTkNZIiwNCiAgIlZFR0VUQUJMRV9GUkVRVUVOQ1kiLA0KICAiTUVBVF9FR0dTX0ZSRVFVRU5DWSIsDQogICJQUkVQQVJFRF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiRlJVSVRfRlJFUVVFTkNZIiwNCiAgIk9ORV9MSVRFUl9PRl9XQVRFUl9BX0RBWV9GUkVRVUVOQ1kiLA0KICAiU0VBRk9PRF9GUkVRVUVOQ1kiLA0KICAiSE9NRUNPT0tFRF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiSElHSF9GQVRfUkVEX01FQVRfRlJFUVVFTkNZIiwNCiAgIlJFQURZX1RPX0VBVF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiU1VHQVJfU1dFRVRFTkVEX0RSSU5LX0ZSRVFVRU5DWSIsDQogICJTVUdBUllfU1dFRVRTX0ZSRVFVRU5DWSIsDQogICJTQUxURURfU05BQ0tTX0ZSRVFVRU5DWSIsDQogICJPTElWRV9PSUwiKQ0KDQoNCiN0YXJnZXQgPSBjKCJSRURfTUVBVF9GUkVRVUVOQ1kiLCJXSE9MRV9HUkFJTl9GUkVRVUVOQ1kiKQ0KDQoNCg0KDQpsZXZlbHNfc2V0ID0gYyhgTmV2ZXJgPSJOZXZlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBSYXJlbHlgPSJSYXJlbHkgKGxlc3MgdGhhbiBvbmNlL3dlZWspIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYE9jY2FzaW9uYWxseWA9Ik9jY2FzaW9uYWxseSAoMS0yIHRpbWVzL3dlZWspIiwgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgUmVndWxhcmx5YD0iUmVndWxhcmx5ICgzLTUgdGltZXMvd2VlaykiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYERhaWx5YCA9ICJEYWlseSIpDQoNCm9yZGVyX2xldmVscyA9IGMoIk5ldmVyIiwiUmFyZWx5IiwiT2NjYXNpb25hbGx5IiwiUmVndWxhcmx5IiwiRGFpbHkiKQ0KDQoNCmNvbWJpbmVfcG9scl9tb2RlbF9yZXN1bHQgPSBmdW5jdGlvbih0YXJnZXQsbGV2ZWxzX3NldCwgb3JkZXJfbGV2ZWxzKXsNCg0KICBmaW5hbF9yZXMgPSBOVUxMDQogIA0KZm9yKGkgaW4gc2VxX2Fsb25nKHRhcmdldCkpIHsNCiAgDQogIGNhdCgibW9kZWxpbmciLHRhcmdldFtpXSwiLi4uIikNCiAgDQogIHJlcz0gcHJlcGFyZV9kYXRhX2Zvcl9tb2RlbGluZyh0YXJnZXQgPSB0YXJnZXRbaV0sIGxldmVsc19zZXQ9bGV2ZWxzX3NldCwgb3JkZXJfbGV2ZWxzPW9yZGVyX2xldmVscykgJT4lIA0KICBwb2xyX21vZGVsaW5nKCkNCiAgDQogIHRtcD1kYXRhLmZyYW1lKHRhcmdldD10YXJnZXRbaV0scmVzKQ0KICANCiAgZmluYWxfcmVzID0gcmJpbmQoZmluYWxfcmVzLHRtcCkNCiAgDQogIGNhdCgiLiBkb25lXG4iKSB9DQoNCiAgcmV0dXJuKGZpbmFsX3JlcykgDQogICAgDQp9DQoNCg0KZGlldF9maW5hbF9yZXMgPSBjb21iaW5lX3BvbHJfbW9kZWxfcmVzdWx0KHRhcmdldCA9IHRhcmdldCwgbGV2ZWxzX3NldD1sZXZlbHNfc2V0LCBvcmRlcl9sZXZlbHM9b3JkZXJfbGV2ZWxzKQ0KDQpzYXZlKGRpZXRfZmluYWxfcmVzLCBmaWxlPSJkaWV0X2ZpbmFsX3Jlcy5yZGEiKQ0KDQpgYGANCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTZ9DQoNCg0KZGlldF9maW5hbF9yZXMgJT4lDQogIG11dGF0ZShSb3cubmFtZXMgPSBSb3cubmFtZXMgJT4lIGFzLmNoYXJhY3RlcigpKSAlPiUgDQogIG11dGF0ZShPUiA9IGN1dChPUiwgYnJlYWtzID0gYygwLDEvNCwxLzIsMSwyLDQsMTAwKSkgJT4lIGFzLmNoYXJhY3RlcigpKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShPUikpICU+JSAjcHVsbChPUikNCiAgbXV0YXRlKE9SID0gaWZlbHNlKHAudmFsdWU+MC4wNSwiTlMiLE9SKSkgJT4lICNwdWxsKE9SKSAlPiUgZmFjdG9yKCkNCiAgbXV0YXRlKE9SID0gZmFjdG9yKE9SLCBsZXZlbHM9YygiKDAuMjUsMC41XSIsICIoMC41LDFdIiwgIk5TIiwgIigxLDJdIiwgIigyLDRdIiwgIig0LDEwMF0iICkgICkpICU+JSANCiAgZmlsdGVyKFJvdy5uYW1lcyAlaW4lIHBhc3RlMCgiYCIsYXMuY2hhcmFjdGVyKDE6MjApLCJgIikgICApICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fdGlsZShhZXMoeD1Sb3cubmFtZXMlPiVhcy5jaGFyYWN0ZXIsIHk9dGFyZ2V0LCBmaWxsPU9SKSkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwoIk9SIiwgbGFiZWxzPWMoIjAuMjUtMC41IiwiMC41LTEiLCJOUyIsIjEtMiIsIjItNCIsIj40IiksIA0KICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCIjZDhiMzY1IiwiI2Y2ZThjMyIsIiNmNWY1ZjUiLCIjYzdlYWU1IiwiIzVhYjRhYyIsIiMwMTY2NWUiKSkgKyBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkNCg0KDQpkaWV0X2ZpbmFsX3JlcyAlPiUNCiAgbXV0YXRlKFJvdy5uYW1lcyA9IFJvdy5uYW1lcyAlPiUgYXMuY2hhcmFjdGVyKCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKE9SKSkgJT4lDQogIG11dGF0ZShPUj1sb2coT1IpKSAlPiUNCiAgcmVzaGFwZTI6OmRjYXN0KFJvdy5uYW1lc350YXJnZXQsIHZhbHVlLnZhciA9ICJPUiIpICU+JQ0KICB0aWJibGU6OmNvbHVtbl90b19yb3duYW1lcygiUm93Lm5hbWVzIikgJT4lDQogIGFzLm1hdHJpeCgpICU+JQ0KICB0KCkgJT4lDQogIGhlYXRtYXAoKQ0KDQoNCg0KZGlldF9maW5hbF9yZXMgJT4lDQogIG11dGF0ZShSb3cubmFtZXMgPSBSb3cubmFtZXMgJT4lIGFzLmNoYXJhY3RlcigpKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShPUikpICU+JQ0KICBtdXRhdGUoT1I9bG9nKE9SKSkgJT4lDQogIGdyb3VwX2J5KHRhcmdldCkgJT4lDQogIG11dGF0ZShPUj1zY2FsZShPUikpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fdGlsZShhZXMoeD1Sb3cubmFtZXMlPiVhcy5jaGFyYWN0ZXIsIHk9dGFyZ2V0LCBmaWxsPU9SKSkgKyBzY2FsZV9maWxsX2Rpc3RpbGxlcigibG9nXG5PZGRzIix0eXBlPSJkaXYiKQ0KDQoNCg0KDQoNCmBgYA0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KDQptZXRhZGF0YSAlPiUgDQogIHNlbGVjdChjb250YWlucygiX0ZSRVFVRU5DWSIpLCAtT1RIRVJfU1VQUExFTUVOVF9GUkVRVUVOQ1ksIC1GRVJNRU5URURfRlJFUVVFTkNZLCBPTElWRV9PSUwpICU+JQ0KICBjb2xuYW1lcygpIC0+IHRhcmdldA0KDQpsZXZlbHNfc2V0ID0gYyhBID0gIk5ldmVyIiwNCiAgICAgICAgICAgICAgIEIgPSAiUmFyZWx5IChsZXNzIHRoYW4gb25jZS93ZWVrKSIsDQogICAgICAgICAgICAgICBCID0gIlJhcmVseSAobGVzcyB0aGFuIG9uY2Uvd2VlaykiLCAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICBDID0gIk9jY2FzaW9uYWxseSAoMS0yIHRpbWVzL3dlZWspIiwgIA0KICAgICAgICAgICAgICAgRCA9ICJSZWd1bGFybHkgKDMtNSB0aW1lcy93ZWVrKSIsIA0KICAgICAgICAgICAgICAgRSA9ICJEYWlseSIpDQoNCm9yZGVyX2xldmVscz1MRVRURVJTWzE6NV0NCg0KI29yZGVyX2xldmVscyA9IGMoIk5ldmVyIiwiUmFyZWx5IiwiT2NjYXNpb25hbGx5IiwiUmVndWxhcmx5IiwiRGFpbHkiKQ0KDQpnbG9iYWxfZmluYWxfcmVzID0gY29tYmluZV9wb2xyX21vZGVsX3Jlc3VsdCh0YXJnZXQgPSB0YXJnZXRbMTozXSwgbGV2ZWxzX3NldD1sZXZlbHNfc2V0LCBvcmRlcl9sZXZlbHM9b3JkZXJfbGV2ZWxzKQ0KDQoNCiNwcmVwYXJlX2RhdGFfZm9yX21vZGVsaW5nKHRhcmdldCA9IHRhcmdldFsxXSwgbGV2ZWxzX3NldD1sZXZlbHNfc2V0LCBvcmRlcl9sZXZlbHM9b3JkZXJfbGV2ZWxzKQ0KDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCm1ldGFkYXRhJGBTdWItcmVnaW9uIE5hbWVgICU+JSB0YWJsZQ0KbWV0YWRhdGEkYFJlZ2lvbiBOYW1lYCAlPiUgdGFibGUNCg0KZW50ZXJvdHlwZXMgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZD1wYXN0ZTAoImV0IixFbnRlcm90eXBlc19pZCkpICU+JQ0KICByZXNoYXBlMjo6ZGNhc3QoYHNhbXBsZV9uYW1lYCB+IGBFbnRlcm90eXBlc19pZGAsIGxlbmd0aCkgJT4lDQogIG1lcmdlKG1ldGFkYXRhICU+JSBmaWx0ZXIoQ09VTlRSWSAlaW4lIGMoIlVTQSIsIkNhbmFkYSIpKSAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLGBTdWItcmVnaW9uIE5hbWVgKSwuLCBieS55PSJzYW1wbGVfbmFtZSIsIGJ5Lng9IlNBTVBMRV9OQU1FIikgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgbXV0YXRlKGBTdWItcmVnaW9uIE5hbWVgID0gZm9yY2F0czo6ZmN0X3JlbGV2ZWwoYFN1Yi1yZWdpb24gTmFtZWAsIHJlZiA9ICJOb3J0aGVybiBBbWVyaWNhIikpICU+JQ0KICBkcGx5cjo6cmVuYW1lKHJlZ2lvbj1gU3ViLXJlZ2lvbiBOYW1lYCkgJT4lDQogIHNlbGVjdCgtU0FNUExFX05BTUUsLWV0MTkpIC0+IGRmX3JlZ2lvbg0KICBubmV0OjptdWx0aW5vbShyZWdpb24gfiAuLCBkYXRhID0gZGZfcmVnaW9uKSAtPiByZWdpb25fYmlydGhfbW9kZWwNCg0KDQpyZWdpb25fYmlydGhfbW9kZWxfZWZmZWN0cyA9IGdnZWZmZWN0czo6Z2dlZmZlY3QocmVnaW9uX2JpcnRoX21vZGVsKQ0KDQpzYXZlKHJlZ2lvbl9iaXJ0aF9tb2RlbCwgZmlsZT0icmVnaW9uX2JpcnRoX21vZGVsLnJkYSIpDQoNCnJlZ2lvbl9iaXJ0aF9tb2RlbF9zdW1tYXJ5ID0gc3VtbWFyeShyZWdpb25fYmlydGhfbW9kZWwpDQoNCmNpID0gY29uZmludChyZWdpb25fYmlydGhfbW9kZWwpDQoNCnp2YWx1ZXMgPC0gcmVnaW9uX2JpcnRoX21vZGVsX3N1bW1hcnkkY29lZmZpY2llbnRzIC8gcmVnaW9uX2JpcnRoX21vZGVsX3N1bW1hcnkkc3RhbmRhcmQuZXJyb3JzDQpwbm9ybShhYnMoenZhbHVlcyksIGxvd2VyLnRhaWw9RkFMU0UpKjINCg0KDQooMTAwKihleHAoY29lZihyZWdpb25fYmlydGhfbW9kZWwpKS0xKSkgJT4lIC5bLC0xXSAlPiUgIGhlYXRtYXAoKQ0KDQoNCmNvZWYocmVnaW9uX2JpcnRoX21vZGVsKSAlPiUgLlssLTFdICU+JSBoZWF0bWFwKCkNCg0KenZhbHVlcyAlPiUgLlssLTFdICU+JSAuWywtMTNdJT4lICBoZWF0bWFwKCkNCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQpjb2VmKHJlZ2lvbl9iaXJ0aF9tb2RlbCkgJT4lIC5bLC0xXSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigicmVnaW9uIikgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkLnZhcnM9InJlZ2lvbiIpICU+JQ0KICBncm91cF9ieShyZWdpb24pICU+JQ0KICBtdXRhdGUodmFsdWU9c2NhbGUodmFsdWUpKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX3RpbGUoYWVzKHk9cmVnaW9uLHg9dmFyaWFibGUsZmlsbD12YWx1ZSkpICsgc2NhbGVfZmlsbF9kaXN0aWxsZXIodHlwZT0iZGl2IikNCg0KDQpgYGANCg0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0NCg0KcmJpbmQoY29lZihyZWdpb25fYmlydGhfbW9kZWwpICU+JSAuWywtMV0gJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oInJlZ2lvbiIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZC52YXJzPSJyZWdpb24iKSAlPiUNCiAgZ3JvdXBfYnkocmVnaW9uKSAlPiUNCiAgbXV0YXRlKHZhbHVlPXNjYWxlKHZhbHVlKSkgJT4lIGRwbHlyOjpyZW5hbWUodGFyZ2V0PTEscGFydGl0aW9uPTIsT1I9MykgJT4lIHNlbGVjdCgxOjMpLA0KDQoNCmRpZXRfZmluYWxfcmVzICU+JQ0KICBtdXRhdGUoUm93Lm5hbWVzID0gUm93Lm5hbWVzICU+JSBhcy5jaGFyYWN0ZXIoKSkgJT4lDQogIGZpbHRlcighaXMubmEoT1IpKSAlPiUNCiAgbXV0YXRlKE9SPWxvZyhPUikpICU+JQ0KICBncm91cF9ieSh0YXJnZXQpICU+JQ0KICBtdXRhdGUoT1I9c2NhbGUoT1IpKSAgJT4lIGRwbHlyOjpyZW5hbWUodGFyZ2V0PTEscGFydGl0aW9uPTIsT1I9MykgJT4lIHNlbGVjdCgxOjMpICkgJT4lDQogIA0KICByZXNoYXBlMjo6ZGNhc3QocGFydGl0aW9ufnRhcmdldCwgdmFsdWUudmFyID0gIk9SIikgJT4lDQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJwYXJ0aXRpb24iKSAlPiUNCiAgYXMubWF0cml4KCkgJT4lDQogIHQoKSAlPiUNCiAgaGVhdG1hcChjb2wgPSBoY2wuY29sb3JzKDEyLCAiQnJCRyIsIHJldiA9IFRSVUUpKQ0KDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCg0KbWV0YWRhdGEkR0xVVEVOICU+JSB0YWJsZQ0KDQplbnRlcm90eXBlcyAlPiUNCiAgcmVzaGFwZTI6OmRjYXN0KGBzYW1wbGVfbmFtZWAgfiBgRW50ZXJvdHlwZXNfaWRgLCBsZW5ndGgpICU+JQ0KICBtZXJnZShtZXRhZGF0YSAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEdMVVRFTiksLiwgYnkueT0ic2FtcGxlX25hbWUiLCBieS54PSJTQU1QTEVfTkFNRSIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShHTFVURU4gPSBmb3JjYXRzOjpmY3RfcmVjb2RlKEdMVVRFTiwgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYE5vYD0iTm8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgWWVzYD0iSSBkbyBub3QgZWF0IGdsdXRlbiBiZWNhdXNlIGl0IG1ha2VzIG1lIGZlZWwgYmFkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFllc2A9Ikkgd2FzIGRpYWdub3NlZCB3aXRoIGNlbGlhYyBkaXNlYXNlIiwgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgbWVkaXVtYD0iSSB3YXMgZGlhZ25vc2VkIHdpdGggZ2x1dGVuIGFsbGVyZ3kgKGFudGktZ2x1dGVuIElnRyksIGJ1dCBub3QgY2VsaWFjIGRpc2Vhc2UiKSAlPiUgDQogICAgICAgICAgIGZhY3RvcihsZXZlbHMgPSBjKCJObyIsIm1lZGl1bSIsIlllcyIpICwgb3JkZXJlZCA9IFRSVUUpICkgICU+JQ0KICBzZWxlY3QoLVNBTVBMRV9OQU1FLC1gMTlgKSAtPiBkZl90ZXN0DQogIA0KcG9scl9tb2RlbCA9IE1BU1M6OnBvbHIoR0xVVEVOIH4gLiwgZGF0YSA9IGRmX3Rlc3QsIEhlc3M9VFJVRSkNCg0Kc3VtbWFyeShwb2xyX21vZGVsKQ0KDQpleHAoY29lZihwb2xyX21vZGVsKSkNCg0KY3RhYmxlIDwtIGNvZWYoc3VtbWFyeShwb2xyX21vZGVsKSkNCg0KcCA8LSBwbm9ybShhYnMoY3RhYmxlWywgInQgdmFsdWUiXSksIGxvd2VyLnRhaWwgPSBGQUxTRSkgKiAyDQpjdGFibGUgPC0gY2JpbmQoY3RhYmxlLCAicCB2YWx1ZSIgPSBwKQ0KDQpjaSA8LSBjb25maW50KHBvbHJfbW9kZWwpDQoNCmV4cChjYmluZChPUiA9IGNvZWYocG9scl9tb2RlbCksIGNpKSkNCmN0YWJsZQ0KDQoNCg0KDQoNCg0KDQpgYGANCg0KYGBge3J9DQoNCg0KbWV0YWRhdGEkR0xVVEVOICU+JSB0YWJsZQ0KDQplbnRlcm90eXBlcyAlPiUNCiAgcmVzaGFwZTI6OmRjYXN0KGBzYW1wbGVfbmFtZWAgfiBgRW50ZXJvdHlwZXNfaWRgLCBsZW5ndGgpICU+JQ0KICBtZXJnZShtZXRhZGF0YSAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLEdMVVRFTiksLiwgYnkueT0ic2FtcGxlX25hbWUiLCBieS54PSJTQU1QTEVfTkFNRSIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShHTFVURU4gPSBmb3JjYXRzOjpmY3RfcmVjb2RlKEdMVVRFTiwgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYE5vYD0iTm8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgWWVzYD0iSSBkbyBub3QgZWF0IGdsdXRlbiBiZWNhdXNlIGl0IG1ha2VzIG1lIGZlZWwgYmFkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFllc2A9Ikkgd2FzIGRpYWdub3NlZCB3aXRoIGNlbGlhYyBkaXNlYXNlIiwgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgWWVzYD0iSSB3YXMgZGlhZ25vc2VkIHdpdGggZ2x1dGVuIGFsbGVyZ3kgKGFudGktZ2x1dGVuIElnRyksIGJ1dCBub3QgY2VsaWFjIGRpc2Vhc2UiKSAlPiUgDQogICAgICAgICAgIGZhY3RvcihsZXZlbHMgPSBjKCJObyIsIlllcyIpICwgb3JkZXJlZCA9IFRSVUUpICkgICU+JQ0KICBzZWxlY3QoLVNBTVBMRV9OQU1FLC1gMTlgKSAtPiBkZl90ZXN0DQogIA0KcG9scl9tb2RlbCA9IGdsbShHTFVURU4gfiAuLCBkYXRhID0gZGZfdGVzdCwgZmFtaWx5PWJpbm9taWFsKQ0KDQpzdW1tYXJ5KHBvbHJfbW9kZWwpDQoNCmV4cChjb2VmKHBvbHJfbW9kZWwpKQ0KDQpjdGFibGUgPC0gY29lZihzdW1tYXJ5KHBvbHJfbW9kZWwpKQ0KDQojcCA8LSBwbm9ybShhYnMoY3RhYmxlWywgInQgdmFsdWUiXSksIGxvd2VyLnRhaWwgPSBGQUxTRSkgKiAyDQojY3RhYmxlIDwtIGNiaW5kKGN0YWJsZSwgInAgdmFsdWUiID0gcCkNCg0KY2kgPC0gY29uZmludChwb2xyX21vZGVsKQ0KDQpleHAoY2JpbmQoT1IgPSBjb2VmKHBvbHJfbW9kZWwpLCBjaSkpDQpjdGFibGUNCg0KDQoNCg0KDQpgYGANCg0KYGBge3J9DQoNCg0KbWV0YWRhdGEkU1BFQ0lBTElaRURfRElFVF9FWENMVURFX05JR0hUU0hBREVTICU+JSB0YWJsZQ0KDQplbnRlcm90eXBlcyAlPiUNCiAgcmVzaGFwZTI6OmRjYXN0KGBzYW1wbGVfbmFtZWAgfiBgRW50ZXJvdHlwZXNfaWRgLCBsZW5ndGgpICU+JQ0KICBtZXJnZShtZXRhZGF0YSAlPiUgc2VsZWN0KFNBTVBMRV9OQU1FLFNQRUNJQUxJWkVEX0RJRVRfRVhDTFVERV9EQUlSWSksLiwgYnkueT0ic2FtcGxlX25hbWUiLCBieS54PSJTQU1QTEVfTkFNRSIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShTUEVDSUFMSVpFRF9ESUVUX0VYQ0xVREVfREFJUlkgPSBmb3JjYXRzOjpmY3RfcmVjb2RlKFNQRUNJQUxJWkVEX0RJRVRfRVhDTFVERV9EQUlSWSwgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYE5vYD0iTm8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgWWVzYD0iWWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFllc2A9InRydWUiLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBOb2A9ImZhbHNlIikgJT4lIA0KICAgICAgICAgICBmYWN0b3IobGV2ZWxzID0gYygiTm8iLCJZZXMiKSAsIG9yZGVyZWQgPSBUUlVFKSApICAlPiUNCiAgc2VsZWN0KC1TQU1QTEVfTkFNRSwtYDE5YCkgLT4gZGZfdGVzdA0KICANCnBvbHJfbW9kZWwgPSBnbG0oU1BFQ0lBTElaRURfRElFVF9FWENMVURFX0RBSVJZIH4gLiwgZGF0YSA9IGRmX3Rlc3QsIGZhbWlseT1iaW5vbWlhbCkNCg0Kc3VtbWFyeShwb2xyX21vZGVsKQ0KDQpleHAoY29lZihwb2xyX21vZGVsKSkNCg0KY3RhYmxlIDwtIGNvZWYoc3VtbWFyeShwb2xyX21vZGVsKSkNCg0KI3AgPC0gcG5vcm0oYWJzKGN0YWJsZVssICJ0IHZhbHVlIl0pLCBsb3dlci50YWlsID0gRkFMU0UpICogMg0KI2N0YWJsZSA8LSBjYmluZChjdGFibGUsICJwIHZhbHVlIiA9IHApDQoNCmNpIDwtIGNvbmZpbnQocG9scl9tb2RlbCkNCg0KZXhwKGNiaW5kKE9SID0gY29lZihwb2xyX21vZGVsKSwgY2kpKQ0KY3RhYmxlDQoNCg0KDQoNCmBgYA0KYGBge3J9DQoNCg0KDQptZXRhZGF0YSRESUFCRVRFUyAlPiUgdGFibGUNCg0KZW50ZXJvdHlwZXMgJT4lDQogIHJlc2hhcGUyOjpkY2FzdChgc2FtcGxlX25hbWVgIH4gYEVudGVyb3R5cGVzX2lkYCwgbGVuZ3RoKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGEgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxESUFCRVRFUyksLiwgYnkueT0ic2FtcGxlX25hbWUiLCBieS54PSJTQU1QTEVfTkFNRSIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShESUFCRVRFUyA9IGZvcmNhdHM6OmZjdF9yZWNvZGUoRElBQkVURVMsICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBOb2A9IkkgZG8gbm90IGhhdmUgdGhpcyBjb25kaXRpb24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgWWVzYD0iRGlhZ25vc2VkIGJ5IGEgbWVkaWNhbCBwcm9mZXNzaW9uYWwgKGRvY3RvciwgcGh5c2ljaWFuIGFzc2lzdGFudCkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgbWVkaXVtYD0iRGlhZ25vc2VkIGJ5IGFuIGFsdGVybmF0aXZlIG1lZGljaW5lIHByYWN0aXRpb25lciIsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYG1lZGl1bWA9IlNlbGYtZGlhZ25vc2VkIikgJT4lIA0KICAgICAgICAgICBmYWN0b3IobGV2ZWxzID0gYygiTm8iLCJtZWRpdW0iLCJZZXMiKSAsIG9yZGVyZWQgPSBUUlVFKSApICAlPiUNCiAgZmlsdGVyKERJQUJFVEVTICE9ICJtZWRpdW0iKSAlPiUNCiAgc2VsZWN0KC1TQU1QTEVfTkFNRSwtYDE5YCkgLT4gZGZfdGVzdA0KICANCnBvbHJfbW9kZWwgPSBnbG0oRElBQkVURVMgfiAuLCBkYXRhID0gZGZfdGVzdCwgZmFtaWx5PWJpbm9taWFsKQ0KDQpzdW1tYXJ5KHBvbHJfbW9kZWwpDQoNCmV4cChjb2VmKHBvbHJfbW9kZWwpKQ0KDQpjdGFibGUgPC0gY29lZihzdW1tYXJ5KHBvbHJfbW9kZWwpKQ0KDQojcCA8LSBwbm9ybShhYnMoY3RhYmxlWywgInQgdmFsdWUiXSksIGxvd2VyLnRhaWwgPSBGQUxTRSkgKiAyDQojY3RhYmxlIDwtIGNiaW5kKGN0YWJsZSwgInAgdmFsdWUiID0gcCkNCg0KY2kgPC0gY29uZmludChwb2xyX21vZGVsKQ0KDQpleHAoY2JpbmQoT1IgPSBjb2VmKHBvbHJfbW9kZWwpLCBjaSkpDQpjdGFibGUNCg0KDQoNCg0KDQpgYGANCg0KYGBge3J9DQoNCg0KbWV0YWRhdGEkQk1JX0NBVCAlPiUgdGFibGUNCg0KZW50ZXJvdHlwZXMgJT4lDQogIHJlc2hhcGUyOjpkY2FzdChgc2FtcGxlX25hbWVgIH4gYEVudGVyb3R5cGVzX2lkYCwgbGVuZ3RoKSAlPiUNCiAgbWVyZ2UobWV0YWRhdGEgJT4lIHNlbGVjdChTQU1QTEVfTkFNRSxCTUlfQ0FUKSwuLCBieS55PSJzYW1wbGVfbmFtZSIsIGJ5Lng9IlNBTVBMRV9OQU1FIikgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgbXV0YXRlKEJNSV9DQVQgPSBmb3JjYXRzOjpmY3RfcmVjb2RlKEJNSV9DQVQsICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBVbmRlcndlaWdodGA9IlVuZGVyd2VpZ2h0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYE5vcm1hbGA9Ik5vcm1hbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBPdmVyd2VpZ2h0YD0iT3ZlcndlaWdodCIsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYE9iZXNlYD0iT2Jlc2UiKSAlPiUgDQogICAgICAgICAgIGZhY3RvcihsZXZlbHMgPSBjKCJVbmRlcndlaWdodCIsIk5vcm1hbCIsIk92ZXJ3ZWlnaHQiLCJPYmVzZSIpICwgb3JkZXJlZCA9IFRSVUUpICkgICU+JQ0KICBmaWx0ZXIoQk1JX0NBVCAhPSAiVW5kZXJ3ZWlnaHQiKSAlPiUNCiAgbXV0YXRlKEJNSV9DQVQgPSBmYWN0b3IoQk1JX0NBVCwgbGV2ZWxzID0gYygiTm9ybWFsIiwiT3ZlcndlaWdodCIsIk9iZXNlIikgLCBvcmRlcmVkID0gVFJVRSkpICU+JQ0KICBzZWxlY3QoLVNBTVBMRV9OQU1FLC1gMTlgKSAtPiBkZl90ZXN0DQogIA0KcG9scl9tb2RlbCA9IE1BU1M6OnBvbHIoQk1JX0NBVCB+IC4sIGRhdGEgPSBkZl90ZXN0LCBIZXNzPVRSVUUpDQoNCnN1bW1hcnkocG9scl9tb2RlbCkNCg0KZXhwKGNvZWYocG9scl9tb2RlbCkpDQoNCmN0YWJsZSA8LSBjb2VmKHN1bW1hcnkocG9scl9tb2RlbCkpDQoNCnAgPC0gcG5vcm0oYWJzKGN0YWJsZVssICJ0IHZhbHVlIl0pLCBsb3dlci50YWlsID0gRkFMU0UpICogMg0KY3RhYmxlIDwtIGNiaW5kKGN0YWJsZSwgInAgdmFsdWUiID0gcCkNCg0KY2kgPC0gY29uZmludChwb2xyX21vZGVsKQ0KDQpleHAoY2JpbmQoT1IgPSBjb2VmKHBvbHJfbW9kZWwpLCBjaSkpDQpjdGFibGUNCg0KDQoNCg0KDQoNCmBgYA0KDQoNCg0KIyMgbXVsdGlub21pYWwgcmVncmVzc2lvbg0KDQp3ZSBhaW1lZCBoZXJlIHRvIHByZWRpY3QgbWljcm9iaW9tZSBwYXJ0aXRpb24gZnJvbSBtZXRhZGF0YS4gDQpQYXJ0aXRpb24gIzEsIHRoZSBtb3N0IGNlbnRyb2lkIGluIGJyYW5jaCBzdHJ1Y3R1cmUgYW5kIGhpZ2hlc3QgZGl2ZXJzaXR5LA0Kd2lsbCBiZSB1c2VkIGFzIHJlZmVyZW5jZQ0KDQoNCg0KIyMjIHByZXBhcmUgZGF0YQ0KDQojIyMjIGltcG9ydCBtZXRhZGF0YSBhbmQgbWVyZ2Ugd2l0aCBVTlNEIHJlZ2lvbnMNCmBgYHtyfQ0KZW50ZXJvdHlwZXMgPSByZWFkcjo6cmVhZF9jc3YyKCJlbnRlcm90eXBlc19wcmVkaWN0aW9uX291dGxpZXJzLmNzdiIpWywtMV0gJT4lIGZpbHRlcighaXMubmEoRW50ZXJvdHlwZXNfaWQpKQ0KbWV0YWRhdGE9cmVhZC5jc3YyKHN5c3RlbS5maWxlKCJkYXRhLXJhdy9NZXRhZGF0YV8xMDMxN18yMDE5MTAyMi0xMTI0MTRfY3VyYXRlZHY0X1ZTdjEuY3N2IiwgcGFja2FnZSA9ICJndXR6aWxsYSIpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsICkgJT4lIG11dGF0ZV9hbGwobmFfaWYsIiIpDQoNCm1ldGFkYXRhICU+JSAuWzE6NSwxOjVdDQoNCg0KZGF0YSgiVU5TRF9jb3VudHJpZXMiKQ0KDQptZXRhZGF0YSA8LSBtZXRhZGF0YSAlPiUgDQogICNzZWxlY3QoU0FNUExFX05BTUUsIENPVU5UUllfT0ZfQklSVEgpICU+JQ0KICBtZXJnZShVTlNEX2NvdW50cmllcyAlPiUgDQogICAgICAgICAgc2VsZWN0KGBDb3VudHJ5IG9yIEFyZWFgLCBgU3ViLXJlZ2lvbiBOYW1lYCwgYFJlZ2lvbiBOYW1lYCkgJT4lIA0KICAgICAgICAgIG11dGF0ZShgQ291bnRyeSBvciBBcmVhYCA9ICBnc3ViKCJVbml0ZWQgS2luZ2RvbSBvZiBHcmVhdCBCcml0YWluIGFuZCBOb3J0aGVybiBJcmVsYW5kIiwgIlVuaXRlZCBLaW5nZG9tIiwgYENvdW50cnkgb3IgQXJlYWApKSAlPiUgDQogICAgICAgICAgbXV0YXRlKGBDb3VudHJ5IG9yIEFyZWFgID0gIGdzdWIoIlVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYSIsICJVU0EiLCBgQ291bnRyeSBvciBBcmVhYCkpICU+JQ0KICAgICAgICAgIG11dGF0ZShgU3ViLXJlZ2lvbiBOYW1lYCA9ICBpZmVsc2UoYFN1Yi1yZWdpb24gTmFtZWAgJWluJSBjKCJDZW50cmFsIEFzaWEiLCAiU291dGhlcm4gQXNpYSIpLCAiQ2VudHJhbCBhbmQgU291dGhlcm4gQXNpYSIsYFN1Yi1yZWdpb24gTmFtZWApKSAlPiUNCiAgICAgICAgICBtdXRhdGUoYFN1Yi1yZWdpb24gTmFtZWAgPSAgaWZlbHNlKGBTdWItcmVnaW9uIE5hbWVgICVpbiUgYygiTWVsYW5lc2lhIiwgIk1pY3JvbmVzaWEiLCJQb2x5bmVzaWEiKSwgIk9jZWFuaWEgKG90aGVycykiLGBTdWItcmVnaW9uIE5hbWVgKSksIA0KICAgICAgICBieS54PSJDT1VOVFJZX09GX0JJUlRIIiwgYnkueT0iQ291bnRyeSBvciBBcmVhIiwgYWxsLnggPSBUUlVFKQ0KDQoNCg0KDQpgYGANCg0KDQojIyMjIGNsZWFuIG1ldGFkYXRhIGVudGVyb3R5cGVzDQoNCmBgYHtyfQ0KDQoNCnZhcmlhYmxlX3RvX3JlbW92ZT0gYygiSEVJR0hUX0NNIiwgDQoiV0VJR0hUX0tHIiwNCiJTQU1QTEVfVFlQRSIsDQoiQk1JX0NBVCIsDQoiSE9TVF9TVUJKRUNUX0lEIiwNCiJBTk9OWU1JWkVEX05BTUUiLA0KIkFTU0lHTkVEX0ZST01fR0VPIiwNCiJCSVJUSF9ZRUFSIiwNCiJERVNDUklQVElPTiIsDQoiRE5BX0VYVFJBQ1RFRCIsDQoiSEVJR0hUX1VOSVRTIiwNCiJXRUlHSFRfVU5JVFMiLA0KIlNDSUVOVElGSUNfTkFNRSIsDQoiU1VSVkVZX0lEIiwNCiJUQVhPTl9JRCIsDQoiV0VJR0hUX1VOSVRTIiwNCiJWSU9TQ1JFRU5fU1RBVFVTIiwiVklPU0NSRUVOX1NVUlZFWUlEIiwiUFVCTElDIiwiVElUTEUiLCJHRU9fTE9DX05BTUUiKQ0KDQoNCg0KDQpoZWFsdGhfbWV0YWRhdGEgPSBjKCJCTUlfQ0FUIiwNCiJBTlRJQklPVElDX0hJU1RPUlkiICwNCiJBTFpIRUlNRVJTIiwNCiJBVVRPSU1NVU5FIiwNCiJDQU5DRVIiLA0KIkRJQUJFVEVTIiwNCiJJQkQiLA0KIklCUyIsDQoiS0lETkVZX0RJU0VBU0UiLA0KIkFDSURfUkVGTFVYIiwNCiJBTExFUkdJQ19UT19JX0hBVkVfTk9fRk9PRF9BTExFUkdJRVNfVEhBVF9JX0tOT1dfT0YiLA0KIkNBUkRJT1ZBU0NVTEFSX0RJU0VBU0UiLA0KIkNESUZGIiwNCiJERVBSRVNTSU9OX0JJUE9MQVJfU0NISVpPUEhSRU5JQSIsDQoiRVBJTEVQU1lfT1JfU0VJWlVSRV9ESVNPUkRFUiIsDQoiRlVOR0FMX09WRVJHUk9XVEgiLA0KIkdMVVRFTiIsDQoiTEFDVE9TRSIsDQoiTElWRVJfRElTRUFTRSIsDQoiTFVOR19ESVNFQVNFIiwNCiJNRU5UQUxfSUxMTkVTUyIsDQoiTUlHUkFJTkUiLA0KIlBLVSIsDQoiU0lCTyIsDQoiVEhZUk9JRCIpDQoNCmRpZXRfdmFyaWFibGVzID0NCiAgYygiVFlQRVNfT0ZfUExBTlRTIiwNCiAgIkRJRVRfVFlQRSIsDQogICJBTENPSE9MX0ZSRVFVRU5DWSIsDQogICJSRURfTUVBVF9GUkVRVUVOQ1kiLA0KICAiV0hPTEVfR1JBSU5fRlJFUVVFTkNZIiwNCiAgIlZFR0VUQUJMRV9GUkVRVUVOQ1kiLA0KICAiTUVBVF9FR0dTX0ZSRVFVRU5DWSIsDQogICJQUkVQQVJFRF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiRlJVSVRfRlJFUVVFTkNZIiwNCiAgIk9ORV9MSVRFUl9PRl9XQVRFUl9BX0RBWV9GUkVRVUVOQ1kiLA0KICAiU0VBRk9PRF9GUkVRVUVOQ1kiLA0KICAiSE9NRUNPT0tFRF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiSElHSF9GQVRfUkVEX01FQVRfRlJFUVVFTkNZIiwNCiAgIlJFQURZX1RPX0VBVF9NRUFMU19GUkVRVUVOQ1kiLA0KICAiU1VHQVJfU1dFRVRFTkVEX0RSSU5LX0ZSRVFVRU5DWSIsDQogICJTVUdBUllfU1dFRVRTX0ZSRVFVRU5DWSIsDQogICJTQUxURURfU05BQ0tTX0ZSRVFVRU5DWSIsDQogICJTUEVDSUFMSVpFRF9ESUVUX0ZPRE1BUCIsDQogICJTUEVDSUFMSVpFRF9ESUVUX0VYQ0xVREVfREFJUlkiLA0KICAiU1BFQ0lBTElaRURfRElFVF9FWENMVURFX05JR0hUU0hBREVTIiwNCiAgIlNQRUNJQUxJWkVEX0RJRVRfTU9ESUZJRURfUEFMRU9fRElFVCIsDQogICJTUEVDSUFMSVpFRF9ESUVUX1BBTEVPRElFVF9PUl9QUklNQUxfRElFVCIsDQogICJPTElWRV9PSUwiKQ0KDQoNCg0KbWV0YWRhdGEgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSwgY29udGFpbnMoIl9GUkVRVUVOQ1kiKSwgDQogICAgICAgICBUWVBFU19PRl9QTEFOVFMsIE9MSVZFX09JTCwgRElFVF9UWVBFLCANCiAgICAgICAgIGNvbnRhaW5zKCJTUEVDSUFMSVpFRF9ESUVUXyIpLA0KICAgICAgICAgYWxsX29mKGhlYWx0aF9tZXRhZGF0YSksIGNvbnRhaW5zKCJBTENPSE9MX1RZUEVTXyIpLCANCiAgICAgICAgIEFHRV9ZRUFSUywgU0VYLCBDT0xMRUNUSU9OX1NFQVNPTiwgYFN1Yi1yZWdpb24gTmFtZWApICU+JQ0KICBzZWxlY3QoLVNQRUNJQUxJWkVEX0RJRVRfV0VTVEVOUFJJQ0VfT1JfT1RIRVJfTE9XR1JBSU5fTE9XX1BST0NFU1NFRF9GTywgLUFMQ09IT0xfVFlQRVNfVU5TUEVDSUZJRUQpICU+JQ0KICBkcGx5cjo6cmVuYW1lKFJFR0lPTl9CSVJUSD1gU3ViLXJlZ2lvbiBOYW1lYCkgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkLnZhcnM9IlNBTVBMRV9OQU1FIikgJT4lIA0KICBmaWx0ZXIodmFsdWUhPSJMYWJDb250cm9sIHRlc3QiKSAlPiUNCiAgZmlsdGVyKHZhbHVlICE9ICJTZWxmLWRpYWdub3NlZCIpICU+JQ0KICBmaWx0ZXIodmFsdWUgIT0gIkRpYWdub3NlZCBieSBhbiBhbHRlcm5hdGl2ZSBtZWRpY2luZSBwcmFjdGl0aW9uZXIiKSAlPiUNCiAgbXV0YXRlKHZhbHVlID0gZm9yY2F0czo6ZmN0X3JlY29kZSh2YWx1ZSwgTmV2ZXIgPSAiTmV2ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJhcmVseSA9ICJSYXJlbHkgKGxlc3MgdGhhbiBvbmNlL3dlZWspIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSYXJlbHkgPSAiUmFyZWx5IChhIGZldyB0aW1lcy9tb250aCkiLCAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2NjYXNpb25hbGx5ID0gIk9jY2FzaW9uYWxseSAoMS0yIHRpbWVzL3dlZWspIiwgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlZ3VsYXJseSA9ICJSZWd1bGFybHkgKDMtNSB0aW1lcy93ZWVrKSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERhaWx5ID0gIkRhaWx5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZZXMgPSAidHJ1ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTm8gID0gImZhbHNlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZZXMgPSAiRGlhZ25vc2VkIGJ5IGEgbWVkaWNhbCBwcm9mZXNzaW9uYWwgKGRvY3RvciwgcGh5c2ljaWFuIGFzc2lzdGFudCkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vICA9ICJJIGRvIG5vdCBoYXZlIHRoaXMgY29uZGl0aW9uIiApKSAlPiUNCiAgbXV0YXRlKHZhbHVlID0gZm9yY2F0czo6ZmN0X2V4cGxpY2l0X25hKHZhbHVlLCAiTWlzc2luZyIpICkgJT4lDQogIGZpbHRlcighaXMubmEodmFsdWUpKSAlPiUNCiAgbXV0YXRlKHZhbHVlPSB2YWx1ZSAlPiUgYXMuY2hhcmFjdGVyKSAlPiUNCiAgcmVzaGFwZTI6OmRjYXN0KFNBTVBMRV9OQU1FfnZhcmlhYmxlLCB2YWx1ZS52YXIgPSAidmFsdWUiLCBmaWxsPSJNaXNzaW5nIikgJT4lDQogIG11dGF0ZShBR0VfWUVBUlMgPSBBR0VfWUVBUlMgJT4lIGFzLmNoYXJhY3RlcigpICU+JSBhcy5udW1lcmljKSAlPiUNCiAgbXV0YXRlKEJPV0VMX01PVkVNRU5UX0ZSRVFVRU5DWSA9IGZvcmNhdHM6OmZjdF9yZWxldmVsKEJPV0VMX01PVkVNRU5UX0ZSRVFVRU5DWSxyZWY9Ik9uZSIpKSAlPiUNCiAgbXV0YXRlKFJFR0lPTl9CSVJUSCAgICAgICAgICAgICA9IGZvcmNhdHM6OmZjdF9yZWxldmVsKFJFR0lPTl9CSVJUSCwgcmVmID0gIk5vcnRoZXJuIEFtZXJpY2EiKSkgJT4lDQogIG11dGF0ZShBTlRJQklPVElDX0hJU1RPUlkgICAgICAgPSBmb3JjYXRzOjpmY3RfcmVsZXZlbChBTlRJQklPVElDX0hJU1RPUlksIHJlZiA9ICJJIGhhdmUgbm90IHRha2VuIGFudGliaW90aWNzIGluIHRoZSBwYXN0IHllYXIuIikpICU+JQ0KICBtZXJnZShlbnRlcm90eXBlcyAlPiUgc2VsZWN0KHNhbXBsZV9uYW1lLCBFbnRlcm90eXBlc19pZCksIGJ5Lnk9InNhbXBsZV9uYW1lIiwgYnkueD0iU0FNUExFX05BTUUiKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gcGFzdGUwKCJtIixFbnRlcm90eXBlc19pZCkpICU+JSBzZWxlY3QoLVNBTVBMRV9OQU1FKSAtPiBtZXRhZGF0YV9lbnRlcm90eXBlcw0KICANCiAgDQogICAgICAgICAgIA0KbWV0YWRhdGFfZW50ZXJvdHlwZXMgJT4lIGRpbQ0KDQptZXRhZGF0YV9lbnRlcm90eXBlcyRFbnRlcm90eXBlc19pZCA9IGZvcmNhdHM6OmZjdF9yZWxldmVsKG1ldGFkYXRhX2VudGVyb3R5cGVzJEVudGVyb3R5cGVzX2lkLCByZWYgPSAibTEiKQ0KDQojVE8gRE8gOiBjb252ZXJ0IG9yZGluYWwgY2F0ZWdvcnkgdG8gbnVtZXJpYw0KDQoNCg0KICANCg0KDQoNCmBgYA0KDQpgYGB7cn0NCg0KDQptZXRhZGF0YV9lbnRlcm90eXBlcyAlPiUgDQogIGZpbHRlcihFbnRlcm90eXBlc19pZCA9PSJtMSIpICU+JQ0KICBzZWxlY3QoQk1JX0NBVCxBTlRJQklPVElDX0hJU1RPUlksVkVHRVRBQkxFX0ZSRVFVRU5DWSxSRUdJT05fQklSVEgsU0VYLCBBR0VfWUVBUlMpICU+JQ0KICBtdXRhdGUoQUdFXzYwID0gQUdFX1lFQVJTID4gNjApICU+JQ0KICBzZWxlY3QoLUFHRV9ZRUFSUykgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgYXMubWF0cml4KCkgJT4lDQogIHJlc2hhcGUyOjptZWx0KCkgJT4lDQogIGdyb3VwX2J5KFZhcjIsdmFsdWUpICU+JQ0KICBmaWx0ZXIodmFsdWUhPSJNaXNzaW5nIikgJT4lDQogIHN1bW1hcmlzZShuPW4oKSkgJT4lDQogIG11dGF0ZShmcmVxID0gbiAvIHN1bShuKSkgJT4lDQogIGZpbHRlcih2YWx1ZSAlaW4lIGMoIlRSVUUiLCJOb3JtYWwiLCJJIGhhdmUgbm90IHRha2VuIGFudGliaW90aWNzIGluIHRoZSBwYXN0IHllYXIuIiwiRGFpbHkiLCJOb3J0aGVybiBBbWVyaWNhIiwiZmVtYWxlIikpICU+JQ0KICBtdXRhdGUodHlwZT0icmVmIikgLT4gc21hbGxfc3VtbWFyeV9yZWZfc2V0DQogIA0KDQptZXRhZGF0YV9lbnRlcm90eXBlcyAlPiUgDQogICNmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgPT0ibTEiKSAlPiUNCiAgc2VsZWN0KEJNSV9DQVQsQU5USUJJT1RJQ19ISVNUT1JZLFZFR0VUQUJMRV9GUkVRVUVOQ1ksUkVHSU9OX0JJUlRILFNFWCwgQUdFX1lFQVJTKSAlPiUNCiAgbXV0YXRlKEFHRV82MCA9IEFHRV9ZRUFSUyA+IDYwKSAlPiUNCiAgc2VsZWN0KC1BR0VfWUVBUlMpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGFzLm1hdHJpeCgpICU+JQ0KICByZXNoYXBlMjo6bWVsdCgpICU+JQ0KICBncm91cF9ieShWYXIyLHZhbHVlKSAlPiUNCiAgZmlsdGVyKHZhbHVlIT0iTWlzc2luZyIpICU+JQ0KICBzdW1tYXJpc2Uobj1uKCkpICU+JQ0KICBtdXRhdGUoZnJlcSA9IG4gLyBzdW0obikpICU+JQ0KICBmaWx0ZXIodmFsdWUgJWluJSBjKCJUUlVFIiwiTm9ybWFsIiwiSSBoYXZlIG5vdCB0YWtlbiBhbnRpYmlvdGljcyBpbiB0aGUgcGFzdCB5ZWFyLiIsIkRhaWx5IiwiTm9ydGhlcm4gQW1lcmljYSIsImZlbWFsZSIpKSAlPiUNCiAgbXV0YXRlKHR5cGU9ImFsbCIpIA0KICANCiAgDQogIA0KICBtZXRhZGF0YV9lbnRlcm90eXBlcyAlPiUgDQogICNmaWx0ZXIoRW50ZXJvdHlwZXNfaWQgPT0ibTEiKSAlPiUNCiAgc2VsZWN0KEJNSV9DQVQsQU5USUJJT1RJQ19ISVNUT1JZLFZFR0VUQUJMRV9GUkVRVUVOQ1ksUkVHSU9OX0JJUlRILFNFWCwgQUdFX1lFQVJTKSAlPiUNCiAgbXV0YXRlKEFHRV82MCA9IEFHRV9ZRUFSUyA+IDYwKSAlPiUNCiAgc2VsZWN0KC1BR0VfWUVBUlMpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGFzLm1hdHJpeCgpICU+JQ0KICByZXNoYXBlMjo6bWVsdCgpICU+JQ0KICBncm91cF9ieShWYXIyLHZhbHVlKSAlPiUNCiAgZmlsdGVyKHZhbHVlIT0iTWlzc2luZyIpICU+JQ0KICBzdW1tYXJpc2Uobj1uKCkpICU+JQ0KICBtdXRhdGUoZnJlcSA9IG4gLyBzdW0obikpICU+JQ0KICBmaWx0ZXIodmFsdWUgJWluJSBjKCJUUlVFIiwiTm9ybWFsIiwiSSBoYXZlIG5vdCB0YWtlbiBhbnRpYmlvdGljcyBpbiB0aGUgcGFzdCB5ZWFyLiIsIkRhaWx5IiwiTm9ydGhlcm4gQW1lcmljYSIsImZlbWFsZSIpKSAlPiUNCiAgICBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh5PWZyZXEseD1WYXIyLCBmaWxsPSJhbGwgZGF0YXNldCIpLCBzdGF0PSJpZGVudGl0eSIpICsgY29vcmRfZmxpcCgpICsgc2NhbGVfeV9jb250aW51b3VzKCJQcmV2YWxlbmNlIixsYWJlbHM9c2NhbGVzOjpwZXJjZW50KSArDQogICAgc2NhbGVfeF9kaXNjcmV0ZSgiIixsYWJlbHM9YygiTm9ybWFsIEJNSVxuKDE4LjUgLSAyNC45KSIsIk5vIGFudGliaW90aWNcbmluIHRoZSBwYXN0IHllYXIiLCJEYWlseSB2ZWdldGFibGUiLCJOb3J0aGVybiBBbWVyaWNhIiwiRmVtYWxlIiwiQWdlID4gNjB5IiApKSArIA0KICAgIGdlb21fcG9pbnQoZGF0YT1zbWFsbF9zdW1tYXJ5X3JlZl9zZXQsIGFlcyh5PWZyZXEseD1WYXIyLCBjb2xvcj0icmVmIE0xIiksIHNpemU9NSkgKw0KICAgIGdlb21fc2VnbWVudChkYXRhPXNtYWxsX3N1bW1hcnlfcmVmX3NldCwgYWVzKHg9VmFyMiwgeGVuZD1WYXIyLCB5PTAsIHllbmQ9ZnJlcSkpICsNCiAgICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKyANCiAgICBzY2FsZV9jb2xvcl9tYW51YWwoIiIsIHZhbHVlcyA9ICJibGFjayIsIGxhYmVscz0iTTEgKHJlZikiKSArDQogICAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiIikgLT4gZmlnNEQNCg0KZmlnNEQNCg0KYGBgDQoNCg0KDQojIyMjIGNsZWFuIG1ldGFkYXRhIGVudGVyb3R5cGVzIG51bWVyaWNhbA0KDQpgYGB7cn0NCg0KcmFuZ2UwXzEgPSBmdW5jdGlvbih4KSB7KHgtbWluKHgsIG5hLnJtID0gVFJVRSkpLyhtYXgoeCwgbmEucm09IlRSVUUiKS1taW4oeCxuYS5ybSA9IFRSVUUpKX0NCg0KbWV0YWRhdGEgJT4lDQogIHNlbGVjdChTQU1QTEVfTkFNRSwgY29udGFpbnMoIl9GUkVRVUVOQ1kiKSwgDQogICAgICAgICBUWVBFU19PRl9QTEFOVFMsIE9MSVZFX09JTCwgRElFVF9UWVBFLCANCiAgICAgICAgIGNvbnRhaW5zKCJTUEVDSUFMSVpFRF9ESUVUXyIpLA0KICAgICAgICAgYWxsX29mKGhlYWx0aF9tZXRhZGF0YSksQk1JLCBjb250YWlucygiQUxDT0hPTF9UWVBFU18iKSwNCiAgICAgICAgIEFHRV9ZRUFSUywgU0VYLCBDT0xMRUNUSU9OX1NFQVNPTiwgYFN1Yi1yZWdpb24gTmFtZWApICU+JQ0KICBzZWxlY3QoLVNQRUNJQUxJWkVEX0RJRVRfV0VTVEVOUFJJQ0VfT1JfT1RIRVJfTE9XR1JBSU5fTE9XX1BST0NFU1NFRF9GTywgLUJNSV9DQVQsIC1BTENPSE9MX1RZUEVTX1VOU1BFQ0lGSUVEKSAlPiUNCiAgZHBseXI6OnJlbmFtZShSRUdJT05fQklSVEg9YFN1Yi1yZWdpb24gTmFtZWApICU+JSAjc2VsZWN0KC1TQU1QTEVfTkFNRSkgJT4lIGFwcGx5KDIsdGFibGUpDQogIHRpZHlleHQ6Om9uZWhvdCh2YXIgPSBjKCJSRUdJT05fQklSVEgiLCJHTFVURU4iLCJDT0xMRUNUSU9OX1NFQVNPTiIpKSAlPiUNCiAgc2VsZWN0KC1HTFVURU5fTm8pICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZC52YXJzPWMoIlNBTVBMRV9OQU1FIikpICU+JSANCiAgbXV0YXRlKHZhbHVlPSBpZmVsc2UodmFsdWUgJWluJSBjKCJMYWJDb250cm9sIHRlc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm90aGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWxmLWRpYWdub3NlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlhZ25vc2VkIGJ5IGFuIGFsdGVybmF0aXZlIG1lZGljaW5lIHByYWN0aXRpb25lciIpLE5BLHZhbHVlKSkgJT4lDQogIG11dGF0ZSh2YWx1ZSA9IGZvcmNhdHM6OmZjdF9yZWNvZGUodmFsdWUsICAgYDBgID0gIk5ldmVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMC4yNWAgPSAiUmFyZWx5IChsZXNzIHRoYW4gb25jZS93ZWVrKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDAuMjVgID0gIlJhcmVseSAoYSBmZXcgdGltZXMvbW9udGgpIiwgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAwLjVgID0gIk9jY2FzaW9uYWxseSAoMS0yIHRpbWVzL3dlZWspIiwgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAwLjc1YCA9ICJSZWd1bGFybHkgKDMtNSB0aW1lcy93ZWVrKSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAxYCA9ICJEYWlseSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDFgID0gInRydWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAwYCA9ICJmYWxzZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDFgID0gIlllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDBgID0gIk5vIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAiRGlhZ25vc2VkIGJ5IGEgbWVkaWNhbCBwcm9mZXNzaW9uYWwgKGRvY3RvciwgcGh5c2ljaWFuIGFzc2lzdGFudCkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAwYCA9ICJJIGRvIG5vdCBoYXZlIHRoaXMgY29uZGl0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMGAgPSAiZmVtYWxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAibWFsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDBgID0gIkkgaGF2ZSBub3QgdGFrZW4gYW50aWJpb3RpY3MgaW4gdGhlIHBhc3QgeWVhci4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAwLjI1YCA9ICJZZWFyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMC41YCA9ICI2IG1vbnRocyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDAuNzVgID0gIk1vbnRoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAiV2VlayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDBgID0gIkxlc3MgdGhhbiA1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMC4yNWAgPSAiNiB0byAxMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDAuNWAgPSAiMTEgdG8gMjAiLCAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDAuNzVgID0gIjIxIHRvIDMwIiwgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAxYCA9ICJNb3JlIHRoYW4gMzAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMGAgPSAiTGVzcyB0aGFuIG9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDAuMmAgPSAiT25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMC40YCA9ICJUd28iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAwLjZgID0gIlRocmVlIiwgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAwLjZgID0gIkZvdXIiLCAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDFgID0gIkZpdmUgb3IgbW9yZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDBgID0gIk9tbml2b3JlIiAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDAuMjVgID0gIk9tbml2b3JlIGJ1dCBkbyBub3QgZWF0IHJlZCBtZWF0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMC41YCA9ICJWZWdldGFyaWFuIGJ1dCBlYXQgc2VhZm9vZCIsICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMC43NWAgPSAiVmVnZXRhcmlhbiIsICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAiVmVnYW4iDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUNCiAgbXV0YXRlKHZhbHVlPSB2YWx1ZSAlPiUgYXMuY2hhcmFjdGVyICU+JSBhcy5udW1lcmljKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUodmFsdWUgPSBpZmVsc2UoaXMubmEodmFsdWUpLG1lYW4odmFsdWUsbmEucm0gPSBUUlVFKSx2YWx1ZSkpICU+JSAjc2xpY2Vfc2FtcGxlKHByb3A9MC4xKQ0KICByZXNoYXBlMjo6ZGNhc3QoU0FNUExFX05BTUV+dmFyaWFibGUsIHZhbHVlLnZhciA9ICJ2YWx1ZSIsIGZpbGw9Ik1pc3NpbmciKSAlPiUNCiAgbXV0YXRlKEFHRV9ZRUFSUyA9IEFHRV9ZRUFSUyAlPiUgYXMuY2hhcmFjdGVyKCkgJT4lIGFzLm51bWVyaWMgJT4lIHJhbmdlMF8xKCkgKSAlPiUNCiAgbXV0YXRlKEJNSSA9IEJNSSAlPiUgYXMuY2hhcmFjdGVyKCkgJT4lIGFzLm51bWVyaWMgJT4lIHJhbmdlMF8xKCkgKSAlPiUNCiAgI211dGF0ZShBR0VfWUVBUlMgPSBpZmVsc2UoaXMubmEoQUdFX1lFQVJTKSxtZWFuKEFHRV9ZRUFSUyxuYS5ybSA9IFRSVUUpLHZhbHVlKSkgJT4lDQogICNtdXRhdGUoUkVHSU9OX0JJUlRIICAgICAgICAgICAgID0gZm9yY2F0czo6ZmN0X3JlbGV2ZWwoUkVHSU9OX0JJUlRILCByZWYgPSAiTm9ydGhlcm4gQW1lcmljYSIpKSAlPiUNCiAgbWVyZ2UoZW50ZXJvdHlwZXMgJT4lIHNlbGVjdChzYW1wbGVfbmFtZSwgRW50ZXJvdHlwZXNfaWQpLCBieS55PSJzYW1wbGVfbmFtZSIsIGJ5Lng9IlNBTVBMRV9OQU1FIikgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IHBhc3RlMCgibSIsRW50ZXJvdHlwZXNfaWQpKSAlPiUgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoIlNBTVBMRV9OQU1FIikgLT4gbWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtDQoNCm1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUNCiAgc2VsZWN0KC1FbnRlcm90eXBlc19pZCkgJT4lDQogIG11dGF0ZV9hbGwoYXMubnVtZXJpYykgJT4lIGNvcihtZXRob2Q9InNwZWFybWFuIikgJT4lDQogIC5eMiAlPiUgc3FydCgpICU+JSBoZWF0bWFwDQogIA0KDQpzYXZlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSwgZmlsZT0iYWdwX21ldGFkYXRhX2VudGVyb3R5cGVzX251bS5yZGEiKQ0KIA0KDQpgYGANCiMjIyMgbWV0YWRhdGEgZW50ZXJvdHlwZXMgY29ycmVzcG9uZGFuY2UgYW5hbHlzaXMNCg0KDQpgYGB7cn0NCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JQ0KICBzZWxlY3QoLUVudGVyb3R5cGVzX2lkKSAlPiUNCiAgbXV0YXRlX2FsbChhcy5udW1lcmljKSAlPiUNCiAgYWRlNDo6ZHVkaS5wY2Eoc2Nhbm5mPUYsbmY9MzApIC0+IG1ldGFkYXRhX2VudGVyb3R5cGVzX251bV9wY2ENCg0KDQpjdW1zdW0obWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtX3BjYSRlaWcvc3VtKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bV9wY2EkZWlnKSkNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtX3BjYSRjbyAlPiUgLlsxOjMwXSAlPiUNCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oIm1ldGFkYXRhIikgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkLnZhcnM9Im1ldGFkYXRhIikgICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh4PW1ldGFkYXRhLHk9dmFsdWUpLCBzdGF0ID0gImlkZW50aXR5IikgKyANCiAgZmFjZXRfd3JhcCh+dmFyaWFibGUsIG5jb2wgPSAxMCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpDQoNCg0KDQptZXRhZGF0YV9lbnRlcm90eXBlc19udW1fcGNhJGNvICU+JSAuWzE6MzBdICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigibWV0YWRhdGEiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQudmFycz0ibWV0YWRhdGEiKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUodmFsdWVfdz1hYnModmFsdWUpKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUodmFsdWVfdG90ID0gc3VtKHZhbHVlX3cpKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUodmFsdWVfdz12YWx1ZV93L3ZhbHVlX3RvdCkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgbXV0YXRlKHZhbHVlX3RvdCA9IHN1bSh2YWx1ZV90b3QpKSAlPiUNCiAgYXJyYW5nZSh2YXJpYWJsZSxkZXNjKHZhbHVlX3cpKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUodmFsdWVfY3VtID0gY3Vtc3VtKHZhbHVlX3cpKSAlPiUNCiAgZmlsdGVyKHZhbHVlX2N1bSA8IDAuMjUpICU+JQ0KICBwdWxsKG1ldGFkYXRhKSAlPiUgdW5pcXVlKCkNCiANCm1ldGFkYXRhX2VudGVyb3R5cGVzX251bV9wY2EkY28gJT4lIC5bMTozMF0gJT4lDQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJtZXRhZGF0YSIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZC52YXJzPSJtZXRhZGF0YSIpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZSh2YWx1ZV93PWFicyh2YWx1ZSkpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZSh2YWx1ZV90b3QgPSBzdW0odmFsdWVfdykpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZSh2YWx1ZV93PXZhbHVlX3cvdmFsdWVfdG90KSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUodmFsdWVfdG90ID0gc3VtKHZhbHVlX3RvdCkpICU+JQ0KICBhcnJhbmdlKHZhcmlhYmxlLGRlc2ModmFsdWVfdykpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZSh2YWx1ZV9jdW0gPSBjdW1zdW0odmFsdWVfdykpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIHNsaWNlX21heChhYnModmFsdWUpLCBuID0gMikgJT4lDQogIHB1bGwobWV0YWRhdGEpICU+JSB1bmlxdWUoKQ0KDQoNCg0KDQogIG1ldGFkYXRhX2VudGVyb3R5cGVzX251bV9iY2E9IGFkZTQ6OmJjYShtZXRhZGF0YV9lbnRlcm90eXBlc19udW1fcGNhLCBmYWM9bWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtJEVudGVyb3R5cGVzX2lkICU+JSBhcy5jaGFyYWN0ZXIoKSAlPiUgYXMuZmFjdG9yKCksIHNjYW5uZj1GLCBuPTMwKSANCg0KICAjYWRlNDo6cmFuZHRlc3QobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtX2JjYSkNCiAgDQogIA0KICBtZXRhZGF0YV9lbnRlcm90eXBlc19udW1fYmNhJGNvICU+JQ0KICAgIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJtZXRhZGF0YSIpICU+JQ0KICByZXNoYXBlMjo6bWVsdChpZC52YXJzPSJtZXRhZGF0YSIpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZSh2YWx1ZV93PWFicyh2YWx1ZSkpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZSh2YWx1ZV90b3QgPSBzdW0odmFsdWVfdykpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZSh2YWx1ZV93PXZhbHVlX3cvdmFsdWVfdG90KSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUodmFsdWVfdG90ID0gc3VtKHZhbHVlX3RvdCkpICU+JQ0KICBhcnJhbmdlKHZhcmlhYmxlLGRlc2ModmFsdWVfdykpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZSh2YWx1ZV9jdW0gPSBjdW1zdW0odmFsdWVfdykpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIHNsaWNlX21heChhYnModmFsdWUpLCBuID0gNSkgJT4lDQogICNmaWx0ZXIodmFsdWVfY3VtIDwgMC4wNSkgJT4lICAgDQogICNmaWx0ZXIoYWJzKHZhbHVlKT4gMC4xKSAlPiUgIA0KICBwdWxsKG1ldGFkYXRhKSAlPiUgdW5pcXVlKCkNCiAgICANCiAgDQpkaW0obWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtKSAgDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCmNiaW5kKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSAlPiUNCiAgc2VsZWN0KC1ESUVUX1RZUEUsLUNPTExFQ1RJT05fU0VBU09OLC1SRUdJT05fQklSVEgsLUVudGVyb3R5cGVzX2lkLC1HTFVURU4pICU+JQ0KICBtdXRhdGVfYWxsKGFzLm51bWVyaWMpLA0KDQptZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lDQogIHNlbGVjdChESUVUX1RZUEUsQ09MTEVDVElPTl9TRUFTT04sUkVHSU9OX0JJUlRILEVudGVyb3R5cGVzX2lkLEdMVVRFTikgJT4lDQogIG11dGF0ZV9hbGwoYXMuY2hhcmFjdGVyKSAlPiUNCiAgbXV0YXRlX2FsbChmdW5jdGlvbih4KXtpZmVsc2UoaXMubmEoeCksIk1pc3NpbmciLHgpfSkgJT4lDQogIG11dGF0ZV9hbGwoYXMuZmFjdG9yKSkgJT4lDQogIHNlbGVjdCgtRW50ZXJvdHlwZXNfaWQpICU+JQ0KICBhZGU0OjpkdWRpLm1peChzY2FubmY9RkFMU0UsIG5mPTMyKSAtPiBtZXRhZGF0YV9lbnRlcm90eXBlc19jb2ENCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JQ0KICBzZWxlY3QoLURJRVRfVFlQRSwtQ09MTEVDVElPTl9TRUFTT04sLVJFR0lPTl9CSVJUSCwtRW50ZXJvdHlwZXNfaWQsLUdMVVRFTikgJT4lDQogIG11dGF0ZV9hbGwoYXMubnVtZXJpYykgJT4lDQogIGFkZTQ6OmR1ZGkubWl4KHNjYW5uZj1GQUxTRSwgbmY9MzApIC0+IG1ldGFkYXRhX2VudGVyb3R5cGVzX3BjYQ0KDQoNCmFkZTQ6OnNjYXR0ZXIobWV0YWRhdGFfZW50ZXJvdHlwZXNfY29hKQ0KDQoNCmN1bXN1bShtZXRhZGF0YV9lbnRlcm90eXBlc19jb2EkZWlnL3N1bShtZXRhZGF0YV9lbnRlcm90eXBlc19jb2EkZWlnKSkNCg0KYWRlNDo6cy5jb3JjaXJjbGUobWV0YWRhdGFfZW50ZXJvdHlwZXNfY29hJGNvKQ0KDQoNCm1ldGFkYXRhX2VudGVyb3R5cGVzX2NvYSRjbyAlPiUgLlsxOjRdICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigibWV0YWRhdGEiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQudmFycz0ibWV0YWRhdGEiKSAgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKHg9bWV0YWRhdGEseT12YWx1ZSksIHN0YXQgPSAiaWRlbnRpdHkiKSArIA0KICBmYWNldF93cmFwKH52YXJpYWJsZSwgbmNvbCA9IDQpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQ0KDQoNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfY29hJGxpICU+JQ0KICBjYmluZChtZXRhZGF0YV9lbnRlcm90eXBlc19udW0pICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHg9QXhpczEsIHk9QXhpczIsIGNvbD1FbnRlcm90eXBlc19pZCkpDQoNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfY29hJGNvICU+JSAuWzE6MzJdICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigibWV0YWRhdGEiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQudmFycz0ibWV0YWRhdGEiKSAgJT4lDQogIGZpbHRlcihhYnModmFsdWUpPjAuNSkNCg0KDQpjdW1zdW0obWV0YWRhdGFfZW50ZXJvdHlwZXNfcGNhJGVpZy9zdW0obWV0YWRhdGFfZW50ZXJvdHlwZXNfcGNhJGVpZykpDQoNCm1ldGFkYXRhX2VudGVyb3R5cGVzX3BjYSRjMSAlPiUgLlsxOjI0XSAlPiUNCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oIm1ldGFkYXRhIikgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkLnZhcnM9Im1ldGFkYXRhIikgICU+JQ0KICBtdXRhdGUodHlwZT1OQSkgJT4lDQogIG11dGF0ZSh0eXBlPWlmZWxzZShncmVwbCgiUkVHSU8iLCBtZXRhZGF0YSksIlJlZ2lvbiIsdHlwZSApKSAlPiUNCiAgbXV0YXRlKHR5cGU9aWZlbHNlKGdyZXBsKCJHTFVURSIsIG1ldGFkYXRhKSwiR2x1dGVuIix0eXBlICkpICU+JQ0KICBtdXRhdGUodHlwZT1pZmVsc2UoZ3JlcGwoIkNPTExFIiwgbWV0YWRhdGEpLCJDb2xsZWN0aW9uIix0eXBlICkpICU+JQ0KICBtdXRhdGUodHlwZT1pZmVsc2UoZ3JlcGwoIkRJRVQiLCBtZXRhZGF0YSksIkRpZXQiLHR5cGUgKSkgJT4lDQogIGZpbHRlcihpcy5uYSh0eXBlKSkgJT4lDQogIGZpbHRlcihhYnModmFsdWUpPjAuMjUpICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyh4PW1ldGFkYXRhLHk9dmFsdWUpLCBzdGF0ID0gImlkZW50aXR5IikgKyANCiAgZmFjZXRfd3JhcCh+dmFyaWFibGUsIG5jb2wgPSA2LCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpDQoNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfcGNhJGxpICU+JQ0KICBjYmluZChtZXRhZGF0YV9lbnRlcm90eXBlc19udW0pICU+JQ0KICBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHg9QXhpczEsIHk9QXhpczIsIGNvbD1FbnRlcm90eXBlc19pZCkpDQoNCm1ldGFkYXRhX2VudGVyb3R5cGVzX3BjYSRjMSAlPiUgLlsxOjIzXSAlPiUNCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oIm1ldGFkYXRhIikgJT4lDQogIHJlc2hhcGUyOjptZWx0KGlkLnZhcnM9Im1ldGFkYXRhIikgICU+JQ0KICBmaWx0ZXIoYWJzKHZhbHVlKT4wLjI1KQ0KDQoNCm1ldGFkYXRhX2VudGVyb3R5cGVzX2JjYSA9IGFkZTQ6OmJjYShtZXRhZGF0YV9lbnRlcm90eXBlc19jb2EsIGZhYz1hcy5mYWN0b3IobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtJEVudGVyb3R5cGVzX2lkKSwgbmY9MTgsIHNjYW5uZj1GQUxTRSkNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfYmNhX3JhbmR0ZXN0ID0gYWRlNDo6cmFuZHRlc3QobWV0YWRhdGFfZW50ZXJvdHlwZXNfYmNhKQ0KDQpjdW1zdW0obWV0YWRhdGFfZW50ZXJvdHlwZXNfYmNhJGVpZy9zdW0obWV0YWRhdGFfZW50ZXJvdHlwZXNfYmNhJGVpZykpDQoNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfYmNhJGMxICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigibWV0YWRhdGEiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQudmFycz0ibWV0YWRhdGEiKSAgJT4lDQogIG11dGF0ZSh0eXBlPU5BKSAlPiUNCiAgbXV0YXRlKHR5cGU9aWZlbHNlKGdyZXBsKCJSRUdJTyIsIG1ldGFkYXRhKSwiUmVnaW9uIix0eXBlICkpICU+JQ0KICBtdXRhdGUodHlwZT1pZmVsc2UoZ3JlcGwoIkdMVVRFIiwgbWV0YWRhdGEpLCJHbHV0ZW4iLHR5cGUgKSkgJT4lDQogIG11dGF0ZSh0eXBlPWlmZWxzZShncmVwbCgiQ09MTEUiLCBtZXRhZGF0YSksIkNvbGxlY3Rpb24iLHR5cGUgKSkgJT4lDQogIG11dGF0ZSh0eXBlPWlmZWxzZShncmVwbCgiRElFVCIsIG1ldGFkYXRhKSwiRGlldCIsdHlwZSApKSAlPiUNCiAgZmlsdGVyKGlzLm5hKHR5cGUpKSAlPiUNCiAgZmlsdGVyKGFicyh2YWx1ZSk+MC4yNSkgJT4lDQogIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKHg9bWV0YWRhdGEseT12YWx1ZSksIHN0YXQgPSAiaWRlbnRpdHkiKSArIA0KICBmYWNldF93cmFwKH52YXJpYWJsZSwgbmNvbCA9IDYsIHNjYWxlcyA9ICJmcmVlX3giKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfYmNhJGMxICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigibWV0YWRhdGEiKSAlPiUNCiAgcmVzaGFwZTI6Om1lbHQoaWQudmFycz0ibWV0YWRhdGEiKSAgJT4lDQogIG11dGF0ZSh0eXBlPU5BKSAlPiUNCiAgbXV0YXRlKHR5cGU9aWZlbHNlKGdyZXBsKCJSRUdJTyIsIG1ldGFkYXRhKSwiUmVnaW9uIix0eXBlICkpICU+JQ0KICBtdXRhdGUodHlwZT1pZmVsc2UoZ3JlcGwoIkdMVVRFIiwgbWV0YWRhdGEpLCJHbHV0ZW4iLHR5cGUgKSkgJT4lDQogIG11dGF0ZSh0eXBlPWlmZWxzZShncmVwbCgiQ09MTEUiLCBtZXRhZGF0YSksIkNvbGxlY3Rpb24iLHR5cGUgKSkgJT4lDQogIG11dGF0ZSh0eXBlPWlmZWxzZShncmVwbCgiRElFVCIsIG1ldGFkYXRhKSwiRGlldCIsdHlwZSApKSAlPiUNCiAgZmlsdGVyKCFpcy5uYSh0eXBlKSkgJT4lDQogIGZpbHRlcihhYnModmFsdWUpPjEpDQoNCmFkZTQ6OnMuY2xhc3MobWV0YWRhdGFfZW50ZXJvdHlwZXNfYmNhJGxzLCBmYWM9YXMuZmFjdG9yKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bSRFbnRlcm90eXBlc19pZCkpDQoNCmFkZTQ6OnMubGFiZWwobWV0YWRhdGFfZW50ZXJvdHlwZXNfYmNhJGxpKQ0KDQoNCg0KDQpgYGANCg0KDQoNCiMjIyMgYWxjb29sIHR5cGVzIGV4cGxvDQpgYGB7cn0NCg0KbGlicmFyeShVcFNldFIpDQoNCmFsY29ob2xfdHlwZXNfbGlzdCA9IGxpc3QoQkVFUkNJREVSICAgPSBtZXRhZGF0YSAlPiUgZmlsdGVyKEFMQ09IT0xfVFlQRVNfQkVFUkNJREVSID09ICJZZXMiKSAlPiUgcHVsbChTQU1QTEVfTkFNRSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIFNQSVJJVFNIQVJEID0gbWV0YWRhdGEgJT4lIGZpbHRlcihBTENPSE9MX1RZUEVTX1NQSVJJVFNIQVJEX0FMQ09IT0wgPT0gIlllcyIpICU+JSBwdWxsKFNBTVBMRV9OQU1FKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgUkVEX1dJTkUgICAgPSBtZXRhZGF0YSAlPiUgZmlsdGVyKEFMQ09IT0xfVFlQRVNfUkVEX1dJTkUgPT0gIlllcyIpICU+JSBwdWxsKFNBTVBMRV9OQU1FKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgU09VUl9CRUVSUyAgPSBtZXRhZGF0YSAlPiUgZmlsdGVyKEFMQ09IT0xfVFlQRVNfU09VUl9CRUVSUyA9PSAiWWVzIikgJT4lIHB1bGwoU0FNUExFX05BTUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBXSElURV9XSU5FICA9IG1ldGFkYXRhICU+JSBmaWx0ZXIoQUxDT0hPTF9UWVBFU19XSElURV9XSU5FID09ICJZZXMiKSAlPiUgcHVsbChTQU1QTEVfTkFNRSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIFVOU1BFQ0lGSUVEID0gbWV0YWRhdGEgJT4lIGZpbHRlcihBTENPSE9MX1RZUEVTX1VOU1BFQ0lGSUVEICA9PSAiWWVzIikgJT4lIHB1bGwoU0FNUExFX05BTUUpKQ0KDQp1cHNldChhbGNvaG9sX3R5cGVzX2xpc3QpDQoNCm1ldGFkYXRhICU+JQ0KICBzZWxlY3QoY29udGFpbnMoIkFMQ09IT0xfVFlQRVNfIiksIC1BTENPSE9MX1RZUEVTX1VOU1BFQ0lGSUVEKSAlPiUNCiAgbXV0YXRlX2FsbChmdW5jdGlvbih4KSBpZmVsc2UoeD09IlllcyIsMSwwKSkgJT4lIA0KdXBzZXQoZ3JvdXAuYnkgPSAic2V0cyIsY3V0b2ZmID0gMykNCg0KYGBgDQoNCg0KDQojIyMgYnVpbGQgbW9kZWwNCmBgYHtyfQ0KDQpsaWJyYXJ5KG5uZXQpDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkoYnJvb20uaGVscGVycykNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfdG1wID0gIA0KICBtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lDQogIG11dGF0ZShBTlRJQklPVElDX0hJU1RPUlkgPSBBTlRJQklPVElDX0hJU1RPUlkgJT4lIGFzLm51bWVyaWMsDQogICAgICAgICBCT1dFTF9NT1ZFTUVOVF9GUkVRVUVOQ1kgPSBCT1dFTF9NT1ZFTUVOVF9GUkVRVUVOQ1kgJT4lIGFzLm51bWVyaWMsDQogICAgICAgICBBR0VfWUVBUlMgPSBBR0VfWUVBUlMgJT4lIGFzLm51bWVyaWMsDQogICAgICAgICBTRVggPSBTRVggJT4lIGFzLm51bWVyaWMsDQogICAgICAgICBUWVBFU19PRl9QTEFOVFMgPSBUWVBFU19PRl9QTEFOVFMgJT4lIGFzLm51bWVyaWMsDQogICAgICAgICBWRUdFVEFCTEVfRlJFUVVFTkNZID0gVkVHRVRBQkxFX0ZSRVFVRU5DWSAlPiUgYXMubnVtZXJpYywNCiAgICAgICAgIElCRCA9IElCRCAlPiUgYXMubnVtZXJpYywNCiAgICAgICAgIEZST1pFTl9ERVNTRVJUX0ZSRVFVRU5DWSA9IEZST1pFTl9ERVNTRVJUX0ZSRVFVRU5DWSAlPiUgYXMubnVtZXJpYywNCiAgICAgICAgIFRFRVRIQlJVU0hJTkdfRlJFUVVFTkNZID0gVEVFVEhCUlVTSElOR19GUkVRVUVOQ1kgJT4lIGFzLm51bWVyaWMpICU+JQ0KICAjc2xpY2Vfc2FtcGxlKG4gPSA1MDAwLCByZXBsYWNlID0gRkFMU0UpICU+JQ0KICBuYS5vbWl0KCkNCiAgDQoNCg0KcmVnbSAgPC0gbXVsdGlub20oRW50ZXJvdHlwZXNfaWQgfiBBTlRJQklPVElDX0hJU1RPUlkgKyBCT1dFTF9NT1ZFTUVOVF9GUkVRVUVOQ1kgKyANCiAgICAgICAgICAgICAgICAgICAgQUdFX1lFQVJTICsgU0VYICsgVFlQRVNfT0ZfUExBTlRTICsgVkVHRVRBQkxFX0ZSRVFVRU5DWSArIA0KICAgICAgICAgICAgICAgICAgICBJQkQgKyBGUk9aRU5fREVTU0VSVF9GUkVRVUVOQ1kgKyAgVEVFVEhCUlVTSElOR19GUkVRVUVOQ1kgKyBSRUdJT05fQklSVEggKyBHTFVURU4gLCBkYXRhID0gbWV0YWRhdGFfZW50ZXJvdHlwZXNfdG1wKSAjTWF4Tld0cyA9IDEwMjYNCnJlZ20yIDwtIHN0ZXAocmVnbSkNCg0KDQpzYXZlKHJlZ20sIGZpbGU9InJlZ20ucmRhIikNCnNhdmUocmVnbTIsIGZpbGU9InJlZ20yLnJkYSIpDQoNCiNyZWdtMl9PUiAgIDwtIFJmYXN0OjpvZGRzLnJhdGlvKHJlZ20yKQ0KI3NhdmUocmVnbTJfT1IsIGZpbGU9InJlZ20yX09SLnJkYSIpDQoNCnJlZ20yX3RpZHkgPC0gdGlkeV9wbHVzX3BsdXMocmVnbTIsIGV4cG9uZW50aWF0ZSA9IFRSVUUpDQpyZWdtMl9wbG90IDwtIGdnY29lZl9tdWx0aW5vbShyZWdtMixleHBvbmVudGlhdGUgPSBUUlVFLCB0eXBlID0gImZhY2V0ZWQiKQ0KDQpzYXZlKHJlZ20yX3RpZHksIGZpbGU9InJlZ20yX3RpZHkucmRhIikNCnNhdmUocmVnbTJfcGxvdCwgZmlsZT0icmVnbTJfcGxvdC5yZGEiKQ0KDQoNCiNyZWdtMl9wbG90JGRhdGEgJT4lIGdnY29lZl9wbG90KGZhY2V0X2NvbD0ieS5sZXZlbCIsIGV4cG9uZW50aWF0ZSA9IFRSVUUpDQoNCg0KYGBgDQoNCg0KYGBge3J9DQpsaWJyYXJ5KG5uZXQpDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkoYnJvb20uaGVscGVycykNCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfdG1wID0gIA0KICBtZXRhZGF0YV9lbnRlcm90eXBlc19udW0gJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZCA9IEVudGVyb3R5cGVzX2lkICU+JSBmb3JjYXRzOjpmY3RfcmVsZXZlbChyZWYgPSAibTEiKSkgJT4lDQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGFzLm51bWVyaWMpICU+JQ0KICBuYS5vbWl0KCkNCiAgDQoNCg0KcmVnbSAgPC0gbXVsdGlub20oRW50ZXJvdHlwZXNfaWQgfiAuICwgZGF0YSA9IG1ldGFkYXRhX2VudGVyb3R5cGVzX3RtcCwgTWF4Tld0cyA9IDE5MzgpIA0KDQpyZWdtX3RpZHkgPC0gdGlkeV9wbHVzX3BsdXMocmVnbSwgZXhwb25lbnRpYXRlID0gVFJVRSkNCg0Kc2F2ZShyZWdtX3RpZHksIGZpbGU9InJlZ21fdGlkeS5yZGEiKQ0KDQojIHJlZ20yIDwtIHN0ZXAocmVnbSkNCiMgDQojIHNhdmUocmVnbSwgZmlsZT0icmVnbS5yZGEiKQ0KIyBzYXZlKHJlZ20yLCBmaWxlPSJyZWdtMi5yZGEiKQ0KIyANCiMgDQojIHJlZ20yX3RpZHkgPC0gdGlkeV9wbHVzX3BsdXMocmVnbTIsIGV4cG9uZW50aWF0ZSA9IFRSVUUpDQojIA0KIyBzYXZlKHJlZ20yX3RpZHksIGZpbGU9InJlZ20yX3RpZHkucmRhIikNCiMgDQojIA0KIyANCiMgZXhwKGNvZWYocmVnbSkpDQojIA0KIyBjdGFibGUgPC0gY29lZihzdW1tYXJ5KHJlZ20pKQ0KIyANCiMgcCA8LSBwbm9ybShhYnMoY3RhYmxlWywgInQgdmFsdWUiXSksIGxvd2VyLnRhaWwgPSBGQUxTRSkgKiAyDQojIGN0YWJsZSA8LSBjYmluZChjdGFibGUsICJwIHZhbHVlIiA9IHApDQoNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KYGBge3J9DQpzaGFubm9uX3BhdGggPSBzeXN0ZW0uZmlsZSgiZGF0YS1yYXcvcWlpbWUvZ2VuZXJhdGVkLWZpbGVzLTIwMTkwNTEyL2FscGhhL3NoYW5ub24ucXphIiwgcGFja2FnZSA9ICJndXR6aWxsYSIpDQoNCnNoYW5ub24gPSBxaWltZTJSOjpyZWFkX3F6YShzaGFubm9uX3BhdGgpJGRhdGEgJT4lIGFzLmRhdGEuZnJhbWUNCg0KZW50ZXJvdHlwZXMgPSByZWFkcjo6cmVhZF9jc3YyKCJlbnRlcm90eXBlc19wcmVkaWN0aW9uX291dGxpZXJzLmNzdiIpWywtMV0gJT4lIGZpbHRlcighaXMubmEoRW50ZXJvdHlwZXNfaWQpKQ0KDQoNCm1lcmdlKGVudGVyb3R5cGVzLHNoYW5ub24sYnkueD0ic2FtcGxlX25hbWUiLCBieS55PSJyb3cubmFtZXMiKSAlPiUNCiAgZ3JvdXBfYnkoRW50ZXJvdHlwZXNfaWQpICU+JQ0KICBzdW1tYXJpc2Uoc2hhbm5vbl9tZWRpYW49bWVkaWFuKHNoYW5ub24pKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkID0gcGFzdGUwKCJtIixFbnRlcm90eXBlc19pZCkpLT4gZW50ZXJvdHlwZXNfc2hhbm5vbl9tZWRpYW4NCmBgYA0KDQoNCmBgYHtyfQ0KY29lZihyZWdtKSAlPiUgDQogIHJlc2hhcGUyOjptZWx0KCkgJT4lIA0KICBmaWx0ZXIoVmFyMiAhPSAiKEludGVyY2VwdCkiKSAlPiUgDQogIG1lcmdlKGVudGVyb3R5cGVzX3NoYW5ub25fbWVkaWFuLCBieS54PSJWYXIxIiwgYnkueT0iRW50ZXJvdHlwZXNfaWQiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIikgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoVmFyMSAlaW4lIGMoIm0xOCIsIm0xNCIsIm0xNiIsIm0xNyIsIm03IiksICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoVmFyMSAlaW4lIGMoIm0xMSIsIm0xNSIsIm02IiwibTgiLCJtMTAiLCJtMyIsIm00IiwibTIiKSwgIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoVmFyMSAlaW4lIGMoIm0xMyIpLCAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKFZhcjEgPSBWYXIxICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihzaGFubm9uX21lZGlhbikpICU+JSANCiAgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyh4PVZhcjEseT0xMF52YWx1ZSwgY29sPWJyYW5jaCkpICsgc2NhbGVfeV9sb2cxMCgpICsgZmFjZXRfd3JhcCh+VmFyMiwgc2NhbGU9ImZyZWVfeSIpDQoNCg0KDQpyZWdtX3RpZHkgJT4lIA0KICBtZXJnZShlbnRlcm90eXBlc19zaGFubm9uX21lZGlhbiwgYnkueD0ieS5sZXZlbCIsIGJ5Lnk9IkVudGVyb3R5cGVzX2lkIikgJT4lDQogIG11dGF0ZShicmFuY2ggPSJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTgiLCJtMTQiLCJtMTYiLCJtMTciLCJtNyIpLCAiUHJldm90ZWxsYSBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTMiKSwgIkFra2VybWFuc2lhIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZSh5LmxldmVsID0geS5sZXZlbCAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoc2hhbm5vbl9tZWRpYW4pKSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyh4PXkubGV2ZWwseT1lc3RpbWF0ZSwgY29sPWJyYW5jaCwgYWxwaGE9cC52YWx1ZTwwLjA1KSkgKyBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nIikgKyBmYWNldF93cmFwKH50ZXJtLCBzY2FsZT0iZnJlZV95IikNCg0KDQpyZWdtX3RpZHkgJT4lIA0KICBtZXJnZShlbnRlcm90eXBlc19zaGFubm9uX21lZGlhbiwgYnkueD0ieS5sZXZlbCIsIGJ5Lnk9IkVudGVyb3R5cGVzX2lkIikgJT4lDQogIG11dGF0ZShicmFuY2ggPSJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTgiLCJtMTQiLCJtMTYiLCJtMTciLCJtNyIpLCAiUHJldm90ZWxsYSBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTMiKSwgIkFra2VybWFuc2lhIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZSh5LmxldmVsID0geS5sZXZlbCAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoc2hhbm5vbl9tZWRpYW4pKSAlPiUNCiAgZmlsdGVyKHAudmFsdWUgPCAwLjA1KSAlPiUNCiAgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyh4PXRlcm0seT1sb2coZXN0aW1hdGUpLCBjb2w9YnJhbmNoKSkgKyANCiAgI3NjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2ciKSArIA0KICBmYWNldF93cmFwKH55LmxldmVsLCBzY2FsZT0iZnJlZV94IiwgbnJvdz0yKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApDQoNCg0KYGBgDQoNCiMjIyBkYXRhIHZpeg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9DQoNCiMgcmVnbV90aWR5ICU+JSANCiMgICBtZXJnZShlbnRlcm90eXBlc19zaGFubm9uX21lZGlhbiwgYnkueD0ieS5sZXZlbCIsIGJ5Lnk9IkVudGVyb3R5cGVzX2lkIikgJT4lDQojICAgbXV0YXRlKGJyYW5jaCA9IkNsb3N0cmlkaWFsZXMgRE1NIHR5cGVzIikgJT4lDQojICAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTE4IiwibTE0IiwibTE2IiwibTE3IiwibTciKSwgIlByZXZvdGVsbGEgRE1NIHR5cGVzIixicmFuY2gpKSAlPiUNCiMgICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KIyAgIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoeS5sZXZlbCAlaW4lIGMoIm0xMyIpLCAiQWtrZXJtYW5zaWEgRE1NIHR5cGVzIixicmFuY2gpKSAlPiUNCiMgICBtdXRhdGUoZXN0aW1hdGUgPSBsb2coZXN0aW1hdGUpKSAlPiUNCiMgICAjbXV0YXRlKGVzdGltYXRlID0gaWZlbHNlKHAudmFsdWU+MC4wNSwwLGVzdGltYXRlKSkgJT4lDQojICAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KIyAgIG11dGF0ZShzPW1lYW4oYWJzKGVzdGltYXRlKSkpICU+JSANCiMgICBmaWx0ZXIocz4wKSAlPiUNCiMgICBtdXRhdGUoeS5sZXZlbCA9IHkubGV2ZWwgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHNoYW5ub25fbWVkaWFuKSkgJT4lDQojICAgbXV0YXRlKHZhcmlhYmxlID0gdmFyaWFibGUgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHMpKSAlPiUNCiMgICBnZ3Bsb3QoKSArIGdlb21fdGlsZShhZXMoeD15LmxldmVsLCB5PXZhcmlhYmxlLCBmaWxsPWVzdGltYXRlKSkgKyBzY2FsZV9maWxsX2dyYWRpZW50MigpICsgZmFjZXRfZ3JpZCgufmJyYW5jaCwgc2NhbGU9ImZyZWVfeCIsIHNwYWNlID0gImZyZWVfeCIpDQoNCmxvYWQoInJlZ21fdGlkeS5yZGEiKSAgDQogIA0KICByZWdtX3RpZHkgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlX2dyb3VwID0gImRpc2Vhc2UiKSAlPiUNCiAgICBtdXRhdGUodmFyaWFibGVfZ3JvdXAgPSANCiAgICAgICAgICAgICBjYXNlX3doZW4oZ3JlcGwoIkZSRVFVRU5DWSIsIHZhcmlhYmxlKSB+ICJEaWV0LCBkZW1vZ3JhcGhpYyBhbmQgbGlmZXN0eWxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkFMQ09IT0wiLCB2YXJpYWJsZSkgfiAiRGlldCwgZGVtb2dyYXBoaWMgYW5kIGxpZmVzdHlsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlICVpbiUgYygiQUdFX1lFQVJTIiwiU0VYIiwiRElFVF9UWVBFIiwiVFlQRVNfT0ZfUExBTlRTIikgfiAiRGlldCwgZGVtb2dyYXBoaWMgYW5kIGxpZmVzdHlsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJTUEVDSUFMSVpFRCIsIHZhcmlhYmxlKSB+IlNwZWNpYWxpemVkIERpZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiUkVHSU9OIiwgdmFyaWFibGUpIH4gIlJlZ2lvbiBvZiBCaXJ0aCIsDQogICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiSGVhbHRoIGFzc29jaWF0ZWQiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgJT4lDQogICAgbWVyZ2UoZW50ZXJvdHlwZXNfc2hhbm5vbl9tZWRpYW4sIGJ5Lng9InkubGV2ZWwiLCBieS55PSJFbnRlcm90eXBlc19pZCIpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0iQ2xvc3RyaWRpYWxlcyBETU0gcGFydGl0aW9ucyIpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTgiLCJtMTQiLCJtMTYiLCJtMTciLCJtNyIpLCAiUHJldm90ZWxsYSBETU0gcGFydGl0aW9ucyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoeS5sZXZlbCAlaW4lIGMoIm0xMSIsIm0xNSIsIm02IiwibTgiLCJtMTAiLCJtMyIsIm00IiwibTIiKSwgIkJhY3Rlcm9pZGVzIERNTSBwYXJ0aXRpb25zIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTEzIiksICJBa2suIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGVzdGltYXRlID0gbG9nKGVzdGltYXRlKSkgJT4lDQogIG11dGF0ZShlc3RpbWF0ZTIgPSBpZmVsc2UocC52YWx1ZT4wLjA1LDAsZXN0aW1hdGUpKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUocz1tZWFuKGFicyhlc3RpbWF0ZTIpKSkgJT4lIA0KICBmaWx0ZXIocz4wKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoeS5sZXZlbCA9IHkubGV2ZWwgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHNoYW5ub25fbWVkaWFuLCAuZGVzYyA9IEZBTFNFKSkgJT4lDQogIG11dGF0ZSh2YXJpYWJsZSA9IHZhcmlhYmxlICU+JSBhcy5jaGFyYWN0ZXIgJT4lIGFzLmZhY3RvcigpICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihzLCAuZGVzYyA9IEZBTFNFKSkgJT4lIA0KICBnZ3Bsb3QoKSArIA0KICAgIGdlb21fdGlsZShhZXMoeD15LmxldmVsLCB5PXZhcmlhYmxlLCBmaWxsPWVzdGltYXRlKSkgKyANCiAgICBnZW9tX3BvaW50KGFlcyh4PXkubGV2ZWwsIHk9dmFyaWFibGUsIGFscGhhPXAudmFsdWU8MC4wNSkpICsgDQogICAgc2NhbGVfZmlsbF9ncmFkaWVudDIoIkxvZyBPUiIsIGxvdz1zY2FsZXM6Om11dGVkKCJibHVlIiksIG1pZD0id2hpdGUiLCBoaWdoPXNjYWxlczo6bXV0ZWQoInJlZCIpKSArDQogICAgZmFjZXRfZ3JpZCh2YXJpYWJsZV9ncm91cH5icmFuY2gsIHNjYWxlPSJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsgDQogICAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkpICsNCiAgeWxhYigiTWljcm9iaW9tZSBwYXJ0aXRpb25cbm9yZGVyZWQgYnkgYnJhbmNoIGFuZCBieSBhbHBoYS1kaXZlcnNpdHkiKSArIHlsYWIoIkFHUCBxdWVzdGlvbm5haXJlIHZhcmlhYmxlIikgLT4gZmlnNEENCiAgICBmaWc0QQ0KICBnZ3NhdmUoInBhcnRpdGlvbnNfbXVsdGlub21pYWxfbG9nT1IucGRmIiwgaGVpZ2h0ID0gMTIsIHdpZHRoID0gMTQpDQogIA0KICANCiAgIyByZXNoYXBlMjo6ZGNhc3QoeS5sZXZlbH52YXJpYWJsZSwgdmFsdWUudmFyID0gImVzdGltYXRlIikgJT4lDQogICMgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoInkubGV2ZWwiKSAlPiUNCiAgIyBhcy5tYXRyaXgoKSAlPiUNCiAgIyB0KCkgJT4lDQogICMgaGVhdG1hcChzY2FsZSA9ICJub25lIiwgY29sID0gY20uY29sb3JzKDI1NikpDQoNCiAgDQpyZWdtX3RpZHkgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlX2dyb3VwID0gImRpc2Vhc2UiKSAlPiUNCiAgICBtdXRhdGUodmFyaWFibGVfZ3JvdXAgPSANCiAgICAgICAgICAgICBjYXNlX3doZW4oZ3JlcGwoIkZSRVFVRU5DWSIsIHZhcmlhYmxlKSB+ICJEaWV0LCBkZW1vZ3JhcGhpYyBhbmQgbGlmZXN0eWxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkFMQ09IT0wiLCB2YXJpYWJsZSkgfiAiRGlldCwgZGVtb2dyYXBoaWMgYW5kIGxpZmVzdHlsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlICVpbiUgYygiQUdFX1lFQVJTIiwiU0VYIiwiRElFVF9UWVBFIiwiVFlQRVNfT0ZfUExBTlRTIikgfiAiRGlldCwgZGVtb2dyYXBoaWMgYW5kIGxpZmVzdHlsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJTUEVDSUFMSVpFRCIsIHZhcmlhYmxlKSB+IlNwZWNpYWxpemVkIERpZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiUkVHSU9OIiwgdmFyaWFibGUpIH4gIlJlZ2lvbiBvZiBCaXJ0aCIsDQogICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiSGVhbHRoIGFzc29jaWF0ZWQiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgJT4lDQogICAgbWVyZ2UoZW50ZXJvdHlwZXNfc2hhbm5vbl9tZWRpYW4sIGJ5Lng9InkubGV2ZWwiLCBieS55PSJFbnRlcm90eXBlc19pZCIpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0iQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTE4IiwibTE0IiwibTE2IiwibTE3IiwibTciKSwgIlByZXZvdGVsbGEgRE1NIHR5cGVzIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTExIiwibTE1IiwibTYiLCJtOCIsIm0xMCIsIm0zIiwibTQiLCJtMiIpLCAiQmFjdGVyb2lkZXMgRE1NIHR5cGVzIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTEzIiksICJBa2suIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGVzdGltYXRlID0gbG9nKGVzdGltYXRlKSkgJT4lDQogIG11dGF0ZShlc3RpbWF0ZTIgPSBpZmVsc2UocC52YWx1ZT4wLjA1LDAsZXN0aW1hdGUpKSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBtdXRhdGUocz1tZWFuKGFicyhlc3RpbWF0ZTIpKSkgJT4lIA0KICBmaWx0ZXIocz4wKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoeS5sZXZlbCA9IHkubGV2ZWwgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHNoYW5ub25fbWVkaWFuLCAuZGVzYyA9IEZBTFNFKSkgJT4lDQogIG11dGF0ZSh2YXJpYWJsZSA9IHZhcmlhYmxlICU+JSBhcy5jaGFyYWN0ZXIgJT4lIGFzLmZhY3RvcigpICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihzLCAuZGVzYyA9IEZBTFNFKSkgJT4lICANCiAgZ3JvdXBfYnkodmFyaWFibGUsdmFyaWFibGVfZ3JvdXAsYnJhbmNoKSAlPiUNCiAgc3VtbWFyaXNlKGVzdGltYXRlPXN1bShhYnMoZXN0aW1hdGUyKSkpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fYmFyKGFlcyh4PXZhcmlhYmxlLHk9ZXN0aW1hdGUsZmlsbD1icmFuY2gpLCBzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKw0KICBmYWNldF9ncmlkKHZhcmlhYmxlX2dyb3Vwfi4sIHNjYWxlPSJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsgY29vcmRfZmxpcCgpICsgc2NhbGVfZmlsbF9icmV3ZXIodHlwZT0icXVhbCIpICsNCiAgeGxhYigiIikgKyB5bGFiKCJhYnNvbHV0ZSBjdW1tdWxhdGVkIExvZyBPUiIpICsNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpKSAtPiBmaWc0Qg0KICANCg0KDQoNCg0KDQogcmVnbV90aWR5ICU+JQ0KICAgIG11dGF0ZSh2YXJpYWJsZV9ncm91cCA9ICJkaXNlYXNlIikgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlX2dyb3VwID0gDQogICAgICAgICAgICAgY2FzZV93aGVuKGdyZXBsKCJGUkVRVUVOQ1kiLCB2YXJpYWJsZSkgfiAiRGlldCwgZGVtb2dyYXBoaWMgYW5kIGxpZmVzdHlsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJBTENPSE9MIiwgdmFyaWFibGUpIH4gIkRpZXQsIGRlbW9ncmFwaGljIGFuZCBsaWZlc3R5bGUiLA0KICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSAlaW4lIGMoIkFHRV9ZRUFSUyIsIlNFWCIsIkRJRVRfVFlQRSIsIlRZUEVTX09GX1BMQU5UUyIpIH4gIkRpZXQsIGRlbW9ncmFwaGljIGFuZCBsaWZlc3R5bGUiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiU1BFQ0lBTElaRUQiLCB2YXJpYWJsZSkgfiJTcGVjaWFsaXplZCBEaWV0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIlJFR0lPTiIsIHZhcmlhYmxlKSB+ICJSZWdpb24gb2YgQmlydGgiLA0KICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkhlYWx0aCBhc3NvY2lhdGVkIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICU+JQ0KICAgIG1lcmdlKGVudGVyb3R5cGVzX3NoYW5ub25fbWVkaWFuLCBieS54PSJ5LmxldmVsIiwgYnkueT0iRW50ZXJvdHlwZXNfaWQiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IkNsb3N0cmlkaWFsZXMgRE1NIHBhcnRpdGlvbnMiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTE4IiwibTE0IiwibTE2IiwibTE3IiwibTciKSwgIlByZXZvdGVsbGEgRE1NIHBhcnRpdGlvbnMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gcGFydGl0aW9ucyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoeS5sZXZlbCAlaW4lIGMoIm0xMyIpLCAiQWtrLiIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShlc3RpbWF0ZSA9IGxvZyhlc3RpbWF0ZSkpICU+JQ0KICBtdXRhdGUoZXN0aW1hdGUyID0gaWZlbHNlKHAudmFsdWU+MC4wNSwwLGVzdGltYXRlKSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgbXV0YXRlKHM9bWVhbihhYnMoZXN0aW1hdGUyKSkpICU+JSANCiAgZmlsdGVyKHM+MCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKHkubGV2ZWwgPSB5LmxldmVsICU+JSBmb3JjYXRzOjpmY3RfcmVvcmRlcihzaGFubm9uX21lZGlhbiwgLmRlc2MgPSBGQUxTRSkpICU+JQ0KICBtdXRhdGUodmFyaWFibGUgPSB2YXJpYWJsZSAlPiUgYXMuY2hhcmFjdGVyICU+JSBhcy5mYWN0b3IoKSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocywgLmRlc2MgPSBGQUxTRSkpICU+JSAgDQogIGdyb3VwX2J5KHkubGV2ZWwsIHZhcmlhYmxlX2dyb3VwLCBicmFuY2gpICU+JQ0KICBzdW1tYXJpc2UoZXN0aW1hdGU9c3VtKGFicyhlc3RpbWF0ZTIpKSkgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9iYXIoYWVzKHg9eS5sZXZlbCx5PWVzdGltYXRlLGZpbGw9dmFyaWFibGVfZ3JvdXApLCBzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKw0KICBmYWNldF9ncmlkKC5+YnJhbmNoLCBzY2FsZT0iZnJlZSIsIHNwYWNlID0gImZyZWUiKSArIHNjYWxlX2ZpbGxfYnJld2VyKCIiLHR5cGU9InF1YWwiLCBwYWxldHRlID0gIlNldDIiKSArDQogIHhsYWIoIiIpICsgeWxhYigiYWJzb2x1dGUgY3VtbXVsYXRlZCBMb2cgT1IiKSArIA0KICAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpIC0+IGZpZzRDDQoNCmBgYA0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTUsIGZpZy53aWR0aD0yNX0NCg0KcF9jdXRfb2ZmPTAuMTANCg0KICByZWdtX3RpZHkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUgbXV0YXRlKHAudmFsdWUgPSBwLmFkanVzdChwLnZhbHVlLCBtZXRob2Q9ImZkciIpKSAlPiUNCiAgICBtdXRhdGUodmFyaWFibGVfZ3JvdXAgPSAiZGlzZWFzZSIpICU+JQ0KICAgbXV0YXRlKHZhcmlhYmxlX2dyb3VwID0gDQogICAgICAgICAgICAgY2FzZV93aGVuKHZhcmlhYmxlICVpbiUgYygiQUdFX1lFQVJTIiwiU0VYIiwiQk1JIiwiQk9XRUxfTU9WRU1FTlRfRlJFUVVFTkNZIikgfiAiSW50cmluc2ljXG5Ib3N0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIk1FQUxTIiwgdmFyaWFibGUpIH4gIkxpZmVzdHlsZVxuJiBoeWdpZW5lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUgJWluJSBjKCJFWEVSQ0lTRV9GUkVRVUVOQ1kiLCJQT09MX0ZSRVFVRU5DWSIsIkNPU01FVElDU19GUkVRVUVOQ1kiLCJQUkVQQVJFRF9NRUFMU19GUkVRVUVOQ1kiLCJURUVUSEJSVVNISU5HX0ZSRVFVRU5DWSIsIlNNT0tJTkdfRlJFUVVFTkNZIikgfiAiTGlmZXN0eWxlXG4mIGh5Z2llbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiRlJFUVVFTkNZIiwgdmFyaWFibGUpIH4gIkRpZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiQUxDT0hPTCIsIHZhcmlhYmxlKSB+ICJEaWV0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUgJWluJSBjKCJESUVUX1RZUEUiLCJUWVBFU19PRl9QTEFOVFMiKSB+ICJEaWV0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIlNQRUNJQUxJWkVEIiwgdmFyaWFibGUpIH4iU3BlY2lhbGl6ZWRcbkRpZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiUkVHSU9OIiwgdmFyaWFibGUpIH4gIlJlZ2lvbiBvZlxuQmlydGgiLA0KICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lZGljYWwgaGlzdG9yeSINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUNCiAgICBtZXJnZShlbnRlcm90eXBlc19zaGFubm9uX21lZGlhbiwgYnkueD0ieS5sZXZlbCIsIGJ5Lnk9IkVudGVyb3R5cGVzX2lkIikgJT4lDQogIG11dGF0ZShicmFuY2ggPSJDbG9zdHJpZGlhbGVzIERNTSBwYXJ0aXRpb25zIikgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoeS5sZXZlbCAlaW4lIGMoIm0xOCIsIm0xNCIsIm0xNiIsIm0xNyIsIm03IiksICJQcmV2b3RlbGxhIERNTSBwYXJ0aXRpb25zIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTExIiwibTE1IiwibTYiLCJtOCIsIm0xMCIsIm0zIiwibTQiLCJtMiIpLCAiQmFjdGVyb2lkZXMgRE1NIHBhcnRpdGlvbnMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTMiKSwgIkFray4iLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoZXN0aW1hdGUgPSBsb2coZXN0aW1hdGUpKSAlPiUNCiAgbXV0YXRlKGVzdGltYXRlMiA9IGlmZWxzZShwLnZhbHVlPnBfY3V0X29mZiwwLGVzdGltYXRlKSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgbXV0YXRlKHM9bWVhbihhYnMoZXN0aW1hdGUyKSkpICU+JSANCiAgZmlsdGVyKHM+MCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKHkubGV2ZWwgPSB5LmxldmVsICU+JSBzdHJpbmdyOjpzdHJfdG9fdXBwZXIoKSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoc2hhbm5vbl9tZWRpYW4sIC5kZXNjID0gVFJVRSkpICU+JQ0KICANCiAgbXV0YXRlKGJyYW5jaCA9IGJyYW5jaCAlPiUgZ3N1YigiRE1NIHR5cGVzIiwgIlxuRE1NIHR5cGVzIiwuKSkgJT4lICNwdWxsKHZhcmlhYmxlKSAlPiUgZ3JlcCgiQ09MTCIsLikNCiAgZmlsdGVyKCEodmFyaWFibGUgJWluJSBncmVwKCJDT0xMIiwgdmFyaWFibGUsIHZhbHVlID0gVFJVRSkgKSkgJT4lDQogIA0KICBtdXRhdGUodmFyaWFibGUgPSBnc3ViKCJfRlJFUVVFTkNZfFNQRUNJQUxJWkVEX0RJRVRffEFMQ09IT0xfVFlQRVNffFJFR0lPTl9CSVJUSF8iLCIiLCB2YXJpYWJsZSkpICU+JQ0KICBtdXRhdGUodmFyaWFibGUgPSANCiAgICAgICAgICAgY2FzZV93aGVuKGdyZXBsKCJOT19GT09EIiwgdmFyaWFibGUpfiJObyBmb29kIGFsbGVyZ3kiLA0KICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm5vdC5lYXQuZ2x1dGVuIiwgdmFyaWFibGUpfiJHbHV0ZW4gaW50b2xlcmFuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoImdsdXRlbi5JZ0ciLCB2YXJpYWJsZSl+IkdsdXRlbiBhbGxlcmd5IChJZ0cpIiwNCiAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJXRVNURU5QUklDRSIsIHZhcmlhYmxlKX4iTG93IHByb2Nlc3NlZCIsDQogICAgICAgICAgICAgICAgICAgICBncmVwbCgiT1RIRVJfUkVTVFJJQ1RJT05TIiwgdmFyaWFibGUpfiJPdGhlciByZXN0cmljdGlvbnMiLA0KICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIlNFWCIsIHZhcmlhYmxlKX4iU2V4IChtYWxlKSIsDQogICAgICAgICAgICAgICAgICAgICBUUlVFIH4gdmFyaWFibGUpKSAlPiUNCiAgbXV0YXRlKHZhcmlhYmxlID0gZ3N1YigiX3xcXC4iLCIgIiwgdmFyaWFibGUpKSAlPiUNCiAgbXV0YXRlKHZhcmlhYmxlID0gdmFyaWFibGUgJT4lIGFzLmNoYXJhY3RlciAlPiUgYXMuZmFjdG9yKCkgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHMsIC5kZXNjID0gVFJVRSkpICU+JSANCiAgICAgbXV0YXRlKGJyYW5jaCA9IGJyYW5jaCAlPiUgZ3N1YigiRE1NIHBhcnRpdGlvbnMiLCAiXG5ETU0gcGFydGl0aW9ucyIsLikpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICAgIGdlb21fdGlsZShhZXMoeT15LmxldmVsLCB4PXZhcmlhYmxlLCBmaWxsPWVzdGltYXRlKSkgKyANCiAgICBnZW9tX3BvaW50KGFlcyh5PXkubGV2ZWwsIHg9dmFyaWFibGUsIGFscGhhPXAudmFsdWU8cF9jdXRfb2ZmKSkgKyANCiAgICBzY2FsZV9maWxsX2dyYWRpZW50MigiTG9nIE9SIiwgbG93PXNjYWxlczo6bXV0ZWQoImJsdWUiKSwgbWlkPSJ3aGl0ZSIsIGhpZ2g9c2NhbGVzOjptdXRlZCgicmVkIikpICsNCiAgICBmYWNldF9ncmlkKGJyYW5jaH52YXJpYWJsZV9ncm91cCwgc2NhbGU9ImZyZWUiLCBzcGFjZSA9ICJmcmVlIikgKyANCiAgICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICAgIHNjYWxlX2FscGhhX2Rpc2NyZXRlKCJGRFIgPCAxMCUiKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArDQogICAgeWxhYigiTWljcm9iaW9tZSBwYXJ0aXRpb25cbm9yZGVyZWQgYnkgYnJhbmNoIGFuZCBieSBhbHBoYS1kaXZlcnNpdHkiKSArIHhsYWIoIkFHUCBxdWVzdGlvbm5haXJlIGRhdGEiKSAtPiBmaWc0QQ0KICAgIGZpZzRBDQogICNnZ3NhdmUoInBhcnRpdGlvbnNfbXVsdGlub21pYWxfbG9nT1IucGRmIiwgaGVpZ2h0ID0gMTIsIHdpZHRoID0gMTQpDQogIA0KICANCiANCg0KICANCnJlZ21fdGlkeSAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JSBtdXRhdGUocC52YWx1ZSA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIikpICU+JQ0KICAgIG11dGF0ZSh2YXJpYWJsZV9ncm91cCA9ICJkaXNlYXNlIikgJT4lDQogICBtdXRhdGUodmFyaWFibGVfZ3JvdXAgPSANCiAgICAgICAgICAgICBjYXNlX3doZW4odmFyaWFibGUgJWluJSBjKCJBR0VfWUVBUlMiLCJTRVgiLCJCTUkiLCJCT1dFTF9NT1ZFTUVOVF9GUkVRVUVOQ1kiKSB+ICJJbnRyaW5zaWNcbkhvc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiTUVBTFMiLCB2YXJpYWJsZSkgfiAiTGlmZXN0eWxlXG4mIGh5Z2llbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSAlaW4lIGMoIkVYRVJDSVNFX0ZSRVFVRU5DWSIsIlBPT0xfRlJFUVVFTkNZIiwiQ09TTUVUSUNTX0ZSRVFVRU5DWSIsIlBSRVBBUkVEX01FQUxTX0ZSRVFVRU5DWSIsIlRFRVRIQlJVU0hJTkdfRlJFUVVFTkNZIiwiU01PS0lOR19GUkVRVUVOQ1kiKSB+ICJMaWZlc3R5bGVcbiYgaHlnaWVuZSIsDQogICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJGUkVRVUVOQ1kiLCB2YXJpYWJsZSkgfiAiRGlldCIsDQogICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJBTENPSE9MIiwgdmFyaWFibGUpIH4gIkRpZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSAlaW4lIGMoIkRJRVRfVFlQRSIsIlRZUEVTX09GX1BMQU5UUyIpIH4gIkRpZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiU1BFQ0lBTElaRUQiLCB2YXJpYWJsZSkgfiJTcGVjaWFsaXplZFxuRGlldCIsDQogICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJSRUdJT04iLCB2YXJpYWJsZSkgfiAiUmVnaW9uIG9mXG5CaXJ0aCIsDQogICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTWVkaWNhbCBoaXN0b3J5Ig0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICU+JQ0KICAgIG1lcmdlKGVudGVyb3R5cGVzX3NoYW5ub25fbWVkaWFuLCBieS54PSJ5LmxldmVsIiwgYnkueT0iRW50ZXJvdHlwZXNfaWQiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IkNsb3N0cmlkaWFsZXMgRE1NIHBhcnRpdGlvbnMiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTE4IiwibTE0IiwibTE2IiwibTE3IiwibTciKSwgIlByZXZvdGVsbGEgRE1NIHBhcnRpdGlvbnMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gcGFydGl0aW9ucyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoeS5sZXZlbCAlaW4lIGMoIm0xMyIpLCAiQWtrLiIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShlc3RpbWF0ZSA9IGxvZyhlc3RpbWF0ZSkpICU+JQ0KICBtdXRhdGUoZXN0aW1hdGUyID0gaWZlbHNlKHAudmFsdWU+cF9jdXRfb2ZmLDAsZXN0aW1hdGUpKSAlPiUNCiAgI211dGF0ZShlc3RpbWF0ZTIgPSBlc3RpbWF0ZSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgbXV0YXRlKHM9bWVhbihhYnMoZXN0aW1hdGUyKSkpICU+JSANCiAgZmlsdGVyKHM+MCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKHkubGV2ZWwgPSB5LmxldmVsICU+JSBzdHJpbmdyOjpzdHJfdG9fdXBwZXIoKSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoc2hhbm5vbl9tZWRpYW4sIC5kZXNjID0gVFJVRSkpICU+JQ0KICBtdXRhdGUodmFyaWFibGUgPSB2YXJpYWJsZSAlPiUgYXMuY2hhcmFjdGVyICU+JSBhcy5mYWN0b3IoKSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocywgLmRlc2MgPSBUUlVFKSkgJT4lICANCiAgbXV0YXRlKGJyYW5jaCA9IGJyYW5jaCAlPiUgZ3N1YigiRE1NIHR5cGVzIiwgIlxuRE1NIHR5cGVzIiwuKSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlLHZhcmlhYmxlX2dyb3VwLGJyYW5jaCkgJT4lDQogIHN1bW1hcmlzZShlc3RpbWF0ZT1zdW0oYWJzKGVzdGltYXRlMikpKSAlPiUNCiAgIGZpbHRlcighKHZhcmlhYmxlICVpbiUgZ3JlcCgiQ09MTCIsIHZhcmlhYmxlLCB2YWx1ZSA9IFRSVUUpICkpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fYmFyKGFlcyh5PXZhcmlhYmxlLHg9ZXN0aW1hdGUsZmlsbD1icmFuY2gpLCBzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKw0KICBmYWNldF9ncmlkKC5+dmFyaWFibGVfZ3JvdXAsIHNjYWxlPSJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsgY29vcmRfZmxpcCgpICsgc2NhbGVfZmlsbF9icmV3ZXIodHlwZT0icXVhbCIpICsNCiAgDQogIHlsYWIoIiIpICsgeGxhYigiYWJzb2x1dGVkIGN1bW11bGF0ZWRcbm1vZGVsIHdlaWdodHMiKSArDQoNCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKSAtPiBmaWc0Qg0KICANCg0KDQoNCg0KDQogcmVnbV90aWR5ICU+JQ0KICAgZ3JvdXBfYnkodmFyaWFibGUpICU+JSBtdXRhdGUocC52YWx1ZSA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIikpICU+JQ0KICAgIG11dGF0ZSh2YXJpYWJsZV9ncm91cCA9ICJkaXNlYXNlIikgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlX2dyb3VwID0gDQogICAgICAgICAgICAgY2FzZV93aGVuKHZhcmlhYmxlICVpbiUgYygiQUdFX1lFQVJTIiwiU0VYIiwiQk1JIiwiQk9XRUxfTU9WRU1FTlRfRlJFUVVFTkNZIikgfiAiSW50cmluc2ljXG5Ib3N0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIk1FQUxTIiwgdmFyaWFibGUpIH4gIkxpZmVzdHlsZVxuJiBoeWdpZW5lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUgJWluJSBjKCJFWEVSQ0lTRV9GUkVRVUVOQ1kiLCJQT09MX0ZSRVFVRU5DWSIsIkNPU01FVElDU19GUkVRVUVOQ1kiLCJQUkVQQVJFRF9NRUFMU19GUkVRVUVOQ1kiLCJURUVUSEJSVVNISU5HX0ZSRVFVRU5DWSIsIlNNT0tJTkdfRlJFUVVFTkNZIikgfiAiTGlmZXN0eWxlXG4mIGh5Z2llbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiRlJFUVVFTkNZIiwgdmFyaWFibGUpIH4gIkRpZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiQUxDT0hPTCIsIHZhcmlhYmxlKSB+ICJEaWV0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUgJWluJSBjKCJESUVUX1RZUEUiLCJUWVBFU19PRl9QTEFOVFMiKSB+ICJEaWV0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIlNQRUNJQUxJWkVEIiwgdmFyaWFibGUpIH4iU3BlY2lhbGl6ZWRcbkRpZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiUkVHSU9OIiwgdmFyaWFibGUpIH4gIlJlZ2lvbiBvZlxuQmlydGgiLA0KICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lZGljYWwgaGlzdG9yeSINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUNCiAgICBtZXJnZShlbnRlcm90eXBlc19zaGFubm9uX21lZGlhbiwgYnkueD0ieS5sZXZlbCIsIGJ5Lnk9IkVudGVyb3R5cGVzX2lkIikgJT4lDQogIG11dGF0ZShicmFuY2ggPSJDbG9zdHJpZGlhbGVzIERNTSBwYXJ0aXRpb25zIikgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoeS5sZXZlbCAlaW4lIGMoIm0xOCIsIm0xNCIsIm0xNiIsIm0xNyIsIm03IiksICJQcmV2b3RlbGxhIERNTSBwYXJ0aXRpb25zIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTExIiwibTE1IiwibTYiLCJtOCIsIm0xMCIsIm0zIiwibTQiLCJtMiIpLCAiQmFjdGVyb2lkZXMgRE1NIHBhcnRpdGlvbnMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTMiKSwgIkFray4iLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoZXN0aW1hdGUgPSBsb2coZXN0aW1hdGUpKSAlPiUNCiAgI211dGF0ZShlc3RpbWF0ZTIgPSBpZmVsc2UocC52YWx1ZT5wX2N1dF9vZmYsMCxlc3RpbWF0ZSkpICU+JQ0KICAgbXV0YXRlKGVzdGltYXRlMj1lc3RpbWF0ZSkgJT4lDQogICAgIGZpbHRlcighKHZhcmlhYmxlICVpbiUgZ3JlcCgiQ09MTCIsIHZhcmlhYmxlLCB2YWx1ZSA9IFRSVUUpICkpICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lDQogIG11dGF0ZShzPW1lYW4oYWJzKGVzdGltYXRlMikpKSAlPiUgDQogIGZpbHRlcihzPjApICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIG11dGF0ZSh5LmxldmVsID0geS5sZXZlbCAlPiUgc3RyaW5ncjo6c3RyX3RvX3VwcGVyKCkgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHNoYW5ub25fbWVkaWFuLCAuZGVzYyA9IFRSVUUpKSAlPiUNCiAgbXV0YXRlKHZhcmlhYmxlID0gdmFyaWFibGUgJT4lIGFzLmNoYXJhY3RlciAlPiUgYXMuZmFjdG9yKCkgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHMsIC5kZXNjID0gRkFMU0UpKSAlPiUgIA0KICAgbXV0YXRlKGJyYW5jaCA9IGJyYW5jaCAlPiUgZ3N1YigiRE1NIHBhcnRpdGlvbnMiLCAiXG5ETU0gcGFydGl0aW9ucyIsLikpICU+JQ0KICBncm91cF9ieSh5LmxldmVsLCB2YXJpYWJsZV9ncm91cCwgYnJhbmNoKSAlPiUNCiAgc3VtbWFyaXNlKGVzdGltYXRlPXN1bShhYnMoZXN0aW1hdGUyKSkpICU+JQ0KICANCiAgZ2dwbG90KCkgKw0KICBnZW9tX2JhcihhZXMoeT0geS5sZXZlbCAseD1lc3RpbWF0ZSxmaWxsPXZhcmlhYmxlX2dyb3VwKSwgc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgZmFjZXRfZ3JpZChicmFuY2h+Liwgc2NhbGU9ImZyZWUiLCBzcGFjZSA9ICJmcmVlIikgKyBzY2FsZV9maWxsX2JyZXdlcigiIix0eXBlPSJxdWFsIiwgcGFsZXR0ZSA9ICJTZXQyIikgKw0KICB5bGFiKCJNaWNyb2Jpb21lIHBhcnRpdGlvblxub3JkZXJlZCBieSBicmFuY2ggYW5kIGJ5IGFscGhhLWRpdmVyc2l0eSIpICsgeGxhYigiYWJzb2x1dGVkIGN1bW11bGF0ZWQgbW9kZWwgd2VpZ2h0cyIpICsgDQogICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgLT4gZmlnNEMNCg0KZmlnNEEgPSBmaWc0QSArIHlsYWIoIiIpDQoNCiAoKGZpZzREICsgZmlnNEIgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEsMykpKSAvDQogICAoZmlnNEMgKyBmaWc0QSArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMSwzLjUpKSkgKyBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDMpKSApKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJhIikNCiANCiBnZ3NhdmUoImZpZ3VyZXMvZmlndXJlNC5wZGYiKQ0KIA0KDQpgYGANCg0KDQojIyBmb2N1cyBvbiBCYWN0ZXJvaWRlcyBicmFuY2hlcw0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xMH0NCiAgcmVnbV90aWR5ICU+JQ0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lIG11dGF0ZShwLnZhbHVlID0gcC5hZGp1c3QocC52YWx1ZSwgbWV0aG9kPSJmZHIiKSkgJT4lDQogICAgbXV0YXRlKHZhcmlhYmxlX2dyb3VwID0gImRpc2Vhc2UiKSAlPiUNCiAgIG11dGF0ZSh2YXJpYWJsZV9ncm91cCA9IA0KICAgICAgICAgICAgIGNhc2Vfd2hlbih2YXJpYWJsZSAlaW4lIGMoIkFHRV9ZRUFSUyIsIlNFWCIsIkJNSSIsIkJPV0VMX01PVkVNRU5UX0ZSRVFVRU5DWSIpIH4gIkludHJpbnNpY1xuSG9zdCIsDQogICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJNRUFMUyIsIHZhcmlhYmxlKSB+ICJMaWZlc3R5bGVcbiYgaHlnaWVuZSIsDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlICVpbiUgYygiRVhFUkNJU0VfRlJFUVVFTkNZIiwiUE9PTF9GUkVRVUVOQ1kiLCJDT1NNRVRJQ1NfRlJFUVVFTkNZIiwiUFJFUEFSRURfTUVBTFNfRlJFUVVFTkNZIiwiVEVFVEhCUlVTSElOR19GUkVRVUVOQ1kiLCJTTU9LSU5HX0ZSRVFVRU5DWSIpIH4gIkxpZmVzdHlsZVxuJiBoeWdpZW5lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkZSRVFVRU5DWSIsIHZhcmlhYmxlKSB+ICJEaWV0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIkFMQ09IT0wiLCB2YXJpYWJsZSkgfiAiRGlldCIsDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlICVpbiUgYygiRElFVF9UWVBFIiwiVFlQRVNfT0ZfUExBTlRTIikgfiAiRGlldCIsDQogICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJTUEVDSUFMSVpFRCIsIHZhcmlhYmxlKSB+IlNwZWMuXG5EaWV0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIlJFR0lPTiIsIHZhcmlhYmxlKSB+ICJSZWcuIG9mXG5CaXJ0aCIsDQogICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTWVkaWNhbCBoaXN0b3J5Ig0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICU+JQ0KICAgIG1lcmdlKGVudGVyb3R5cGVzX3NoYW5ub25fbWVkaWFuLCBieS54PSJ5LmxldmVsIiwgYnkueT0iRW50ZXJvdHlwZXNfaWQiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IkNsb3N0cmlkaWFsZXMgRE1NIHBhcnRpdGlvbnMiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZSh5LmxldmVsICVpbiUgYygibTE4IiwibTE0IiwibTE2IiwibTE3IiwibTciKSwgIlByZXZvdGVsbGEgRE1NIHBhcnRpdGlvbnMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gcGFydGl0aW9ucyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoeS5sZXZlbCAlaW4lIGMoIm0xMyIpLCAiQWtrLiIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShzdWJzdGF0ZXMgPSAiSGlnaCIpICU+JQ0KICBtdXRhdGUoc3Vic3RhdGVzID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTEiLCJtNiIsIm0xMCIsIm0zIiksICJNZWRpdW0iLHN1YnN0YXRlcykpICU+JQ0KICBtdXRhdGUoc3Vic3RhdGVzID0gaWZlbHNlKHkubGV2ZWwgJWluJSBjKCJtMTUiKSwgIkxvdyIsc3Vic3RhdGVzKSkgJT4lDQogIGZpbHRlcihicmFuY2ggPT0gIkJhY3Rlcm9pZGVzIERNTSBwYXJ0aXRpb25zIikgJT4lDQogIG11dGF0ZShzdWJzdGF0ZXMgPSBzdWJzdGF0ZXMgJT4lIGZvcmNhdHM6OmZjdF9yZWxldmVsKCJIaWdoIixhZnRlcj0yICkpICU+JQ0KICBtdXRhdGUoZXN0aW1hdGUgPSBsb2coZXN0aW1hdGUpKSAlPiUNCiAgbXV0YXRlKGVzdGltYXRlMiA9IGlmZWxzZShwLnZhbHVlPnBfY3V0X29mZiwwLGVzdGltYXRlKSkgJT4lDQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUNCiAgbXV0YXRlKHM9bWVhbihhYnMoZXN0aW1hdGUyKSkpICU+JSANCiAgZmlsdGVyKHM+MCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKHkubGV2ZWwgPSB5LmxldmVsICU+JSBzdHJpbmdyOjpzdHJfdG9fdXBwZXIoKSAlPiUgZm9yY2F0czo6ZmN0X3Jlb3JkZXIoc2hhbm5vbl9tZWRpYW4sIC5kZXNjID0gVFJVRSkpICU+JQ0KICANCiAgbXV0YXRlKGJyYW5jaCA9IGJyYW5jaCAlPiUgZ3N1YigiRE1NIHR5cGVzIiwgIlxuRE1NIHR5cGVzIiwuKSkgJT4lICNwdWxsKHZhcmlhYmxlKSAlPiUgZ3JlcCgiQ09MTCIsLikNCiAgZmlsdGVyKCEodmFyaWFibGUgJWluJSBncmVwKCJDT0xMIiwgdmFyaWFibGUsIHZhbHVlID0gVFJVRSkgKSkgJT4lDQogIA0KICBtdXRhdGUodmFyaWFibGUgPSBnc3ViKCJfRlJFUVVFTkNZfFNQRUNJQUxJWkVEX0RJRVRffEFMQ09IT0xfVFlQRVNffFJFR0lPTl9CSVJUSF8iLCIiLCB2YXJpYWJsZSkpICU+JQ0KICBtdXRhdGUodmFyaWFibGUgPSANCiAgICAgICAgICAgY2FzZV93aGVuKGdyZXBsKCJOT19GT09EIiwgdmFyaWFibGUpfiJObyBmb29kIGFsbGVyZ3kiLA0KICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm5vdC5lYXQuZ2x1dGVuIiwgdmFyaWFibGUpfiJHbHV0ZW4gaW50b2xlcmFuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoImdsdXRlbi5JZ0ciLCB2YXJpYWJsZSl+IkdsdXRlbiBhbGxlcmd5IChJZ0cpIiwNCiAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJXRVNURU5QUklDRSIsIHZhcmlhYmxlKX4iTG93IHByb2Nlc3NlZCIsDQogICAgICAgICAgICAgICAgICAgICBncmVwbCgiT1RIRVJfUkVTVFJJQ1RJT05TIiwgdmFyaWFibGUpfiJPdGhlciByZXN0cmljdGlvbnMiLA0KICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIlNFWCIsIHZhcmlhYmxlKX4iU2V4IChtYWxlKSIsDQogICAgICAgICAgICAgICAgICAgICBUUlVFIH4gdmFyaWFibGUpKSAlPiUNCiAgbXV0YXRlKHZhcmlhYmxlID0gZ3N1YigiX3xcXC4iLCIgIiwgdmFyaWFibGUpKSAlPiUNCiAgbXV0YXRlKHZhcmlhYmxlID0gdmFyaWFibGUgJT4lIGFzLmNoYXJhY3RlciAlPiUgYXMuZmFjdG9yKCkgJT4lIGZvcmNhdHM6OmZjdF9yZW9yZGVyKHMsIC5kZXNjID0gVFJVRSkpICU+JSANCiAgICAgbXV0YXRlKGJyYW5jaCA9IGJyYW5jaCAlPiUgZ3N1YigiRE1NIHBhcnRpdGlvbnMiLCAiXG5ETU0gcGFydGl0aW9ucyIsLikpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICAgIGdlb21fdGlsZShhZXMoeT15LmxldmVsLCB4PXZhcmlhYmxlLCBmaWxsPWVzdGltYXRlKSkgKyANCiAgICBnZW9tX3BvaW50KGFlcyh5PXkubGV2ZWwsIHg9dmFyaWFibGUsIGFscGhhPXAudmFsdWU8cF9jdXRfb2ZmKSkgKyANCiAgICAjc2NhbGVfZmlsbF9ncmFkaWVudDIoIkxvZyBPUiIsIGxvdz1zY2FsZXM6Om11dGVkKCJibHVlIiksIG1pZD0id2hpdGUiLCBoaWdoPXNjYWxlczo6bXV0ZWQoInJlZCIpKSArDQogICAgc2NhbGVfZmlsbF9ncmFkaWVudCgiTG9nIE9SIiwgbG93PSJ3aGl0ZSIsIGhpZ2g9IiMxYTFhMWEiKSArICANCiAgICBmYWNldF9ncmlkKHZhcmlhYmxlX2dyb3VwfnN1YnN0YXRlcywgc2NhbGU9ImZyZWUiLCBzcGFjZSA9ICJmcmVlIikgKyANCiAgICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKw0KICAgIHNjYWxlX2FscGhhX2Rpc2NyZXRlKCJGRFIgPCAxMCUiKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArDQogICAgeWxhYigiTWljcm9iaW9tZSBCYWN0ZXJvaWRlcyBwYXJ0aXRpb25zIikgKyB4bGFiKCJBR1AgcXVlc3Rpb25uYWlyZSBkYXRhIikgKyBjb29yZF9mbGlwKCkgDQoNCiAgDQogDQoNCg0KDQoNCmBgYA0KDQoNCg0KDQoNCnRvIGRvOiBwbG90IHNoYW5ub24gdnMgY3VtdWxhdGVkIG1vZGVsIHdlaWdodCBhbmQgbWFrZSBhbiBpZCBjYXJkIGZvciBwYXJ0aXRpb24gMSAocmVmKQ0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MjAsIGZpZy53aWR0aD0yMH0NCg0KZmlnNEEgKyBjb29yZF9mbGlwKCkNCg0KDQooZmlnNEErZmlnNEIrIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMiwxKSkpIC8gKGZpZzRDKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDMsMSkpDQoNCg0KYGBgDQoNCg0KYGBge3J9DQoNCg0KICANCiAgWiA9IG1vZGVsLm1hdHJpeChvYmplY3QpDQogICAgcHJvYnMgPC0gb2JqZWN0JGZpdHRlZCAjIGF2b2lkIG5hcHJlZGljdCBmcm9tIGZpdHRlZC5kZWZhdWx0DQogICAgY29lZnMgPC0gY29lZihvYmplY3QpDQogICAgaWYgKGlzLnZlY3Rvcihjb2VmcykpeyAjIGllIHRoZXJlIGFyZSBvbmx5IDIgcmVzcG9uc2UgY2F0ZWdvcmllcw0KICAgICAgICBjb2VmcyA8LSB0KGFzLm1hdHJpeChjb2VmcykpDQogICAgICAgIHByb2JzIDwtIGNiaW5kKDEgLSBwcm9icywgcHJvYnMpDQogICAgfQ0KICAgIGNvZWZkaW0gPC0gZGltKGNvZWZzKQ0KICAgIHAgPC0gY29lZmRpbVsyTF0NCiAgICBrIDwtIGNvZWZkaW1bMUxdDQogICAgbmNvZWZzIDwtIGsgKiBwDQogICAga3BlZXMgPC0gcmVwKHAsIGspDQogICAgbiA8LSBkaW0oWilbMUxdDQojIyAgTm93IGNvbXB1dGUgdGhlIG9ic2VydmVkICg9IGV4cGVjdGVkLCBpbiB0aGlzIGNhc2UpIGluZm9ybWF0aW9uLA0KIyMgIGUuZy4gYXMgaW4gVCBBbWVtaXlhICJBZHZhbmNlZCBFY29ub21ldHJpY3MiICgxOTg1KSBwcDI5NS02Lg0KIyMgIEhlcmUgaSBhbmQgaiBhcmUgYXMgaW4gQW1lbWl5YSwgYW5kIHgsIHhiYXIgYXJlIHZlY3RvcnMNCiMjICBzcGVjaWZpYyB0byAoaSxqKSBhbmQgdG8gaSByZXNwZWN0aXZlbHkuDQogICAgaW5mbyA8LSBtYXRyaXgoMCwgbmNvZWZzLCBuY29lZnMpDQogICAgTmFtZXMgPC0gZGltbmFtZXMoY29lZnMpDQogICAgaWYgKGlzLm51bGwoTmFtZXNbWzFMXV0pKSB7TmFtZXMgPC0gTmFtZXNbWzJMXV0gfSBlbHNlIHsNCiAgICAgIE5hbWVzIDwtIGFzLnZlY3RvcihvdXRlcihOYW1lc1tbMkxdXSwgTmFtZXNbWzFMXV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKG5hbWUyLCBuYW1lMSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKG5hbWUxLCBuYW1lMiwgc2VwID0gIjoiKSkpfQ0KICAgIGRpbW5hbWVzKGluZm8pIDwtIGxpc3QoTmFtZXMsIE5hbWVzKQ0KICAgIHgwIDwtIG1hdHJpeCgwLCBwLCBrKzFMKQ0KICAgIHJvdy50b3RhbHMgPC0gb2JqZWN0JHdlaWdodHMNCiAgICBwYiA8LSB0eHRQcm9ncmVzc0JhcihtaW49MSxtYXg9bikNCiAgICBmb3IgKGkgaW4gc2VxX2xlbihuKSkgew0KICAgICAgDQogICAgICAgIFppIDwtIFpbaSwgXQ0KICAgICAgICB4YmFyIDwtIFppICogcmVwKHByb2JzW2ksIC0xLCBkcm9wID0gRkFMU0VdLCBrcGVlcykNCiAgICAgICAgZm9yIChqIGluIHNlcV9sZW4oaysxKSl7DQogICAgICAgICAgICB4IDwtIHgwDQogICAgICAgICAgICB4Wywgal0gPC0gWmkNCiAgICAgICAgICAgIHggPC0geFssIC0xLCBkcm9wID0gRkFMU0VdDQogICAgICAgICAgICB4IDwtIHggLSB4YmFyDQogICAgICAgICAgICBkaW0oeCkgPC0gYygxLCBuY29lZnMpDQogICAgICAgICAgICBpbmZvIDwtIGluZm8gKyAocm93LnRvdGFsc1tpXSAqIHByb2JzW2ksIGpdICogY3Jvc3Nwcm9kKHgpKQ0KICAgICAgICB9DQogICAgICAgIHNldFR4dFByb2dyZXNzQmFyKHBiLCBpKQ0KICAgIH0NCiAgICBpbmZvDQoNCg0KDQpgYGANCg0KDQojIyBoeXN0ZXJlc2lzIGV4cGxvcmF0aW9uDQoNCg0KDQpgYGB7cn0NCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtICU+JQ0KICBtdXRhdGUoYnJhbmNoID0iQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZShFbnRlcm90eXBlc19pZCAlaW4lIGMoIm0xOCIsIm0xNCIsIm0xNiIsIm0xNyIsIm03IiksICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoRW50ZXJvdHlwZXNfaWQgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkICVpbiUgYygibTEzIiksICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBmaWx0ZXIoYnJhbmNoPT0iQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiB8IEVudGVyb3R5cGVzX2lkID09Im01IikgJT4lDQogIHNlbGVjdChTQUxURURfU05BQ0tTX0ZSRVFVRU5DWSxWRUdFVEFCTEVfRlJFUVVFTkNZLFNVR0FSWV9TV0VFVFNfRlJFUVVFTkNZLFRZUEVTX09GX1BMQU5UUyxGUlVJVF9GUkVRVUVOQ1ksQU5USUJJT1RJQ19ISVNUT1JZKSAlPiUNCiAgbXV0YXRlX2FsbChhcy5udW1lcmljKSAlPiUNCiAgYWRlNDo6ZHVkaS5wY2Eoc2Nhbm5mPUZBTFNFLCBuZj0yKSAtPiBtZXRhZGF0YV9lbnRlcm90eXBlc19wY2FfYnJhbmNoDQogIA0KDQoNCm1ldGFkYXRhX2VudGVyb3R5cGVzX251bV9zaGFubm9uID0gbWVyZ2UobWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtLHNoYW5ub24sIGJ5PSJyb3cubmFtZXMiKQ0KICANCg0KbWV0YWRhdGFfZW50ZXJvdHlwZXNfbnVtX3NoYW5ub24gJT4lDQogIG11dGF0ZShicmFuY2ggPSJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkICVpbiUgYygibTE4IiwibTE0IiwibTE2IiwibTE3IiwibTciKSwgIlByZXZvdGVsbGEgRE1NIHR5cGVzIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZShFbnRlcm90eXBlc19pZCAlaW4lIGMoIm0xMSIsIm0xNSIsIm02IiwibTgiLCJtMTAiLCJtMyIsIm00IiwibTIiKSwgIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoRW50ZXJvdHlwZXNfaWQgJWluJSBjKCJtMTMiKSwgIkFra2VybWFuc2lhIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIGZpbHRlcihicmFuY2g9PSJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiIHwgRW50ZXJvdHlwZXNfaWQgPT0ibTUiKSAlPiUNCiAgc2VsZWN0KFRZUEVTX09GX1BMQU5UUywgc2hhbm5vbiwgRW50ZXJvdHlwZXNfaWQpICU+JQ0KICBtdXRhdGUoRW50ZXJvdHlwZXNfaWQ9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKEVudGVyb3R5cGVzX2lkLCBzaGFubm9uKSkgJT4lDQogICNtdXRhdGUoVFlQRVNfT0ZfUExBTlRTPVRZUEVTX09GX1BMQU5UUyU+JSBhcy5udW1lcmljKCkpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeD1UWVBFU19PRl9QTEFOVFMsZmlsbD1FbnRlcm90eXBlc19pZCksIHN0YXQ9ImNvdW50IiwgcG9zaXRpb249ImZpbGwiKQ0KDQoNCiBtZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW1fc2hhbm5vbixtZXRhZGF0YV9lbnRlcm90eXBlc19wY2FfYnJhbmNoJGxpLCBieS54PSJSb3cubmFtZXMiLCBieS55PSJyb3cubmFtZXMiKSAlPiUgDQogICBtdXRhdGUoYnJhbmNoID0iQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZShFbnRlcm90eXBlc19pZCAlaW4lIGMoIm0xOCIsIm0xNCIsIm0xNiIsIm0xNyIsIm03IiksICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoRW50ZXJvdHlwZXNfaWQgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkICVpbiUgYygibTEzIiksICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBmaWx0ZXIoYnJhbmNoPT0iQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiB8IEVudGVyb3R5cGVzX2lkID09Im01IikgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZD0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoRW50ZXJvdHlwZXNfaWQsIHNoYW5ub24pKSAlPiUNCiAgIHNlbGVjdChBeGlzMSxzaGFubm9uLEVudGVyb3R5cGVzX2lkKSAlPiUNCiAgIGdncGxvdCgpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9QXhpczEseT1zaGFubm9uLGNvbD1FbnRlcm90eXBlc19pZCksIHNpemU9MSxhbHBoYT0wLjUpDQoNCm1lcmdlKG1ldGFkYXRhX2VudGVyb3R5cGVzX251bV9zaGFubm9uLG1ldGFkYXRhX2VudGVyb3R5cGVzX3BjYV9icmFuY2gkbGksIGJ5Lng9IlJvdy5uYW1lcyIsIGJ5Lnk9InJvdy5uYW1lcyIpICU+JSANCiAgIG11dGF0ZShicmFuY2ggPSJDbG9zdHJpZGlhbGVzIERNTSB0eXBlcyIpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkICVpbiUgYygibTE4IiwibTE0IiwibTE2IiwibTE3IiwibTciKSwgIlByZXZvdGVsbGEgRE1NIHR5cGVzIixicmFuY2gpKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZShFbnRlcm90eXBlc19pZCAlaW4lIGMoIm0xMSIsIm0xNSIsIm02IiwibTgiLCJtMTAiLCJtMyIsIm00IiwibTIiKSwgIkJhY3Rlcm9pZGVzIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoRW50ZXJvdHlwZXNfaWQgJWluJSBjKCJtMTMiKSwgIkFra2VybWFuc2lhIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIGZpbHRlcihicmFuY2g9PSJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiIHwgRW50ZXJvdHlwZXNfaWQgPT0ibTUiKSAlPiUNCiAgbXV0YXRlKEVudGVyb3R5cGVzX2lkPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihFbnRlcm90eXBlc19pZCwgc2hhbm5vbikpICU+JQ0KICAgc2VsZWN0KEF4aXMxLHNoYW5ub24sRW50ZXJvdHlwZXNfaWQpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeD1yYW5rKCgtQXhpczEpKSsxLGZpbGw9RW50ZXJvdHlwZXNfaWQpLCBwb3NpdGlvbj0iZmlsbCIsIGJpbnM9MzApICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSAgKyBzY2FsZV94X2xvZzEwKCkNCg0KDQptZXJnZShtZXRhZGF0YV9lbnRlcm90eXBlc19udW1fc2hhbm5vbixtZXRhZGF0YV9lbnRlcm90eXBlc19wY2FfYnJhbmNoJGxpLCBieS54PSJSb3cubmFtZXMiLCBieS55PSJyb3cubmFtZXMiKSAlPiUgDQogICBtdXRhdGUoYnJhbmNoID0iQ2xvc3RyaWRpYWxlcyBETU0gdHlwZXMiKSAlPiUNCiAgbXV0YXRlKGJyYW5jaCA9IGlmZWxzZShFbnRlcm90eXBlc19pZCAlaW4lIGMoIm0xOCIsIm0xNCIsIm0xNiIsIm0xNyIsIm03IiksICJQcmV2b3RlbGxhIERNTSB0eXBlcyIsYnJhbmNoKSkgJT4lDQogIG11dGF0ZShicmFuY2ggPSBpZmVsc2UoRW50ZXJvdHlwZXNfaWQgJWluJSBjKCJtMTEiLCJtMTUiLCJtNiIsIm04IiwibTEwIiwibTMiLCJtNCIsIm0yIiksICJCYWN0ZXJvaWRlcyBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBtdXRhdGUoYnJhbmNoID0gaWZlbHNlKEVudGVyb3R5cGVzX2lkICVpbiUgYygibTEzIiksICJBa2tlcm1hbnNpYSBETU0gdHlwZXMiLGJyYW5jaCkpICU+JQ0KICBmaWx0ZXIoYnJhbmNoPT0iQmFjdGVyb2lkZXMgRE1NIHR5cGVzIiB8IEVudGVyb3R5cGVzX2lkID09Im01IikgJT4lDQogIG11dGF0ZShFbnRlcm90eXBlc19pZD0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoRW50ZXJvdHlwZXNfaWQsIHNoYW5ub24pKSAlPiUNCiAgIHNlbGVjdChBeGlzMSxzaGFubm9uLEVudGVyb3R5cGVzX2lkKSAlPiUNCiAgZ2dwbG90KCkgKyANCiAgZ2VvbV9wb2ludChhZXMoeD1yYW5rKCgtQXhpczEpKSsxLHk9c2hhbm5vbikpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKQ0KDQoNCg0KYGBgDQoNCg0KDQoNCg0K