Set up

Load libraries

library(tidyverse)
library(readxl)
library(DT)
library(Matrix)
library(patchwork)
library(gridExtra)
library(viridis)
library(RColorBrewer)
library(ComplexHeatmap)
library(circlize)
library(purrr)
library(broom)
#library(broom.mixed)
library(igraph)
library(ggpubr)
library(correlation)
library(ggrepel)
library(ggalluvial)
library(Seurat)
library(clusterProfiler)
library(umap) ## https://github.com/tkonopka/umap/blob/master/vignettes/umap.Rmd
library(tidygraph)
library(ggraph)
library(scales)
library(WGCNA)
library(mixOmics)
library(eulerr)
library(lmerTest)
#library(broom.mixed)
library(emmeans)

Load data

# Malaria Explore 1536 data
data <- utils::read.delim("../data/data/explore1536/20230411_infectious_olink.tsv") 
# Malaria sampleTable
sampleTable_simple <- readRDS("../data/metaData_clean/Explore1536_Malaria_sampleTable_simple.rds")
# Malaria subjectTable
subjectTable <- readRDS("../data/metaData_clean/MalariaResource_subjectTable.rds")
# Malaria clinchem data
clinchem_study_pats_acute.wide <- readRDS("../data/metaData_clean/Explore1536_ClinicalChemistry_acute.rds")

# Tropical fever Explore 1536 data
TF.long <- readRDS("../data/data_clean/Explore1536_TF_tidy_long.rds")
# Tropical fever sampleTable
TF_sampleTable <- readRDS("../data/metaData_clean/Explore1536_TF_sampleTable.rds")


# HPA v24
hpa_24.0 <- read_tsv("../data/hpa/proteinatlas_v24.tsv") %>% janitor::clean_names() %>% 
  mutate(secretome_location = ifelse(is.na(secretome_location),"Not secreted",secretome_location))
# HPA tissue expression v23
hpa.tissue <- read_tsv("../data/hpa/rna_tissue_consensus.tsv") %>% janitor::clean_names()


# Load cleaned malaria data
#-   assays with QC warn in more than 70% of all assays
#-   samples with more than 70% below LOD
data.wide <- readRDS("../data/data_clean/Explore1536_tidy_wide.rds")
data.long <- readRDS("../data/data_clean/Explore1536_tidy_long.rds")

## Explore 1536 data set - MGH Covid-19 study, Filbin et al. 2021
covid_NPXdata <- read_delim("../data/MGH_OLINK_COVID/MGH_COVID_OLINK_NPX.txt",comment = "##")
mgh.covid.meta <- read_delim("../data/MGH_OLINK_COVID/MGH_COVID_Clinical_Info.txt", comment="##") %>% janitor::clean_names()
mgh.covid.meta.key <- read_excel("../data/MGH_OLINK_COVID/variable_descriptions.xlsx")

## load tropical fever cohort data
TF_SOFA <- readRDS("../data/metaData_clean/2021213_TF_DA_TROP_SOFAscores.rds") %>% filter(diagnose_clean!="P.falciparum")
TF.long <- readRDS("../data/data_clean/Explore1536_TF_tidy_long.rds")

## loding  MIP Cohort FACS data - Lautenbach et al. Cell Reports 2022

FACs_data <- read_delim("../../MalariaTravellers/data/TravellerCohort_FACS_log2cpu_long.csv")
FACS_meta <- read_delim("../../MalariaTravellers/data/TravellerCohort_SubjectTable.csv")

Set theme & colors

theme_set(theme_minimal(base_size = 6))

time3_col <- c("Acute" = "#C51B7D", 
               "D10" = "#E9A3C9",
               "M12" = "#4D9221")

sex2_col <- c(male = "#c5b8dc",
              female = "#b9d2b1")

endemic2_col <- c(primary_infected = "#998EC3",
                  previously_exposed = "#F1A340")
severe_5_col = c("1"="tomato",
                 "0"="grey80")

secretome_location_cols <- c("Secreted to blood" = "#FB8072",
                             "Intracellular and membrane" = "#8DD3C7",
                             "Secreted in other tissues" = "#B3DE69",
                             "Secreted to extracellular matrix" = "#80B1D3",
                             "Secreted in brain" = "#b9d2b1",#"#FCCDE5",
                             "Secreted to digestive system" = "#FDB462",
                             "Secreted - unknown location" = "#FFFF00",
                             "Secreted in male reproductive system" = sex2_col[[1]],#"#BEBADA",
                             "Secreted in female reproductive system" = sex2_col[[2]],
                             "Not secreted" = "#D9D9D9")

secretome_location_tissue_spec_cols <- c(secretome_location_cols,
                                         c("Not secreted - Tissue enriched" = "#88419d",
                                           "Not secreted - Tissue enhanced" = "#8c96c6",
                                           "Not secreted - Group enriched" = "#b3cde3",
                                           "Not secreted - Low tissue specificity" = "#edf8fb")
                                         )

SOFA_sub_col = colorRamp2(c(0,4), c("white","red"))

patient_kclust3 <- c('3' = "#92c5de", '2' = "#f4a582", '1' = "#ca0020")
patient_kclust3_lab <- c("mild"="#92c5de", "moderate"="#f4a582", "severe"="#ca0020")
patient_kclust3_lab_conv <- c("mild"="#92c5de", "moderate"="#f4a582", "severe"="#ca0020","convalescence" ="grey50")



SOFA_sub_col = colorRamp2(c(0,4), c("white","red"))

SOFA_total_col = colorRamp2(c(min(subjectTable$SOFA_total,na.rm = TRUE),
                              median(subjectTable$SOFA_total,na.rm = TRUE),
                              max(subjectTable$SOFA_total,na.rm = TRUE)),
                            c(brewer.pal(3,name="PuBu")))

## dimensinality reduction theme
my_dimred_theme <- theme_classic() + 
  theme(axis.text = element_blank(),
        axis.ticks = element_blank(),
        #text = element_text(size = 12),
        #legend.text = element_text(size = 10),
        legend.position = "right") 

## a4 pdf theme
theme_a4_pdf <- theme(axis.text.x = element_text(size=6),
                      axis.text.y = element_text(size=6),
                      axis.title.x = element_text(size=6),
                      axis.title.y = element_text(size=6),
                      ## legend
                      legend.key.size = unit(1, 'cm'), #change legend key size
                      legend.key.height = unit(0.25, 'cm'), #change legend key height
                      legend.key.width = unit(0.25, 'cm'), #change legend key width
                      legend.title = element_text(size=6), #change legend title font size
                      legend.text = element_text(size=6),
                      ## label
                      plot.title = element_blank(),
                      plot.subtitle =  element_blank(),
                      plot.caption =  element_blank(),
                      ## facet_grid
                      strip.text.x = element_text(size = 6,face="bold"),
                      #strip.text.y = element_text(size = 6),
                      strip.placement = "outside"
)

## patchwork panel a4 pdf theme
patchwork_panel_a4_pdf <- patchwork::plot_annotation(theme = theme(plot.title = element_text(size = 12),
                                                                   plot.tag = element_text(size = 16,face = 'bold')
),
tag_levels = 'A') 
asym_study_id <- c("2021004")

## 2013004 - Lib 1
## 2013007 - Lib 2
## 2013008 - Lib 3
## 2018002 - Lib 4

rhapsody_study_ids <- c("2013004","2013007","2013008","2018002")
#require(clusterProfiler)

#length(unique(data$UniProt)) ## 1463
mapping_uniprot_ensembl <- bitr(unique(data$UniProt), 
                                fromType="UNIPROT",
                                toType=c("SYMBOL", "ENSEMBL","ENTREZID"), 
                                OrgDb="org.Hs.eg.db") %>% 
  dplyr::rename(UniProt = UNIPROT,
                Symbol = SYMBOL,
                Ensembl = ENSEMBL,
                Entrez = ENTREZID) %>%
  inner_join(data %>% dplyr::select(Assay,UniProt) %>% dplyr::distinct(),by="UniProt")

#write_delim(mapping_uniprot_ensembl, "../../2022_Explore1536FarnertLab/data/Mapping_Explore_UniProt2Ensembl.txt")

Figure 1

Plasma proteomic perturbation during clinical malaria - Cohort characteristics

fig1.list <- list()

Figure 1B

(fig1.list[["general_sex_age_dist"]] <- subjectTable %>% 
    ggplot(aes(x=age, fill=sex)) +
    geom_density(alpha=.6) +
    #theme_classic() +
    theme(axis.text = element_text(size=6), 
          axis.title = element_text(size=6), 
          axis.ticks.x = element_blank()) + 
    scale_fill_manual(values=sex2_col) +
    scale_color_manual(values=sex2_col) +
    
    labs(fill="Sex",
         x="age [years]",
         y="density")
)

Figure 1C

(fig1.list[["timepoint_sex_perc"]] <-sampleTable_simple %>% 
    inner_join(subjectTable,by="study_id") %>% 
    group_by(Time,sex) %>% 
    tally() %>% 
    group_by(Time) %>% 
    dplyr::mutate(percent=n/sum(n)) %>% 
    ggplot(aes(x=Time,y=n,fill=sex)) +
    geom_bar(stat="identity", position ="fill") +
    geom_text(aes(label=paste0(sprintf("%1.1f", percent*100),"%")),
              position=position_fill(vjust=0.5), colour="white", size =1.5) +
    scale_y_continuous(labels = scales::percent,expand = c(0,.01)) + 
    #theme_minimal() +
    theme(legend.position = "top",
          axis.ticks.x = element_blank()) + 
    scale_fill_manual(values=sex2_col) +
    labs(fill=NULL,
         x=NULL,
         y="Percentage")
)

Figure 1D

(fig1.list[["timepoint_exposure"]] <- sampleTable_simple %>% 
    inner_join(subjectTable,by="study_id") %>% 
    group_by(Time,endemic) %>% 
    tally() %>% 
    group_by(Time) %>% 
    dplyr::mutate(percent=n/sum(n)) %>% 
  mutate(endemic = factor(endemic, levels=c("primary_infected","previously_exposed"))) %>% 
    ggplot(aes(x=Time,y=n,fill=endemic)) +
    geom_bar(stat="identity", position ="fill") +
    geom_text(aes(label=paste0(sprintf("%1.1f", percent*100),"%")),
              position=position_fill(vjust=0.5), colour="white", size =1.5) +
    scale_y_continuous(labels = scales::percent,expand = c(0,.01)) + 
    #theme_minimal() +
    theme(legend.position = "top",
          axis.ticks.x = element_blank()) + 
    scale_fill_manual(values=endemic2_col,labels=c("primary_infected"="primary infected","previously_exposed"="previously exposed")) +
    labs(fill=NULL,
         x=NULL,
         y="Percentage")
)

Figure 1E

df <- data.wide %>% 
  inner_join(sampleTable_simple %>% 
               transmute(sample_id),
             by="sample_id") %>% 
  column_to_rownames("sample_id")

## PC calculation
pcaRes <- stats::prcomp(df,center = TRUE, scale. = TRUE)
varExp <- round(pcaRes$sdev^2 / sum(pcaRes$sdev^2) * 100)
pcaDF <- data.frame(PC1 = pcaRes$x[, 1],
                    PC2 = pcaRes$x[, 2]) %>% 
  rownames_to_column("sample_id") 

## Prep for plotting
data4plot <- pcaDF %>% 
  dplyr::inner_join(sampleTable_simple, by="sample_id")


(pca_fig1 <- data4plot %>% 
    ggplot(mapping = aes(x = PC1, y = PC2, color = Time,fill=NULL, label = NULL)) +
    geom_point(alpha = 0.9, size = 1) +
    ggplot2::scale_color_manual(values= time3_col) +
    labs(x = paste0("PC1 (",  varExp[1], " %)"),
         y = paste0("PC2 (",  varExp[2], " %)")) +
    theme_minimal()  +
    theme(legend.title = element_text(size = 6), 
          legend.text = element_text(size = 6)))

Figure 1F

## nest data
data_nested <- data.long %>% 
  inner_join(sampleTable_simple, by="sample_id") %>% 
  group_by(UniProt,Assay) %>% 
  nest()
## nest data
data_nested <- data.long %>% 
  inner_join(sampleTable_simple, by="sample_id") %>% 
  left_join(subjectTable %>% transmute(study_id, 
                                       exposure = factor(endemic, levels=c("primary_infected","previously_exposed"))),
            by="study_id") %>% 
  group_by(UniProt,Assay) %>% 
  nest()

lme_res <- data_nested %>% 
  mutate(lme.res.simple = purrr::map(data, ~ lmerTest::lmer(NPX ~ Time + exposure + (1|study_id), REML = F,
                                                            control = lme4::lmerControl(check.conv.singular = "ignore"),
                                           data = .x %>% dplyr::filter(Time!="D10"))),
         lme.res.complex = purrr::map(data, ~ lmerTest::lmer(NPX ~ Time * exposure + (1|study_id), REML = F,
                                                             control = lme4::lmerControl(check.conv.singular = "ignore"),
                                           data = .x %>% dplyr::filter(Time!="D10"))),
         lme.simple.tidy = purrr::map(lme.res.simple, ~ broom.mixed::tidy(.,)),
         lme.complex.tidy = purrr::map(lme.res.complex, ~ broom.mixed::tidy(.)),

         posthoc.time = purrr::map(lme.res.simple, ~ summary(contrast(emmeans(., ~ Time), method = "pairwise")) %>% tibble()),
         posthoc.time_exposure = purrr::map(lme.res.complex, ~ summary(contrast(emmeans(., ~ Time * exposure), method = "pairwise")) %>% tibble())
         )
  • finding better model
## compare simple (without interaction) with complex model (interaction)
bic_aic_res <- lme_res %>% 
  mutate(simple_glance = purrr::map(lme.res.simple, ~(broom::glance(.))),
         complex_glance = purrr::map(lme.res.complex, ~(broom::glance(.)))) %>% 
  unnest(cols = c(simple_glance,complex_glance),names_sep = ".") %>% 
  dplyr::select(Assay, contains("AIC"),contains("BIC"))

df_better_model <- bic_aic_res %>% 
  pivot_longer(cols=c(-UniProt,-Assay)) %>% 
  separate(name, into=c("model","eval"),sep = "\\.",remove = T) %>% 
  pivot_wider(names_from = model, values_from = value) %>% 
  mutate(simple_better = simple_glance < complex_glance,
         simple_delta = simple_glance-complex_glance,
         better_model = case_when(abs(simple_delta)>6 ~ "complex",
                                  .default = "simple"))
df_better_model %>% 
  group_by(eval) %>% 
  count(better_model) %>% 
  ggplot(aes(x=better_model, y=n)) +
  geom_col() +
      geom_text(aes(label=n),size=2,nudge_y = 50) + 
  facet_wrap(~eval)

df_better_model %>% filter(eval=="BIC",
                           better_model=="complex") 
## # A tibble: 14 × 8
## # Groups:   UniProt, Assay [14]
##    UniProt Assay   eval  simple_glance complex_glance simple_better simple_delta
##    <chr>   <chr>   <chr>         <dbl>          <dbl> <lgl>                <dbl>
##  1 Q9Y275  TNFSF1… BIC           276.           267.  FALSE                 9.66
##  2 P10586  PTPRF   BIC           153.           146.  FALSE                 7.56
##  3 P05107  ITGB2   BIC           148.           141.  FALSE                 6.98
##  4 Q9HAN9  NMNAT1  BIC           401.           394.  FALSE                 6.73
##  5 P50135  HNMT    BIC           340.           332.  FALSE                 8.39
##  6 Q9UL46  PSME2   BIC           199.           192.  FALSE                 6.96
##  7 P04179  SOD2    BIC           328.           319.  FALSE                 9.55
##  8 P00352  ALDH1A1 BIC           302.           290.  FALSE                11.6 
##  9 Q9P0V8  SLAMF8  BIC           308.           301.  FALSE                 6.78
## 10 Q16772  GSTA3   BIC           350.           341.  FALSE                 8.69
## 11 Q86SF2  GALNT7  BIC            74.3           68.0 FALSE                 6.33
## 12 Q96I15  SCLY    BIC           280.           273.  FALSE                 6.67
## 13 Q00796  SORD    BIC           401.           391.  FALSE                10.3 
## 14 Q7Z4W1  DCXR    BIC           300.           289.  FALSE                11.3 
## # ℹ 1 more variable: better_model <chr>
lme_res_padj <- lme_res %>% 
  unnest(cols="posthoc.time") %>% 
  filter(contrast=="Acute - M12") %>% 
  ungroup() %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
                  FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
  arrange(p.adj)
assay_better_complex_model <- df_better_model %>% filter(eval=="BIC",
                                                         better_model=="complex") %>% pull(Assay)

plot(euler(
  list("acute_m12" = lme_res_padj %>% filter(FDR==T) %>% pull(Assay),
       "bic_complex_better" = assay_better_complex_model)),
  
        fills = c("#C51B7D",
                  "white"),
       quantities = TRUE,
       lty = 1,#1:3,
       fontsize=2,
       labels = list(fontsize=7),
       shape = "ellipse",adjust_labels = T)

lme_res_padj %>% 
  transmute(Assay, estimate,p.adj) %>% 
  filter(Assay %in% assay_better_complex_model) %>% 
  arrange(-abs(estimate))
## # A tibble: 14 × 3
##    Assay    estimate    p.adj
##    <chr>       <dbl>    <dbl>
##  1 SLAMF8     2.48   4.64e-16
##  2 HNMT       1.42   2.76e- 7
##  3 NMNAT1     1.18   1.77e- 3
##  4 ALDH1A1    1.13   3.00e- 6
##  5 TNFSF13B   1.04   1.30e- 6
##  6 GSTA3      1.03   5.20e- 4
##  7 SOD2       0.920  5.69e- 4
##  8 SCLY       0.905  1.54e- 5
##  9 PSME2      0.814  6.65e- 8
## 10 DCXR       0.637  3.36e- 3
## 11 ITGB2      0.623  2.43e- 8
## 12 SORD       0.391  3.10e- 1
## 13 GALNT7    -0.0573 4.89e- 1
## 14 PTPRF     -0.0129 9.28e- 1
dap.res <- lme_res_padj %>% 
  dplyr::rename(logFC = estimate) %>% 
  mutate(direction = ifelse(logFC<0,"down","up"))  %>% 
  dplyr::select(-c(lme.res.simple,lme.res.complex,lme.complex.tidy))
(dap.acute.volcano <- dap.res %>% 
   ggplot(aes(x=logFC, y=-log10(p.adj), color=FDR)) +
   geom_point(alpha=0.7,size=.5, shape=16) +
   theme_minimal() +
   ggrepel::geom_text_repel(data = . %>% filter(FDR ==TRUE, abs(logFC) >1.5),
                            aes(label = Assay), color="black",
                            force        = 0.5,
                            direction    = "both",
                            segment.size = 0.2,
                            segment.alpha=.1,
                            show.legend = F,
                            size=1,
                            max.overlaps = 16,
                            box.padding = unit(0.2, "lines"),
                            point.padding = unit(0.5, "lines"),
                            segment.color = 'grey50') +
   
   geom_vline(xintercept = c(-1, 1), linetype = "dotted", linewidth = .5) +
   geom_hline(yintercept = -log10(0.01), linetype = "dotted", linewidth = .5) + 
   scale_x_continuous(breaks=c(-4.0,-3.0,-2.0,-1.0,0.0,1.0,2.0,3.0,4.0,5.0,6.0),limits = c(-4,6)) +
   
   geom_segment(aes(x = 1.1, y = 21, xend = 4, yend = 21), color=time3_col[[1]], #y=16.5
                arrow = arrow(length = unit(0.2, "cm"))) +
   annotate("text",x=2.6, y=22.5, size=2, label="High abundant\nin acute malaria") + #y=17.6
   
   geom_segment(aes(x = -1.1, y = 21, xend = -4, yend = 21),color=time3_col[[1]],
                arrow = arrow(length = unit(0.2, "cm"))) +
   annotate("text",x=-2.6, y=22.5, size=2, label="Low abundant\nin acute malaria") + #y=17.1
   
   labs(x="Estimated difference (NPX) at acute compared to convalescence",
        y="-log10(adj. p-value)") +
   theme(legend.position = "none",
         text = element_text(size=6)) +
   scale_color_manual(values= c(time3_col[[3]],time3_col[[1]])))

Figure 1G

hm.input <- data.wide %>% 
  inner_join(sampleTable_simple %>% dplyr::select(DAid,study_id, sample_id, Time),by="sample_id") %>% 
  dplyr::filter(Time=="Acute")

top25 <- dap.res %>% 
  dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>%
  mutate(up_down = ifelse(logFC>0,"up","down")) %>% 
  dplyr::group_by(up_down) %>% 
  slice_head(n=25)

top25.split <- top25 %>% column_to_rownames("Assay") %>% 
  transmute(direction = factor(direction, levels = c("up","down"), labels = c("high","low")))

norm.df <- hm.input %>% column_to_rownames("sample_id") %>% 
  dplyr::select(-c(DAid,Time,study_id)) %>% 
  dplyr::select(c(top25$Assay)) %>% 
  t() %>% scale()

## == ComplexHeatmap == ##
(acute.npx.top25.hm <- norm.df %>% 
    scale() %>% 
    Heatmap(name="scaled\nNPX",
            clustering_distance_columns = "spearman",
            clustering_method_columns="ward.D2",
            
            top_annotation = HeatmapAnnotation(df = data.frame(sample_id = colnames(.)) %>%
                                                 separate(sample_id, into = c("study_id","Time"),sep="\\|") %>% 
                                                 left_join(subjectTable %>% 
                                                             transmute(study_id,
                                                                       endemic = factor(case_when(endemic=="primary_infected"~"primary",
                                                                                                  endemic=="previously_exposed"~"previously",
                                                                                                  .default=NA),levels=c("primary","previously")),
                                                                       severe_5 = ifelse(severe_5==1,"yes","no"))) %>%
                                                 dplyr::select(-study_id,-Time),
                                               simple_anno_size = unit(2, "mm"),
                                               show_annotation_name = F,
                                               annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                                              title_gp = gpar(fontsize = 6),
                                                                              legend_height = unit(3, "mm"), 
                                                                              grid_width = unit(3, "mm")),
                                               show_legend = T,
                                               annotation_label = list(severe_5 = "Severe malaria\n(WHO)",
                                                                       endemic = "exposure"),
                                        col = list(endemic =  c("previously"= "#F1A340","primary"= "#998EC3"),#endemic2_col,
                                                   severe_5 = c("yes"="tomato","no"="grey80")),#severe_5_col),
                                        which="column"),
            
            show_column_names = F,
            column_names_gp = gpar(fontsize = 8),
            show_column_dend = TRUE,
            cluster_columns = TRUE,
            column_dend_reorder = TRUE,
            row_dend_reorder=1-rowSums(abs(norm.df)),
            cluster_row_slices = FALSE,
            row_dend_width = unit(0.5, "cm"), 
            column_dend_height = unit(0.5, "cm"), 
            raster_resize_mat = mean,
            row_title_gp = gpar(fontsize=6),
            show_row_names = TRUE,
            row_split = top25.split,
            row_gap = unit(0.05,"cm"),
            row_names_gp = gpar(fontsize = 6),
            heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                        title_gp = gpar(fontsize = 6),
                                        legend_height = unit(3, "mm"), 
                                        grid_width = unit(3, "mm")),
            height = ncol(.)*unit(1.4, "mm"),
            width = ncol(.)*unit(.14,"mm")
    ))

Figure 1H

top10up <- dap.res %>% dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>%
  mutate(up_down = ifelse(logFC>0,"up","down")) %>% 
  filter(up_down=="up") %>% 
  head(n=10) %>%
  pull(Assay)

(violin_malaria_top10 <- data.long %>% 
   inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),
              by="sample_id") %>% 
   dplyr::filter(Assay %in% c(top10up)) %>% 
   mutate(Assay = factor(Assay, levels = top10up)) %>% 
   
   ggplot(aes(x=Time, y=NPX, color=Time,fill=Time)) + 
   geom_line(aes(group=study_id), color="grey",alpha=.6,size=.2)+
   geom_violin(trim = F,alpha=.2,lwd=.25) +
   geom_boxplot(alpha=1,width=0.25,color="black",outlier.size = 0.5, fatten = 1,lwd=.25,show.legend = F) +
   facet_wrap(~Assay,ncol = 5,scales = "free_y") +
   theme_minimal() +
   labs(x="") +
   theme(axis.text.x = element_text(size=6),
         legend.position = "none") +
   scale_color_manual(values=time3_col) +
   scale_fill_manual(values=time3_col))

Figure 1I

top10down <- dap.res %>% dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>%
  mutate(up_down = ifelse(logFC>0,"up","down")) %>% 
  filter(up_down=="down") %>% 
  head(n=10) %>%
  pull(Assay)

(violin_malaria_top10_down <- data.long %>% 
   inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),
              by="sample_id") %>% 
   dplyr::filter(Assay %in% c(top10down)) %>% 
   mutate(Assay = factor(Assay, levels = top10down)) %>% 
    ggplot(aes(x=Time, y=NPX, color=Time,fill=Time)) + 
    geom_line(aes(group=study_id), color="grey",alpha=.6,size=.2)+
    geom_violin(trim = F,alpha=.2,lwd=.25) +
    geom_boxplot(alpha=1,width=0.25,color="black",outlier.size = 0.5, fatten = 1,lwd=.25,show.legend = F) +
    facet_wrap(~Assay,ncol = 5,scales = "free_y") +
    theme_minimal() +
    labs(x="") +
    theme(axis.text.x = element_text(size=6),
          legend.position = "none") +
    scale_color_manual(values=time3_col) +
    scale_fill_manual(values=time3_col))

Supplementary Table S1

##gtsummary
library(gtsummary)
subjectTable %>% 
  mutate(years_since_endemic = case_when(endemic=="primary"~NA,
                                         .default = years_since_endemic),
         
         SOFA_total = as.numeric(SOFA_total),
         endemic = str_replace(endemic,"_"," "),
         severe_5 = case_when(severe_5==1 ~ "severe",.default = "non-severe")) %>% 
  tbl_summary(include = c(sex, age, endemic, years_since_endemic, diff_acuteSample_spt_current.abs, inf_rbc_max, severe_5,SOFA_total),
              
              statistic = list(all_continuous() ~ "{median} ({min}-{max})",
                               all_categorical() ~ "{n} / {N} ({p}%)"
              ),
             # digits = all_continuous() ~ 2,
             digits = c(age ~ 0,
                        years_since_endemic ~ 0,
                        diff_acuteSample_spt_current.abs ~ 0,
                        inf_rbc_max ~ 2),
              label = c(endemic ~ "Previous malaria exposure",
                        age ~ "Age",
                        sex ~"Sex",
                        years_since_endemic ~ "Years since living in endemic area",
                        inf_rbc_max ~ "Parasitemia [%]",
                        SOFA_total ~ "SOFA scale",
                        diff_acuteSample_spt_current.abs ~ "Days since symptom onset",
                        severe_5 = "Severe malaria according to WHO criteria\n(ref WHO Guidelines for the treatment of Malaria , 3rd edition, 2015)"),
              missing = "no"
  ) %>% 
  add_n() %>% # add column with total number of non-missing observations
  modify_header(label = "**Variable**") %>% # update the column header
  bold_labels() 
Variable N N = 721
Sex 72
    female 17 / 72 (24%)
    male 55 / 72 (76%)
Age 72 39 (20-63)
Previous malaria exposure 72
    previously exposed 48 / 72 (67%)
    primary infected 24 / 72 (33%)
Years since living in endemic area 47 10 (0-33)
Days since symptom onset 69 4 (0-27)
Parasitemia [%] 72 0.80 (0.01-8.00)
Severe malaria according to WHO criteria (ref WHO Guidelines for the treatment of Malaria , 3rd edition, 2015) 72
    non-severe 62 / 72 (86%)
    severe 10 / 72 (14%)
SOFA scale 72
    0 1 / 72 (1.4%)
    1 7 / 72 (9.7%)
    2 19 / 72 (26%)
    3 16 / 72 (22%)
    4 13 / 72 (18%)
    5 8 / 72 (11%)
    6 5 / 72 (6.9%)
    9 2 / 72 (2.8%)
    12 1 / 72 (1.4%)
1 n / N (%); Median (Minimum-Maximum)

Supplementary Table S2

daps.out <- lme_res_padj %>% 
  transmute(UniProt, 
            Assay,
            estimate,
            contrast, 
            SE,
            CI = 1.96*SE,
            df,
            t.ratio,
            p.value, 
            p.adj,
            preferred_model = case_when(Assay %in% assay_better_complex_model ~ "complex",
                                        .default = "simple"))
#daps.out%>%  write_tsv(paste0(result.dir,"Supplementary_TableS2_DifferentiallyAbundantProteins.tsv"))
daps.out #%>% head()
## # A tibble: 1,427 × 11
##    UniProt Assay   estimate contrast    SE    CI    df t.ratio  p.value    p.adj
##    <chr>   <chr>      <dbl> <chr>    <dbl> <dbl> <dbl>   <dbl>    <dbl>    <dbl>
##  1 P28908  TNFRSF8     2.95 Acute -… 0.194 0.379  66.3    15.2 2.34e-23 3.33e-20
##  2 P22301  IL10        6.62 Acute -… 0.455 0.892  66.3    14.5 2.65e-22 1.38e-19
##  3 Q07325  CXCL9       4.33 Acute -… 0.293 0.574  62.9    14.8 3.86e-22 1.38e-19
##  4 P04233  CD74        2.20 Acute -… 0.134 0.263  52.0    16.4 3.41e-22 1.38e-19
##  5 P20333  TNFRSF…     2.66 Acute -… 0.185 0.363  66.3    14.4 5.00e-22 1.43e-19
##  6 P19320  VCAM1       1.48 Acute -… 0.105 0.207  66.3    14.0 1.78e-21 4.22e-19
##  7 P14555  PLA2G2A     4.41 Acute -… 0.243 0.476  41.1    18.2 2.91e-21 5.94e-19
##  8 O95998  IL18BP      2.41 Acute -… 0.177 0.346  66.3    13.6 7.29e-21 1.30e-18
##  9 P09603  CSF1        1.66 Acute -… 0.123 0.242  66.3    13.4 1.37e-20 2.18e-18
## 10 P15291  B4GALT1     1.65 Acute -… 0.119 0.233  59.9    13.9 2.12e-20 2.52e-18
## # ℹ 1,417 more rows
## # ℹ 1 more variable: preferred_model <chr>
daps.out %>% filter(p.adj <=0.01, preferred_model=="simple", estimate<=-1)
## # A tibble: 16 × 11
##    UniProt Assay  estimate contrast     SE    CI    df t.ratio  p.value    p.adj
##    <chr>   <chr>     <dbl> <chr>     <dbl> <dbl> <dbl>   <dbl>    <dbl>    <dbl>
##  1 Q4KMG0  CDON      -1.32 Acute -… 0.0779 0.153  38.1  -17.0  2.36e-19 2.11e-17
##  2 Q9NQ79  CRTAC1    -1.07 Acute -… 0.104  0.204  45.1  -10.3  2.08e-13 3.70e-12
##  3 P21583  KITLG     -1.77 Acute -… 0.187  0.366  54.7   -9.44 4.38e-13 7.11e-12
##  4 O14788  TNFSF…    -2.34 Acute -… 0.240  0.470  47.9   -9.75 5.97e-13 9.57e-12
##  5 Q9UBX1  CTSF      -1.27 Acute -… 0.137  0.269  48.7   -9.22 2.96e-12 3.87e-11
##  6 O60911  CTSV      -1.35 Acute -… 0.163  0.319  66.3   -8.27 8.50e-12 9.86e-11
##  7 P23280  CA6       -1.90 Acute -… 0.223  0.438  47.7   -8.51 4.02e-11 4.09e-10
##  8 Q8TDL5  BPIFB1    -2.18 Acute -… 0.288  0.564  49.6   -7.59 7.57e-10 5.58e- 9
##  9 Q8WTU2  SSC4D     -1.75 Acute -… 0.232  0.454  41.0   -7.55 2.84e- 9 1.78e- 8
## 10 O14793  MSTN      -1.12 Acute -… 0.151  0.296  41.4   -7.40 4.31e- 9 2.56e- 8
## 11 Q15166  PON3      -1.07 Acute -… 0.162  0.318  46.1   -6.62 3.39e- 8 1.75e- 7
## 12 Q9UNE0  EDAR      -1.46 Acute -… 0.226  0.444  51.2   -6.44 4.12e- 8 2.09e- 7
## 13 P06850  CRH       -1.07 Acute -… 0.205  0.401  48.5   -5.25 3.36e- 6 1.19e- 5
## 14 P22466  GAL       -1.08 Acute -… 0.230  0.450  47.5   -4.68 2.38e- 5 7.31e- 5
## 15 Q92583  CCL17     -1.28 Acute -… 0.323  0.633  66.3   -3.97 1.81e- 4 4.78e- 4
## 16 Q9HCM2  PLXNA4    -1.33 Acute -… 0.352  0.690  66.3   -3.79 3.27e- 4 8.20e- 4
## # ℹ 1 more variable: preferred_model <chr>

comp## Supplementary Figure 1 ### Figure S1A

tmp <- data.long %>% 
  distinct(sample_id) 
hm_mat <- tmp %>% 
  separate(sample_id, into = c("study_id","Time"),sep = "\\|",remove = T) %>% 
   mutate(Time = factor(Time, levels=c("Acute","D10","M12")),
          dummy = Time) %>% 
  
  group_by(study_id) %>% 
  mutate(n = n()) %>% 
  arrange(-n) %>% 
  ungroup() %>% 
  
  pivot_wider(names_from = Time, values_from = dummy) %>% 
  dplyr::select(-n) %>% 
  column_to_rownames("study_id") %>% 
  relocate(Acute,D10,M12) %>% 
  t() 

(sample_overlap_hm <- hm_mat %>% 
  Heatmap(row_names_gp = gpar(fontsize=6),
          show_column_names = F,
          na_col = "white",
          column_title_gp = gpar(fontsize=6),
          row_names_side = "left",
          column_names_gp = gpar(fontsize=6),
          column_names_rot = 45,
          show_heatmap_legend = F,
          column_split = data.frame(study_id = colnames(hm_mat)) %>% 
            left_join(subjectTable %>% 
                        transmute(study_id, endemic) %>% 
                        bind_rows(
                          tibble(study_id = c("2014003","2012PT12"),
                                 endemic = c("primary_infected","primary_infected")))) %>%  
            transmute(endemic= factor(endemic, levels=c("primary_infected","previously_exposed"), labels= c("primary infected","previously exposed"))),
          row_title_gp = gpar(fontsize=6),
          
          rect_gp = gpar(col = "white", lwd = .5),
          width = ncol(.)*unit(1, "mm"), 
          height = nrow(.)*unit(2, "mm"),
          #height = ncol(.)*unit(1.4, "mm"),
          #  width = ncol(.)*unit(.5,"mm"),
          border_gp = gpar(col = "black", lty = .9),
          col =  time3_col,
          top_annotation = HeatmapAnnotation(df = data.frame(study_id = colnames(.)) %>% 
                                               left_join(subjectTable %>% 
                                                           transmute(study_id, endemic) %>% 
                                                           bind_rows(
                                                             tibble(study_id = c("2014003","2012PT12"),
                                                                    endemic = c("primary_infected","primary_infected"))
                                                             )) %>% 
                                                           dplyr::select(-study_id),
                                                         simple_anno_size = unit(3, "mm"),
                                                         show_annotation_name = F,
                                                         show_legend = F,
                                                         col = list(endemic =  endemic2_col),
                                                         which="column"))
)

Figure S1B

(acute_exposure_volcano <- lme_res %>% 
  unnest(cols=posthoc.time_exposure) %>% 
  filter(contrast %in%c("Acute primary_infected - M12 primary_infected",
                    "Acute previously_exposed - M12 previously_exposed")) %>% 
  ungroup() %>% 
  group_by(contrast) %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
         FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
  arrange(p.adj) %>% 
  transmute(Assay,contrast, estimate,SE,df,t.ratio, p.value, p.adj, FDR,
            color = case_when(FDR==T & contrast=="Acute primary_infected - M12 primary_infected" ~ "primary_infected",
                              FDR==T & contrast=="Acute previously_exposed - M12 previously_exposed" ~ "previously_exposed",
                              .default = NA
                              ),
            contrast = factor(contrast, levels=c("Acute primary_infected - M12 primary_infected",
                                                 "Acute previously_exposed - M12 previously_exposed")),
            label_4_complex_better = case_when(Assay %in% assay_better_complex_model & contrast=="Acute primary_infected - M12 primary_infected" ~ Assay,
                                               .default = NA)) %>% 
  
  ggplot(aes(y=fct_reorder(Assay, estimate), x=estimate, color=color)) +
 
  scale_color_manual(values=endemic2_col, na.value = "grey",breaks = c("primary_infected","previously_exposed")) +
  labs(color=NULL,
       x="Estimated difference +- 95% CI at acute for\nprimary infected and previously exposed individuals\ncompared to M12",#"Estimated difference (NPX) at acute compared to healthy-state at M12",
       y="ranked proteins") +
  geom_errorbar(aes(xmin=estimate - 1.96*SE, 
                    xmax=estimate + 1.96*SE),
                linewidth=.2,    # Thinner lines
                width=.2,
                alpha=.1) +
    geom_point(alpha=0.7,size=.5, shape=16) +
   geom_text_repel(aes(label=label_4_complex_better),
                    show.legend = F,
                   color="black",
                    vjust = .5,
                    hjust = 1,
                    nudge_x = .75,
                    direction = "y",
                    size=1,
                   #label.size = .1,
                    segment.size = 0.2,
                            segment.alpha=.1,
                    max.overlaps = 16) +
  geom_vline(xintercept = 0, lty=2, alpha=.6) +
  theme_minimal())

lme_res_expo <- lme_res %>% 
  unnest(cols="posthoc.time_exposure") %>% 
  filter(contrast=="Acute primary_infected - Acute previously_exposed") %>% 
  ungroup() %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
                  FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
  filter(FDR==T) %>% 
  arrange(-estimate) 

assays_significant_different_at_acute_exp <- lme_res_expo %>% 
  pull(Assay)

Figure S1C

library(eulerr)

plot(euler(list("acute" = lme_res_padj %>% filter(FDR==T) %>% pull(Assay),
                  "exposure"= lme_res_expo %>% filter(FDR==T) %>% pull(Assay))),# assays_significant_different_at_acute_exp)),#lme_res_expo %>% filter(FDR==T) %>% pull(Assay))),
        fills = c("#C51B7D",
                  "white"),
       quantities = TRUE,
       lty = 1,#1:3,
       fontsize=1,
       labels = list(fontsize=5),
       shape = "ellipse",adjust_labels = T)

acut_exposure_intersect <- intersect(assays_significant_different_at_acute_exp,#lme_res_expo %>% filter(FDR==T) %>% pull(Assay),
                                     lme_res_padj %>% filter(FDR==T) %>% pull(Assay))

Figure S1D

df <- lme_res %>% 
  filter(Assay %in% assays_significant_different_at_acute_exp) %>% 
  mutate(Assay = factor(Assay, levels=assays_significant_different_at_acute_exp)) %>% 
  unnest(cols=posthoc.time_exposure) %>% 
  filter(contrast %in%c("Acute primary_infected - M12 primary_infected",
                        "Acute previously_exposed - M12 previously_exposed")) %>% 
  ungroup() %>% 
  mutate(color = case_when(contrast=="Acute primary_infected - M12 primary_infected" ~ "primary_infected",
                           contrast=="Acute previously_exposed - M12 previously_exposed" ~ "previously_exposed",
                              .default = NA
                              )) %>%
 # rownames_to_column("rownumbers") %>% 
  #filter(Assay%in%c("CXCL10","IFNG","CXCL9","TNFSF13B")) %>% 
  dplyr::select(-(lme.res.simple:posthoc.time)) 
require(ggtext)
(acute_exposure_significant <- df %>% 
    mutate(x.label = paste("<span style = 'color: ",
                         ifelse(Assay %in% acut_exposure_intersect , "pink", "black"),
                         ";'>",
                         Assay,
                         "</span>", sep = ""),
         x.label = fct_reorder(x.label, as.character(Assay))) %>%
  ggplot(aes(x=x.label, y=estimate, color=color)) +
  geom_point(shape=16,size=.5) +
  scale_color_manual(values = endemic2_col, breaks = c("primary_infected","previously_exposed")) +

  geom_hline(yintercept = 0, lty=2, alpha=.3) +
 #  ggrepel::geom_text_repel(show.legend = F, color="black") +
  geom_errorbar(aes(ymin=estimate - 1.96*SE, 
                    ymax=estimate + 1.96*SE),
                linewidth=.2,    # Thinner lines
                width=.2,
                alpha=.5) +
  labs(x=NULL,
       color = NULL,
       y="Estimated difference +- 95% CI at acute for\nprimary infected and previously exposed individuals\ncompared to M12\n") +
      theme(axis.text.x = element_markdown(angle = 90, hjust = 1,vjust=0.5, size=6),
            legend.position = "top")
)

Supplementary Figure 2

related to main Figure 2

Figure S2A

supplementary_covariates.res <- data.long %>% 
  inner_join(sampleTable_simple, by="sample_id") %>% 
  inner_join(subjectTable, by="study_id") %>% 
  filter(Time != "D10") %>% 
  mutate(Time = factor(Time, levels=c("Acute","M12"))) %>% 
  group_by(Assay) %>% 
  nest() %>% 
  mutate(lme.res = purrr::map(data, ~ lmerTest::lmer(NPX ~ Time + year_inclusion + sex + age + endemic + inf_rbc_max + (1|study_id), REML = F,
                                           data = .)),
         lme.tidy = purrr::map(lme.res, ~ broom.mixed::tidy(.)))

supplementary_covariates.res_ <- supplementary_covariates.res %>% 
  unnest(cols = lme.tidy) %>% 
  filter(effect =="fixed", 
         term!="(Intercept)") %>% 
  #filter(term != "Residuals") %>% 
  mutate(term = case_when(term=="sexmale"~"sex",
                          term=="endemicprimary_infected"~"endemic",
                          term=="TimeM12"~"Time",
                          .default = term)) %>% 
  group_by(term) %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr")
  ) %>%
  mutate(term.col = case_when(p.adj > 0.01 ~ NA,
                              p.adj <= 0.01 ~ term))

cov.colors <- c("Time" = time3_col[[1]],setNames(brewer.pal(7,"Dark2")[c(1:3,5:8)], c("sex","endemic","age","year_inclusion","inf_rbc_max")))

counts.fdr <- supplementary_covariates.res_ %>% 
  filter(p.adj <= 0.01) %>% 
  group_by(term) %>% 
  count(sort = T)

(data.aov.plot <- supplementary_covariates.res_ %>% 
    mutate(term = factor(term, levels=counts.fdr$term)) %>% 
    ggplot(aes(x=term, y= -log10(p.adj))) + 
    geom_jitter(aes(color=term.col), show.legend = F,size=.25,alpha=.7,shape=16) +
    ggrepel::geom_text_repel(data= . %>% group_by(term) %>% slice_max(n=5,order_by = -log10(p.adj)), 
                             aes(label=Assay), 
                             show.legend = F,force = .5, nudge_y = .25,
                             segment.size=0.2,
                            segment.alpha=.1,
                             size=1,
                             max.overlaps = 15, color="gray45") +
    geom_hline(yintercept=-log10(0.01), 
               linetype = 3) +
    scale_color_manual(values = cov.colors) +
    
    geom_text(data=counts.fdr,aes(x=term, y=-1.2, label=n, color=term), show.legend = F) +
    scale_x_discrete(labels=c("age" = "Age",
                              "year_inclusion" = "Year\nof\nsampling",
                              "sex" = "Sex",
                              "endemic" = "Previous\nexposure",
                              "inf_rbc_max" = "Parasitemia",
                              "Time" = "Infection\n(Acute vs convalescence)")) +
    theme_minimal() +
    labs(x=NULL, 
         color=NULL) +
    theme())

Figure S2B

n2show <- 3
(anova.sex.plot <- supplementary_covariates.res_ %>%
    filter(term=="sex") %>%
    arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    ggplot(aes(x=Time, y=NPX, fill=as.character(sex))) +
    geom_boxplot( fatten = 1,lwd=.25,outlier.size = 0.5) +
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(x=NULL,
         fill="Sex") +
    scale_fill_manual(values = sex2_col))

(anova.endemic.plot <- supplementary_covariates.res_ %>%
    filter(term=="endemic") %>%
    arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    ggplot(aes(x=Time, y=NPX, fill=as.character(endemic))) +
    geom_boxplot(fatten = 1,lwd=.25,outlier.size = 0.5) +
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(x=NULL,
         fill="Previous exposure") +
    scale_fill_manual(values = endemic2_col))

(anova.year_inclusion.plot <- supplementary_covariates.res_ %>%
    filter(term=="year_inclusion") %>% arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    ggplot(aes(x=as.numeric(year_inclusion),y=NPX,color=Time)) +
    geom_point(size=.5) +
    geom_smooth(linewidth=0.4,
                show.legend = F) +
    scale_x_continuous(limits = c(2011,2021),breaks = c(2011,2016,2021)) + 
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(x="Year of inclusion",
      color="Sample time point") +
    scale_color_manual(values = time3_col))

(anova.age.plot <- supplementary_covariates.res_ %>%
    filter(term=="age") %>% arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    ggplot(aes(x=as.numeric(age),y=NPX,color=Time)) +
    geom_point(size=.5) +
    geom_smooth(linewidth=0.4,
                show.legend = F) +
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(title="",
         x="Age (years)",
         color="Sample time point") + 
    scale_color_manual(values = time3_col)
)

(anova.inf_rbc_max.plot <- supplementary_covariates.res_ %>%
    filter(term=="inf_rbc_max") %>% arrange(p.adj) %>% 
    head(n=n2show) %>% 
    unnest(cols = data) %>% 
    filter(Time=="Acute") %>% 
    ggplot(aes(x=as.numeric(inf_rbc_max),y=NPX,color=as.numeric(inf_rbc_max))) +
    geom_point(size=.5) +
    geom_smooth(aes(color=..x..),
                linewidth=0.4,
                show.legend = F) +
    facet_wrap(~Assay, scales = "free_y") +
    theme_minimal() +
    labs(title="",
         x="Parasitemia, infected erythrocytes [%]",
         color="Parasitemia [%]") + 
    scale_color_gradient(low="grey",high="darkred")
  #scale_color_manual(values = time3_col)
)

(anova.panel <- (anova.inf_rbc_max.plot / 
                   anova.endemic.plot /
                   anova.year_inclusion.plot / 
                   anova.sex.plot/
                   anova.age.plot))

Figure S2C

lme_res.d10 <- data_nested %>% 
  mutate(lme.res = purrr::map(data, ~ lmerTest::lmer(NPX ~ Time + exposure + (1|study_id), REML = F,
                                           control = lme4::lmerControl(check.conv.singular = "ignore"),
                                           data = .x %>% dplyr::filter(Time!="Acute"))),
         posthoc.time = purrr::map(lme.res, ~ summary(contrast(emmeans(., ~ Time), method = "pairwise")) %>% tibble())
        )

lme_res.d10_padj <- lme_res.d10 %>% 
  unnest(cols="posthoc.time") %>% 
  filter(contrast=="D10 - M12") %>% 
  ungroup() %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
         FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
  arrange(p.adj)
acut_d10_list <- list("Acute"=c(lme_res_padj %>% filter(FDR==TRUE, estimate>1) %>% pull(Assay)),
                      "D10" = c(lme_res.d10_padj %>% filter(FDR==TRUE, estimate>1) %>% pull(Assay)))

## venn plot with overlapp numbers
(venn.DAP.acute.d10 <- ggvenn::ggvenn(acut_d10_list,
                                      show_percentage = F,
                                      fill_color = as.character(time3_col[c(1,2)]), 
                                      stroke_size = 0.5,
                                      set_name_size = 2,
                                      text_size = 2,
                                      auto_scale = F,
                                      show_elements = F) +
    theme(plot.title = element_text(hjust = 0.5),
          plot.subtitle = element_text(hjust = 0.5),
          text = element_text(size=6),
          strip.text = element_text(size=6),
          plot.tag = element_text(size=6)))

Figure S2D

(d10_malaria_volcano <-  lme_res.d10_padj %>% 
   arrange(p.adj, abs(estimate)) %>% 
   ggplot(aes(x=estimate, y=-log10(p.adj), color=FDR)) +
   geom_point(alpha=0.7,size=.5, shape=16) +
   ggrepel::geom_text_repel(data = . %>% filter(FDR ==TRUE, abs(estimate) >1),
                            aes(label = Assay), color="black",
                            force        = 0.5,
                            direction    = "both",
                            segment.size = 0.2,
                            segment.alpha=.1,
                            show.legend = F,
                            size=1.5,
                            max.overlaps = 16,
                            box.padding = unit(0.2, "lines"),
                            point.padding = unit(0.5, "lines"),
                            segment.color = 'grey50'
   ) +
   theme_minimal() +
   geom_vline(xintercept = c(-1, 1), linetype = "dotted", size = .5) +
   geom_hline(yintercept = -log10(0.01), linetype = "dotted", size = .5) + 
   scale_x_continuous(breaks=c(-2.5,-1.0,0.0,1.0,2.5,5.0),limits = c(-2.5,5)) +
   labs(x="Estimated difference (NPX)",
        y="-log10(adj. p-value)",
        subtitle= "D10 after disease vs. convalescence",
        caption=paste0("DAP: ",lme_res.d10_padj %>% filter(FDR==TRUE) %>% nrow(),"\n",
                       "DAP up: ",lme_res.d10_padj %>% filter(FDR==TRUE,estimate>0) %>% nrow(),"\n",
                       "DAP FC>1: ",lme_res.d10_padj %>% filter(FDR==TRUE,estimate>1) %>% nrow(),"\n")) +
   theme(legend.position = "none",
         text = element_text(size=6)) +
   scale_color_manual(values= c(time3_col[[3]],time3_col[[2]])))

Figure S2E

(acute_d10_comp <- dap.res %>% 
   ungroup() %>% 
   arrange(-logFC) %>% 
   mutate(row_id=row_number()) %>% 
   mutate(Assay_orders = factor(as.factor(row_id), levels = row_id, labels = Assay),
          Assay_orders = row_id) %>% 
   left_join(lme_res.d10_padj, by=c("Assay","UniProt"),suffix = c(".acute",".d10")) %>% 
   mutate(d = ifelse(estimate>logFC,T,F),
          d_dbl = abs(logFC-estimate)) %>%
   
   ggplot(aes(x=Assay_orders)) +
   geom_segment(data = . %>% filter(p.adj.d10<=0.01, estimate >1), 
                aes(group=Assay, x = Assay_orders, xend = Assay_orders,yend = logFC, y=estimate, color=d), lwd=0.1) +
   geom_point(aes(y=logFC), size=.05, alpha=1, color=time3_col[[1]]) +
   geom_point(data = . %>% filter(p.adj.d10 <=0.05), aes(y=estimate),color=time3_col[[2]], size=.05,alpha=1) +
   
   ggrepel::geom_text_repel(data = . %>% filter(p.adj.d10<=0.05, estimate >1) %>%
                              filter(d==TRUE) %>% 
                              slice_max(order_by = d_dbl,n=10),
                            aes(label = Assay,y=estimate, color=d), 
                            force        = 0.5,
                            direction    = "both",
                            segment.size = 0.1,
                            min.segment.length = 1,
                            nudge_x = 1,
                            show.legend = F,
                            size=2,
                            max.overlaps = 16,
                            box.padding = unit(0.1, "lines"),
                            point.padding = unit(0.5, "lines"),
                            segment.color = 'black') + 
   scale_color_manual(values=c("FALSE" = "navy","TRUE"="red"), labels=c("lower at D10","higher at D10")) +
   geom_hline(yintercept = 0,linetype=3, color=time3_col[[3]]) +
   scale_x_continuous(expand=c(.1,0),
                      trans = "sqrt") + 
   labs(color = NULL,
        x="Proteins ranked by estimated difference (NPX)\nat acute malaria",
        y="Estimated difference (NPX)") +
   theme_minimal() +
   theme(text = element_text(size=6)) 
)

Supplementary Figure 3

related to main Figure 1

Figure S3A

require(clusterProfiler)

length(unique(data$UniProt)) ## 1463
## [1] 1463
entrez_uniprot_name_mapping <- clusterProfiler::bitr(unique(data.long$UniProt), 
                                                     fromType="UNIPROT",
                                                     toType=c("SYMBOL","ENTREZID"),
                                                     OrgDb="org.Hs.eg.db") %>% 
  dplyr::rename(UniProt = UNIPROT,
                Symbol = SYMBOL,
                Entrez = ENTREZID) 

ranks_entrez <- entrez_uniprot_name_mapping %>% 
  inner_join(dap.res %>% ungroup() %>% filter(p.adj<=0.01), by="UniProt") %>%
  arrange(-logFC) %>%
  dplyr::select(Entrez, logFC) %>% deframe()

### KEGG
## all explore proteins
universe.proteins <- data.long %>% distinct(Assay,UniProt) %>% inner_join(entrez_uniprot_name_mapping,by="UniProt")
## prep enrich input
sig_proteins_df <- entrez_uniprot_name_mapping %>% 
  inner_join(dap.res %>% ungroup(), by="UniProt") %>% filter(p.adj <= 0.01) 

# From significant results, we want to filter on log2fold change
sig_proteins <- sig_proteins_df$logFC
# Name the vector
names(sig_proteins) <- sig_proteins_df$Entrez
# omit NA values
sig_proteins <- na.omit(sig_proteins)
# filter on min log2fold change (log2FoldChange > 1)
sig_proteins <- names(sig_proteins)[abs(sig_proteins) > 1]


cp_KEGG.res <- enrichKEGG(
  sig_proteins,
  organism = "hsa",
  #keyType = "UNIPROT",
  pvalueCutoff = 1,
  pAdjustMethod = "BH",
  universe = universe.proteins$Entrez,
  minGSSize = 10, 
  maxGSSize = 500,
  qvalueCutoff = 1,
  use_internal_data = F
)

#data.frame(cp_KEGG.res)


(cp.kegg.acutefc1 <- data.frame(cp_KEGG.res) %>%
    separate(GeneRatio, into=c("hit","total"),sep="/",remove = F,convert=TRUE) %>% 
    head(10) %>% 
    mutate(ratio = hit/total) %>% 
    
    ggplot(aes(x=fct_reorder(Description, -ratio,.desc = TRUE), y=ratio)) +
    geom_bar(stat = "identity", width = 0.05) +
    geom_point(aes(color=-log10(p.adjust))) +#size = 3) +
    geom_text(aes(label=hit),size=2, nudge_y = .01)+
    scale_y_continuous(expand = c(0.02,0), trans = "pseudo_log") +
    scale_x_discrete(expand = c(-0.01, 1)) +
    theme_minimal() +
    theme(text = element_text(size=6 ),
          axis.text.y = element_text(size = 6),
          axis.ticks.x = element_blank()) +
    coord_flip() +
    guides(size = guide_legend(reverse=TRUE)) +
    labs(title = "KEGG_2021_Human",
         x= NULL,
         y = "ratio [protein/total]",
         size="Protein\noverlapp",
         color=expression("-Log"[10]*"(p.adj)"))
  )

Figure S3B

require(pathview)

sig_proteins_df <- entrez_uniprot_name_mapping %>% 
  inner_join(dap.res %>% ungroup(), by="UniProt") %>% filter(p.adj <= 0.01, abs(logFC)>1) 


logFC <- sig_proteins_df$logFC
names(logFC) <- sig_proteins_df$Entrez
pv.out <- pathview(gene.data = logFC, 
                   pathway.id = "hsa04060", 
                   species = "hsa", 
                   limit = list(gene=5, cpd=1),
)

knitr::include_graphics("hsa04060.pathview.png")
KEGG

KEGG

Figure 2

Potential sources and functionalities of plasma proteins during acute malaria

Figure 2A

secretome_location_dap <- dap.res %>% 
  dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>% 
  inner_join(hpa_24.0, by=c("Assay"="gene","UniProt"="uniprot")) %>% 
  mutate(secretome_location_tissue_spec = case_when(secretome_location=="Not secreted"~ paste0(secretome_location," - ",rna_tissue_specificity),
                                                   .default = secretome_location)) %>% 
  group_by(secretome_location_tissue_spec) %>% 
  count(sort = TRUE) 

## change order
secretome_location_dap.order <- secretome_location_dap %>% pull(secretome_location_tissue_spec)
secretome_location_dap.order <- c("Secreted to blood","Intracellular and membrane","Secreted in other tissues","Secreted to extracellular matrix",
                                  "Secreted to digestive system", "Secreted in brain", "Secreted - unknown location", "Secreted in female reproductive system",
                                  "Secreted in male reproductive system",
                                  "Not secreted - Tissue enriched", "Not secreted - Tissue enhanced","Not secreted - Group enriched", "Not secreted - Low tissue specificity")

## plot everything
(hpa.protein.origin.overview <- secretome_location_dap %>% 
    ungroup() %>% 
    mutate(secretome_location_tissue_spec = factor(as.factor(secretome_location_tissue_spec), levels=rev(secretome_location_dap.order))) %>% 
    ggplot(aes(x=secretome_location_tissue_spec,y=n,fill=secretome_location_tissue_spec)) +
    geom_col(width = 0.5) +
    geom_text(aes(label=n),size=2, nudge_y = -.2) +
    coord_flip() +
    scale_y_continuous(trans="pseudo_log",name = NULL, sec.axis = sec_axis(~.,labels = NULL,breaks = NULL, name = "Number of DAPs"),
                       #expand=c(0,.15)
                       expand=c(0,0)

                       ) +
    theme_bw() +
    theme(axis.text.y = element_text(size = 6),
          axis.text.x = element_text(size = 6),
          legend.text=element_text(size=6),
          legend.title=element_text(size=6),
          plot.title = element_text(size=6))+
    scale_fill_manual(values=secretome_location_tissue_spec_cols,
                      limits = secretome_location_dap.order) +
    labs(fill="Protein\norigin\nby HPA",
         x=NULL))

temp.df <- dap.res %>% 
  dplyr::filter(FDR==TRUE) %>%
  arrange(desc(abs(logFC)),desc(p.adj)) %>% 
  inner_join(hpa_24.0, by=c("Assay"="gene","UniProt"="uniprot")) %>% 
  mutate(secretome_location_tissue_spec = case_when(secretome_location=="Not secreted"~ paste0(secretome_location," - ",rna_tissue_specificity),
                                                   .default = secretome_location))

Figure 2B

df1 <- temp.df %>% 
  transmute(Assay, logFC, p.adj, direction,secretome_location_tissue_spec, secretome_function) 

df2 <- df1 %>% 
  group_by(secretome_location_tissue_spec) %>% 
  summarise(atlas_name_count = n()) %>% 
  left_join(
    df1 %>% 
      group_by(secretome_location_tissue_spec, secretome_function, direction) %>% 
      summarise(function_name_count = n()),
    by="secretome_location_tissue_spec") %>% 
  left_join(
    df1 %>% group_by(secretome_location_tissue_spec, secretome_function, direction) %>% 
      summarise(median_logFC = median(logFC)),
    by=c("secretome_location_tissue_spec", "secretome_function","direction"))

(hpa.function.bubbleplot <- df2 %>% 
    filter(!secretome_location_tissue_spec %in% c("NULL", "NA","no mapping"),
           !secretome_function %in% c("NULL")) %>% 
    mutate(secretome_function = case_when(is.na(secretome_function) ~ "No secretome function",
                                          .default = secretome_function)) %>% 
    mutate(secretome_location_tissue_spec = factor(as.factor(secretome_location_tissue_spec),
                                                  levels=rev(secretome_location_dap.order))) %>% 
    ggplot(aes(x=median_logFC,
               y= fct_reorder2(secretome_function, 
                               atlas_name_count,
                               function_name_count,.desc = F))) +
    geom_point(aes(size=function_name_count, color=secretome_location_tissue_spec), show.legend = T) +
    geom_vline(xintercept = 0,linetype=1) +
    geom_text(aes(label = function_name_count),
              size=2, color="grey20",show.legend = F, parse = F) +
    labs(x="median estimated difference (NPX)",
         y=NULL,
         title = "Number DAPs per HPA function",
         size="Number of proteins",
         caption="Size: number of proteins",
         color = "HPA source") +
    scale_color_manual(values=secretome_location_tissue_spec_cols, limits = secretome_location_dap.order) +
    scale_x_continuous(trans = "pseudo_log") +
    scale_y_discrete(expand = c(0,1))+
    guides(size = "none") +
    theme_minimal() +
    scale_size(range=c(3,6)) +
    theme(text = element_text(size=6))
)

Figure 2C

(acute_malaria_hpa_source <- temp.df %>% 
    right_join(top25 %>% transmute(Assay,logFC)) %>% 
    
    ggplot(aes(x=fct_reorder(Assay,logFC), y=logFC, color=secretome_location_tissue_spec)) +
    geom_point(show.legend = TRUE,size=1) +
    geom_col(width = .05,show.legend = F) +
    scale_y_continuous(sec.axis = sec_axis(~.,labels = NULL,breaks = NULL, name = "Top25 DAP")) +
    coord_flip() +
    theme_minimal() +
    theme(plot.title.position = "plot",
          axis.text.y = element_text(size = 4),
          axis.text.x = element_text(size = 6),
          axis.title.x = element_text(size = 6),
          panel.grid.major = element_blank()) +
    labs(color="HPA source",
         x="",
         y="Estimated difference (NPX)",
         title = "Protein source according to Human Protein Atlas") +
    scale_color_manual(values=secretome_location_tissue_spec_cols,
                       limits=secretome_location_dap.order))

Supplementary Figure 4

related to main Figure 2

Figure S4A

malaria.daps.hpa23 <- dap.res %>% 
  arrange(desc(abs(logFC)),desc(p.adj)) %>% 
  filter(p.adj<=0.01) %>% 
  arrange(-logFC) %>% 
  left_join(hpa_24.0,by=c("UniProt" = "uniprot")) %>% 
  ungroup()

## abundant proteins in acute malaria plasma, not immune cell specific nor predicted to be secreted
## => tissue leakage??
malaria.tissue.leakage <- malaria.daps.hpa23 %>% 
  filter(is.na(rna_blood_cell_specificity) | 
           rna_blood_cell_specificity=="Not detected in immune cells", 
         rna_tissue_specificity %in% c("Tissue enriched"),#,"Group enriched","Tissue enhanced"),
         secretome_location =="Not secreted",
         logFC >0)#.5)

secretome.location.order <- c("Secreted to blood","Intracellular and membrane","Secreted in other tissues","Secreted to extracellular matrix",
                                  "Secreted to digestive system", "Secreted in brain", "Secreted - unknown location", "Secreted in female reproductive system",
                                  "Secreted in male reproductive system","Not secreted")
secretome.fun.count <- malaria.daps.hpa23 %>% group_by(secretome_function) %>% count() %>% arrange(-n) %>% pull(secretome_function)

df <- malaria.daps.hpa23 %>% 
  filter(logFC>=0) %>% 
  transmute(Assay,
            direction,
            secretome_location = factor(secretome_location, levels= secretome.location.order),
            secretome_function = factor(secretome_function, levels = secretome.fun.count),
            rna_blood_cell_specificity,
            rna_tissue_specificity = factor(rna_tissue_specificity, levels = c("Tissue enriched",
                                                                               "Group enriched",
                                                                               "Tissue enhanced",
                                                                               "Low tissue specificity",
                                                                               "Not detected")),
            tissue_enriched = factor(case_when(rna_blood_cell_specificity=="Not detected in immune cells" & rna_tissue_specificity == "Tissue enriched" & secretome_location =="Not secreted" & direction == "up" ~"1",
                                               .default = "0"), 
                                     levels=c("1","0"), 
                                     labels=c("1"="Tissue specific and not secreted",
                                              "0"="Less tissue specific")
            ))
(dap.origin.w.tl <- df %>%
    ggplot(aes(axis1 = secretome_location,
               axis2 = secretome_function,
               axis3 = rna_tissue_specificity,
               axis4 = tissue_enriched
    )) +
    geom_alluvium(aes(fill = secretome_location),width = 1/12,geom = "flow", lode.guidance = "forward",) +
    geom_stratum(aes(fill=secretome_location),width = 1/12) +
    ggfittext::geom_fit_text(stat = "stratum", aes(label = after_stat(stratum)),min.size = 1, show.legend = F) +
    scale_x_discrete(limits = c("Secretome\nlocation","Secretome\nfunction", "Tissue specificity\n(based on gene expression)","Tissue specificity\n(overall)"), expand = c(.2, .05)) +
    theme_bw() +
    scale_fill_manual(values= c(secretome_location_cols,"NA"="red","SPEC"="white")) +
    labs(title = "Abundant proteins in blood during acute malaria",
         y= "Number of proteins") +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          axis.ticks.x = element_blank(),
          panel.background = element_rect(colour = "black", size=0.5, fill=NA),
          panel.border = element_rect(size = 0.2, colour = "grey"),
          legend.position = "none"))

Figure S4B

(alluvial_proteinorigin <- df %>%
   ggplot(aes(axis1 = secretome_location,
              axis3 = rna_tissue_specificity,
              axis4 = tissue_enriched
   )) +
   geom_alluvium(aes(fill = tissue_enriched),width = 1/12,geom = "flow", lode.guidance = "forward",) +
   geom_stratum(aes(fill=secretome_location),width = 1/12) +
   ggfittext::geom_fit_text(stat = "stratum", aes(label = after_stat(stratum)),min.size = 1, show.legend = F) +
   
   scale_x_discrete(limits = c("Secretome\nlocation",#"Secretome\nfunction", 
                               "Tissue specificity\n(based on gene expression)","Tissue specificity\n(overall)"), expand = c(.2, .05)) +
   theme_bw() +
   scale_fill_manual(values= c("Tissue specific and not secreted"="red","Less tissue specific"="grey90")) +
   labs(title = "Potential tissue leakage proteins in blood during acute malaria",
        y= "Number of proteins") +
   theme(panel.grid.major = element_blank(),
         panel.grid.minor = element_blank(),
         axis.ticks.x = element_blank(),
         panel.background = element_rect(colour = "black", size=0.5, fill=NA),
         panel.border = element_rect(size = 0.2, colour = "grey"),
         legend.position = "none"))

malaria.tissue.leakage <- df %>% filter(tissue_enriched=="Tissue specific and not secreted") %>% pull(Assay)

Figure S4C

### tissue expression¨
mat <- hpa.tissue %>% 
  filter(gene_name %in% c(malaria.tissue.leakage)) %>% 
  pivot_wider(names_from = tissue, values_from = n_tpm, values_fn = median) %>% 
  dplyr::select(-gene) %>% 
  column_to_rownames("gene_name")

mat1 <- mat %>% 
  t() %>% 
  scale() %>% 
  scales::rescale(to=c(0,1)) %>% 
  t() 

(hm.tissue.leakage <- mat1 %>% 
    t() %>% 
    Heatmap(row_names_gp = gpar(fontsize=6),
            column_names_gp =  gpar(fontsize=4),
            cluster_rows = T,
            cluster_columns = T,
            name="scaled\nnTPM",
            column_title = "High abundant plasma proteins\n 'Tissue specific and not secreted'",
            column_title_gp = gpar(fontsize=6),
            col = circlize::colorRamp2(c(min(mat1),max(mat1)), c("white","red")),
            column_dend_height = unit(5,"mm"),
            row_dend_width = unit(5,"mm"),
            heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                        title_gp = gpar(fontsize = 6),
                                        legend_height = unit(20, "mm")))
)

Figure S4D

(tissue.leakage.violine <- data.long %>% 
   inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),
              by="sample_id") %>% 
   dplyr::filter(Assay %in% c(malaria.tissue.leakage),
                 Time!="D10") %>% 
   mutate(Assay = factor(Assay, levels = c(malaria.tissue.leakage))) %>% 
    ggplot(aes(x=Time, y=NPX, color=Time,fill=Time)) + 
    geom_line(aes(group=study_id), color="grey",alpha=.6,size=.2)+
    geom_violin(trim = F,alpha=.2,lwd=.25) +
    geom_boxplot(alpha=1,width=0.25,color="black",outlier.size = 0.5, fatten = 1,lwd=.25,show.legend = F) +
    facet_wrap(~Assay,ncol = 9,scales = "free_y") +
    theme_minimal() +
    labs(x="") +
    theme(axis.text.x = element_blank(),
          legend.position = "bottom") +
    scale_color_manual(values=time3_col) +
    scale_fill_manual(values=time3_col))

Figure S4E

df <-  data.long %>% 
   inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),
              by="sample_id") %>% 
  filter(Assay%in% c("AGXT","HAO1"),
         Time=="Acute") %>% 
  left_join(
    clinchem_study_pats_acute.wide %>% transmute(study_id, p_asat, p_alat)
  ) %>% 
  pivot_longer(names_to = "clinchem", values_to = "clinchem_val",cols = p_asat:p_alat)

df %>% 
  ggplot(aes(x=NPX,y=clinchem_val)) +
  #geom_point(shape=16, size=.5) +
  geom_point() +
  geom_smooth(method="lm") +
  facet_grid(Assay~clinchem)

library(see)
(agxt_hao1_alat_asat_cor <- df %>% 
  transmute(sample_id, Assay,NPX,clinchem,clinchem_val) %>% 
  pivot_wider(names_from = Assay, values_from = NPX) %>%
  pivot_wider(names_from = clinchem, values_from = clinchem_val) %>% 
  column_to_rownames("sample_id") %>% 
  correlation(method = "spearman") %>% 
  summary() %>% 
  plot() +
  theme(text = element_text(size=12)))

Supplementary Figure 5

related to main Figure 2 ### Figure S5A-D

i="Secreted to blood"
acute_malaria_hpa_function_facet.list <- list()
for(i in c("Secreted to blood","Intracellular and membrane","Secreted in other tissues","Secreted to extracellular matrix","Secreted to digestive system","Secreted in brain","Secreted - unknown location")){
  
  (acute_malaria_hpa_function_facet.list[[i]] <- 
     dap.res %>% 
     dplyr::filter(FDR==TRUE,
                   abs(logFC)>0) %>%
     inner_join(hpa_24.0,by=c("Assay"="gene")) %>% 
     dplyr::filter(secretome_location == i, 
                   !secretome_function %in% c(NA,"NULL","Not secreted")
     ) %>% 
       ungroup() %>% 
       mutate(secretome_function = factor(secretome_function))%>% 
       ggplot(aes(x = fct_reorder2(Assay, secretome_function, -logFC),
                  y=logFC, color = secretome_location)) +
       geom_point(size=1, show.legend = F) + 
       geom_errorbar(aes(ymin= logFC - 1.96*SE,# 1.96*SE =conf.low
                         ymax=logFC + 1.96*SE,#conf.high,
                         color=secretome_location),
                     size=.25,    
                     width=.2,
                     position=position_dodge(.9),
                     alpha=.5) +
       geom_hline(yintercept = 0, linetype=2, alpha=.4) + 
       scale_color_manual(values = secretome_location_cols) +
       coord_flip() +
       theme_minimal() +
       facet_grid(cols = vars(secretome_location), 
                  rows = vars(secretome_function), scales = "free", space = "free_y",drop = F) +
       theme(strip.text.y = element_text(angle = 0,size=3.5),
             strip.placement = "inside",
             axis.text = element_text(size = 3),
             axis.title = element_text(size=5),
             legend.title = element_text(size=5),
             legend.text = element_text(size=5),
             plot.caption = element_text(size=5),
             panel.grid.major.y = element_blank(),
             panel.grid.minor.y = element_blank(),
             panel.grid.major.x = element_line(linewidth = .5),
             panel.grid.minor.x = element_line(linewidth = .5),
             plot.title.position = "plot",
             legend.position = "none") +
       labs(x="",
            y="Estimated difference (NPX) with 95% CI") +
       expand_limits(y = c(-1,1))
  )
}

delta NPX

  • needed for heatmap annotation and later on clustering
df_4_fc <- data.wide %>% 
  inner_join(sampleTable_simple %>% dplyr::select(DAid,study_id, sample_id, Time),by="sample_id") %>% 
  dplyr::filter(Time!="D10") %>% 
  dplyr::select(DAid,study_id, sample_id, Time, everything()) %>% 
  pivot_longer(cols = 5:ncol(.), names_to = "Assay", values_to = "NPX") %>% 
  dplyr::select(-DAid,-sample_id) %>% 
  pivot_wider(values_from = "NPX", names_from = "Time")


M12_median_M12 <- df_4_fc %>% 
  group_by(Assay) %>% 
  summarise(m12_median = median(M12,na.rm = TRUE)) 

fc_over_median_M12 <- df_4_fc %>% 
  inner_join(M12_median_M12, by="Assay") %>% 
  group_by(Assay) %>% 
  mutate(log2FC_medianM12 = Acute-m12_median) %>% 
  dplyr::select(-M12) %>% 
  na.omit() %>% 
  dplyr::rename(dNPX = log2FC_medianM12) 

#fc_over_median_M12 %>% saveRDS("../data/data_clean/20230426_Explore1536_fc_over_median_m12_tidy_long.rds")
fc_over_median_M12 %>% head()
## # A tibble: 6 × 5
## # Groups:   Assay [6]
##   study_id Assay   Acute m12_median   dNPX
##   <chr>    <chr>   <dbl>      <dbl>  <dbl>
## 1 2011PT01 NPPB    1.48      0.0487  1.43 
## 2 2011PT01 HNRNPK -0.193     0.658  -0.851
## 3 2011PT01 CEBPB   0.702     0.140   0.562
## 4 2011PT01 CRHR1  -0.829     0.0427 -0.872
## 5 2011PT01 TSLP    0.952     0.154   0.798
## 6 2011PT01 MFAP3   0.871     0.0906  0.781

Figure 3

Single-cell transcriptomics of PBMCs during acute malaria

df <- data.wide %>% 
  inner_join(sampleTable_simple %>% 
               transmute(sample_id),
             by="sample_id") %>% 
  column_to_rownames("sample_id")

## PC calculation
pcaRes <- stats::prcomp(df,center = TRUE, scale. = TRUE)
varExp <- round(pcaRes$sdev^2 / sum(pcaRes$sdev^2) * 100)
pcaDF <- data.frame(PC1 = pcaRes$x[, 1],
                    PC2 = pcaRes$x[, 2]) %>% 
  rownames_to_column("sample_id") 

## Prep for plotting
data4plot <- pcaDF %>% 
  dplyr::inner_join(sampleTable_simple, by="sample_id") %>% 
  mutate(rhapsody_lib = ifelse(study_id == "2013004","Library 1",
                               ifelse(study_id == "2013007","Library 2",
                                      ifelse(study_id == "2013008","Library 3",
                                             ifelse(study_id == "2018002","Library 4",NA)))))


(plot.pca.rhapsody <- data4plot %>% 
    ggplot(mapping = aes(x = PC1, y = PC2, color = Time,fill=NULL, label = NULL)) +
    geom_point(alpha = 0.9, size = 1) +
    ggrepel::geom_text_repel(data= . %>% filter(study_id %in% rhapsody_study_ids), 
                             aes(x=PC1,y=PC2, label=rhapsody_lib),color="grey10",
                             direction = "both",box.padding = 1, max.overlaps = Inf,
                             size=3, alpha=.9,show.legend = F) +
    geom_point(data= . %>% filter(study_id %in% rhapsody_study_ids),
               aes(color=Time),
               size=0.5, alpha=.8) +
    guides(colour = guide_legend(override.aes = list(size=1,alpha=1)))+
    ggplot2::scale_color_manual(values= time3_col) +
    labs(x = paste0("PC1 (",  varExp[1], " %)"),
         y = paste0("PC2 (",  varExp[2], " %)"),
         shape="Rhapsody library") +
    theme_minimal()  +
    theme(legend.title = element_text(size = 6), 
          legend.text = element_text(size = 6))) 

load seurat object & set colors

library(Seurat)
#pbmc <- readRDS("../data/data/rhapsody/2021-12-17AbSeq_Cell_Calling_qc_cca_wnn_clustering_annotated.rds")
pbmc <- readRDS("../data/data/rhapsody/MalariaTraveler_RhapsodyAbSeq_Cell_Calling_qc_cca_wnn_clustering_annotated.rds")

pbmc$Group_rev <- factor(as.factor(pbmc$Group), levels = c("primary", "previously"))

#- RNA Normalization
pbmc <- NormalizeData(object = pbmc, assay = 'RNA', normalization.method = 'LogNormalize', scale.factor = 10000)

#- Ab Normalization
pbmc <- NormalizeData(object = pbmc, assay = 'ADT', normalization.method = 'CLR') #margin   If performing CLR normalization, normalize across features (1) or cells (2)

## list of proteins/mrna targets covered
ab.markers <- rownames(pbmc@assays$ADT)
rna.markers <- rownames(pbmc@assays$RNA)

##change group color
ENDEMIC_colors <- setNames(c("#F1A340","#998EC3"), c("previously_exposed","primary_infected"))
#previously_exposed   primary_infected 
#         "#F1A340"          "#998EC3" 
ENDEMIC_colors <- setNames(brewer.pal(3,"PuOr")[c(1,3)], c("previously_exposed","primary_infected"))
names(ENDEMIC_colors) <- c("previously","primary")
TIME_colors <- setNames(brewer.pal(6,"PiYG"), c("Acute","D10","M1","M3","M6","Y1"))

scaled_01_col <- circlize::colorRamp2(c(0,1), c("white","red"))

L1_colors <- length(unique(pbmc@meta.data$CellType_L1))
L1_colors <- c("#68a748",
               "#8761cc",
               "#ae953e",
               "#688bcc",
               "#cc693d",
               "#4aac8d",
               "#c361aa",
               "#ca5369")
names(L1_colors) <- unique(pbmc@meta.data$CellType_L1)


Idents(pbmc) <- "CellType_L2"

L2_colors <- length(unique(pbmc@meta.data$CellType_L2))
L2_colors <- c("mDC"="#79658C",
               "pDC" = "#AEA14E",
               
               "CD14 monocytes"= "#D1EAB7",
               "CD16 monocytes"="#DB7D47",
               
               "Vd2+ gdT"="#796CD7",
               "Vd2- gdT" =  "#66AC55",
               
               "NK CD56dim CD16+" = "#EBB69E", 
               "NK CD56dim" =  "#CEE486",
               "NK CD56bright"=  "#E0DADB",
               "NK prolif." ="#B5E7DF",
               
               "B naive" = "#889AE5",
               "B memory" = "#66ED58",
               "Plasma cells" = "#893CEA",
               
               "CD4 naive"= "#E15081",
               "CD4 Treg CD80+"= "#579189",
               "CD4 Treg CD80-"=  "#66DEE2",
               "CD4 Tfh"= "#D64EDB",
               "CD4 effect. activated" = "#D38D96",
               "CD4 effect. memory" = "#EDD591",
               "CD4 trans. memory" =  "#DAB8E3",
               "CD4 central memory"  = "#6FE8BE",
               
               "CD8 naive"= "#CAEB48",
               "CD8 trans. memory"= "#85EB8F",
               "CD8 Tfh"="#E6D253",
               "NKT"="#7BBCDF",
               "CD8 effect. memory"  =  "#A7AE90", 
               "undefined"= "#D984D1")

names(L2_colors) <- unique(pbmc@meta.data$CellType_L2)

Figure 3A, C

arr <- list(x = -13, y = -13, x_len = 5, y_len = 5)

umap_axis <- annotate("segment", linewidth=0.1,
                      x = arr$x, xend = arr$x + c(arr$x_len, 0), 
                      y = arr$y, yend = arr$y + c(0, arr$y_len), 
                      arrow = arrow(type = "closed", length = unit(3, 'pt')))
umap_axis_xlab <- annotate("text", x = arr$x+2.5, y = arr$x-1, label = "wnnUMAP 1",size=1) 
umap_axis_ylab <- annotate("text", y = arr$y+2.5, x = arr$y-1, label = "wnnUMAP 2",size=1,angle=90)


rhapsody_umap_coords <- data.table::data.table(pbmc@meta.data, Embeddings(object = pbmc, reduction = 'wnn.umap')) %>% rownames_to_column("CellID") 

lable_df <- rhapsody_umap_coords %>%
  dplyr::group_by(CellType_L1) %>%
  dplyr::select(CellType_L1, contains("UMAP")) %>%
  summarise_all(mean)

(rhapsody_umap_ggplot_l1 <- rhapsody_umap_coords %>% 
    ggplot(aes(x = wnnUMAP_1, y = wnnUMAP_2)) + 
    geom_point(aes(color = as.character(CellType_L1)), size = 0.1, alpha=.5, show.legend = F,shape = 16) +
    ggrepel::geom_text_repel(data=lable_df,aes(x=wnnUMAP_1,y=wnnUMAP_2, label=CellType_L1),size=1.5) +
        coord_fixed()+
    scale_color_manual(values=L1_colors) +
    theme_void() +
                umap_axis +
                umap_axis_xlab +
                umap_axis_ylab)

lable_df <- rhapsody_umap_coords %>%
  dplyr::group_by(CellType_L2) %>%
  dplyr::select(CellType_L2, contains("UMAP")) %>%
  summarise_all(mean)

(rhapsody_umap_ggplot_l2 <- rhapsody_umap_coords %>% 
    ggplot(aes(x = wnnUMAP_1, y = wnnUMAP_2)) + 
    geom_point(aes(color = as.character(CellType_L2)), size = 0.1, alpha=.5, show.legend = F, shape = 16) + 
    ggrepel::geom_text_repel(data=lable_df,aes(x=wnnUMAP_1,y=wnnUMAP_2, label=CellType_L2),size=1.5) +
    labs(x = 'wnnUMAP 1', y = 'wnnUMAP 2', color=NULL)  + 
    coord_fixed()+
    scale_color_manual(values=L2_colors) +
    theme_void() +
                umap_axis +
                umap_axis_xlab +
                umap_axis_ylab)

Figure 3B

require(scales)
(per_sample_perc_l1 <- tibble(pbmc@meta.data) %>% 
    mutate(orig.ident = paste0("Patient"," 0",Library)) %>% 
    group_by(Time,orig.ident) %>% 
    count(CellType_L1) %>% 
    # Stacked + percent
    ggplot(aes(fill = CellType_L1, y=n, x=orig.ident)) + 
    geom_bar(position="fill", stat="identity",width = 0.9) +
    scale_fill_manual(values = L1_colors) +
    facet_grid(~Time,scales = "free_x") +
    scale_y_continuous(labels = scales::percent,expand = c(0,0)) + 
    labs(x = "",
         y = "Frequency",
         fill="") +
    theme_minimal(base_size = 6) +
    #theme_cowplot() +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
          panel.grid.major = element_blank()))

Figure 3D

pbmc_acute <- subset(pbmc, subset=Time=="Acute")

#- RNA Normalization
pbmc_acute <- NormalizeData(object = pbmc_acute, assay = 'RNA', normalization.method = 'LogNormalize', scale.factor = 10000) %>% ScaleData()

#- Ab Normalization
pbmc_acute <- NormalizeData(object = pbmc_acute, assay = 'ADT', normalization.method = 'CLR') #margin   If performing CLR normalization, normalize across features (1) or cells (2)
## Pseudobulk (Celltype)

#https://github.com/satijalab/seurat/discussions/4210
## AverageExpression
Idents(pbmc_acute) <- "CellType_L2"

## calculation of pseudobulk, for each identity based on count data
pbmc_acute.avg.wide <- log1p(Seurat::AverageExpression(pbmc_acute, group.by = "CellType_L2", slot = "counts", verbose = FALSE)$RNA) %>% 
  data.frame() %>% 
  rownames_to_column("gene") 

colnames(pbmc_acute.avg.wide) <- c("gene",colnames(Seurat::AverageExpression(pbmc_acute, group.by = "CellType_L2", slot = "counts", verbose = FALSE)$RNA))

pbmc_acute.avg.long <- pbmc_acute.avg.wide %>% pivot_longer(names_to = "celltype", values_to = "avgExp",cols = -gene)

Mapping (gene - protein)

## mapping 
full_mapping <- mapping_uniprot_ensembl %>% left_join(hpa_24.0, by=c("Ensembl"="ensembl"))

wilcoxUp <- dap.res %>% filter(FDR==TRUE,logFC>1) %>% pull(UniProt)

gene.selection <- full_mapping %>% 
  filter(UniProt %in% wilcoxUp) %>% 
  filter(Symbol %in% rna.markers) %>% distinct(Assay) %>% pull(Assay)

Figure 3D

Heatmap genes expression

rhapsody.gene.match <- full_mapping %>% 
  filter(UniProt %in% wilcoxUp) %>% 
  filter(Symbol %in% unique(pbmc_acute.avg.wide$gene))

## make matrix for heatmap
mat_pbmc_acute <- pbmc_acute.avg.wide %>% 
  filter(gene %in% rhapsody.gene.match$Symbol) %>% 
  column_to_rownames("gene") %>% 
  as.matrix() 

## make row(gene/protein) annotation df
rowAnno.df <- data.frame(Assay = rownames(mat_pbmc_acute)) %>% 
  left_join(dap.res,by=c("Assay")) %>% 
  #left_join(hpa_24.0,by=c("Assay"="gene")) %>% 
    left_join(hpa_24.0,by=c("UniProt"="uniprot")) %>% 

  mutate(secretome_function = ifelse(is.na(secretome_function),"No annotated function", secretome_function))
  

col.anno.df <- data.frame(colnames = colnames(mat_pbmc_acute)) %>% 
  transmute(colnames,
            colanno = case_when(grepl("DC",colnames) ~ "DC",
                                grepl("monocytes",colnames) ~ "Monocytes",
                                grepl("CD4",colnames) ~ "CD4+ T",
                                grepl("CD8",colnames) ~ "CD8+ T",
                                grepl("B|Plasma",colnames) ~ "B",
                                grepl("NK",colnames) ~ "NK",
                                grepl("gdT",colnames) ~ "gdT",
                                .default = "undefined"),
            colanno = factor(colanno, levels= c("DC","Monocytes","NK","gdT","B","CD4+ T","CD8+ T","undefined")))


right.anno <- HeatmapAnnotation(df = col.anno.df %>% column_to_rownames("colnames"), 
                                which = "row",
                                col = list(colanno = L1_colors),
                                # name = "SNF cluster",
                                show_annotation_name = F,
                                show_legend = F,
                                annotation_name_gp = gpar(fontsize=6),
                                annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                               title_gp = gpar(fontsize = 6),
                                                               direction = "horizontal",
                                                               legend_height = unit(.1, "cm"),
                                                               grid_width = unit(.2, "cm")),
                                simple_anno_size = unit(1, "mm"))

top.anno <-  HeatmapAnnotation(df = rowAnno.df %>% transmute(Assay, secretome_location) %>% column_to_rownames("Assay"),
                               which = "column",
                               show_legend = c(TRUE), 
                               show_annotation_name = F, 
                               annotation_name_gp = gpar(fontsize = 6),
                               annotation_legend_param = list(title = "HPA\nclassification",
                                                              title_gp = gpar(fontsize = 6), 
                                                              labels_gp = gpar(fontsize = 6),
                                                              legend_height = unit(3, "mm"), 
                                                              grid_width = unit(3, "mm")),
                               col = list(secretome_location = c(secretome_location_cols)),
                               simple_anno_size = unit(3, "mm"),
                               
                               na_col = "grey90")

## getting foldchange (dNPX over median convalescence) 
m <- fc_over_median_M12 %>%
  filter(Assay %in% rowAnno.df$Assay) %>% 
  pivot_wider(names_from = Assay, values_from = dNPX,id_cols = study_id) %>% 
  column_to_rownames("study_id") %>% 
  as.matrix() %>% t()

m <- m[rownames(mat_pbmc_acute),]


bottom.anno <- HeatmapAnnotation("Plasma protein\ndNPX" = anno_boxplot(t(m),
                                                                       height = unit(1.5, "cm"),width = unit(1.5,"cm"),
                                                                       box_width = 0.8,
                                                                       axis_param = list(side = "right",
                                                                                         labels_rot = 45,
                                                                                         gp=gpar(fontsize = 5)),
                                                                       gp = gpar(fill="#C51B7D"),
                                                                       outline = FALSE),
                                 annotation_name_rot = 0,
                                 annotation_name_gp = gpar(fontsize = 5),
                                 annotation_name_side = "right",
                                 simple_anno_size = unit(3, "mm"),
                                 which = "column")



(pbmc_l2_acute_hm.wide <- mat_pbmc_acute[rownames(m),] %>% 
    t() %>% 
    ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% 
    as.matrix() %>% 
    ComplexHeatmap::Heatmap(
      name="average\ngene\nexpression",
      col = scaled_01_col,
      
      top_annotation = top.anno,
      bottom_annotation = bottom.anno,
      right_annotation =  right.anno,
      column_dend_height = unit(2, "mm"),
      cluster_rows = F,
      row_dend_reorder = TRUE,
      show_row_names = TRUE,
      column_split = rowAnno.df$secretome_function,
      column_dend_reorder = F,
      row_title_side = "right",
      row_title_gp = gpar(fontsize = 6),
      cluster_columns = T,
      row_split = col.anno.df$colanno,
      row_title = NULL,
      
      column_title_gp = gpar(fontsize=4),
      column_title_rot = 45,
      row_title_rot = 0,
      row_names_gp = gpar(fontsize = 4),
      #row_dend_width = unit(2, "mm"), 
      row_dend_side = "left",
      cluster_row_slices = T,
      column_names_gp = gpar(fontsize = 4), 
      column_names_rot = 90,
      heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                  title_gp = gpar(fontsize = 6),
                                  grid_width = unit(3, "mm")),
    ) 
  )

Figure 3E

CellPhoneDB

#cpdb.protein_input <- read_delim("../data/cellphoneDB/v4.1.0_protein_input.csv")
#cpdb.interaction_input <- read_delim("../data/cellphoneDB/v4.1.0_interaction_input.csv")

cpdb.protein_input <- read_delim("../data/cellphoneDB/v5_protein_input.csv",)
cpdb.interaction_input <- read_delim("../data/cellphoneDB/v5_interaction_input.csv")

kegg.ccr <- read_excel("../data/KEGG_CytokineCytokineReceptorInteraction_malariaspec.xlsx") %>% mutate(Source = "KEGG")
rna.markers.uniprot <- data.frame(gene = rna.markers) %>% 
  left_join(hpa_24.0 %>% transmute(gene, uniprot)) %>% na.omit()
ligand.q <- dap.res %>% filter(p.adj <=0.01, logFC > .1) %>% 
  left_join(cpdb.protein_input,
            by=c("UniProt"="uniprot")) %>% 
  pull(UniProt)

length(ligand.q)
## [1] 502
nw <- cpdb.interaction_input %>% 
  filter(partner_a %in% ligand.q,
         directionality == "Ligand-Receptor") %>% 
  mutate(protein_name_b_strip = gsub("_HUMAN","",protein_name_b),
         protein_name_a = gsub("_HUMAN","",protein_name_a)) %>% 
  mutate(protein_name_b_complex = case_when(is.na(protein_name_b) ~ str_remove(interactors,paste0(protein_name_a,"-")),
                                    .default = protein_name_b)) %>%
   separate_longer_delim(protein_name_b_complex, delim = "+") %>% 
   left_join(hpa_24.0 %>% transmute(protein_name_b_complex = gene,
                                      uniprot_b_complex = uniprot), by=c("protein_name_b_complex")) %>% 
  mutate(protein_name_b = case_when(is.na(protein_name_b) ~ protein_name_b_complex,
                                        .default = protein_name_b),
         partner_b_new = case_when(is.na(uniprot_b_complex) ~ partner_b,
                                   .default = uniprot_b_complex)) %>% 
  transmute(partner_a, partner_b, partner_b_new) %>% 
  filter(partner_b_new %in% rna.markers.uniprot$uniprot) %>% 
  mutate(uniprot_a = partner_a,
         uniprot_b = partner_b_new)
measured.in.plasma <- dap.res %>% filter(p.adj <=0.01, logFC > 0.1) %>% pull(UniProt)
measured.in.plasma.name <- dap.res %>% filter(p.adj <=0.01, logFC > .1) %>% pull(Assay)

G <- as_tbl_graph(nw %>% transmute(from = uniprot_a,
                                   to = uniprot_b))
node_table <- as_tibble(G) %>% 
  left_join(dap.res %>% mutate(measured.as.soluble = T),
            by=c("name"="UniProt")) %>% 
  left_join(hpa_24.0 %>% transmute(gene, uniprot), 
            by=c("name"="uniprot")) %>% 
  mutate(protein_name = gene,
         measured.as.soluble = case_when(is.na(measured.as.soluble) ~F,
                                         .default = T))# %>%
(ligand_receptor_nw <- G %>% 
   inner_join(node_table,by="name") %>% 
   create_layout(layout = "fr") %>% 
   ggraph() + 
   geom_edge_link(alpha=.02) + 
   geom_edge_fan(width = .5, color = "grey90") +
   geom_node_point(aes(color=if_else(measured.as.soluble==T,logFC,NA),
                       size= if_else(measured.as.soluble==T,logFC,1))) +
   guides(color = guide_colourbar(barwidth = 3, barheight = .75),
          size=F) +
   labs(color="logFC of proteins\nin plasma") +
   scale_size(range=c(1,3.5)) +
   geom_node_text(aes(label = protein_name,
                      color= if_else(measured.as.soluble==T,logFC,NA)),
                  size=1, 
                  repel=T) +
   scale_color_continuous(low="thistle2",
                          high="darkred", 
                          guide="colorbar",
                          na.value="grey20") +
   theme_void() +
   theme(legend.position = "bottom",
         plot.title = element_text(size=6),
         legend.title = element_text( size=6),
         legend.text=element_text(size=6)) 
)

receptor_fam <- list(cxc_subfam = c("CXCR1","CXCR2","CXCR3","CXCR4","CXCR5","CXCR6","CXCR7","XCR1","CX3CR1"),
                     cc_subfam = paste0("CCR",1:11),
                     class1helicalcyto_fam = c("IL2RA","IL4R"),
                     class2helicalcyto_fam = c("IL10RA","IL10RB"),
                     prolaction_fam = c("GHR","CSF3R"),
                     ifn_fam =c("IFNAR1","IFNAR2","IFNGR1","IFNGR2"),
                     il1likecyto_fam = c("IL1R1","IL1RAP","IL1R2","IL18R1","IL18RAP","ST2","IL1RAP"),
                     nonclassified = c("CD4","CSF1R"),
                     tnf_fam = c("TNFR1","TNFR2","HVEM","FAS","DR4","DR5","DCR1","DCR2","EDAR","RANK","CD27","CD30","CD40","Ox40","TACI"),
                     tgfb_fam = c("TGFBR2","ACVR2B","ACVR1B")) %>% 
  enframe() %>% unnest(cols = c(value)) %>% dplyr::rename(subfam = name, receptor = value)
#extract all transmembrane receptors from CellPhoneDB as uniprotIDs

## filter CellPhoneDB protein_input for transmembrane & receptors
cpdb.receptor.transmem.name <- cpdb.protein_input %>% filter(transmembrane==T |
                                                               receptor==T) %>% 
  mutate(protein_name = gsub("_HUMAN","",protein_name)) %>% 
  pull(uniprot)
df <- pbmc_acute.avg.wide %>% 
  right_join(rna.markers.uniprot) %>% 
  filter(uniprot %in% nw$uniprot_b)

geneAnno <- df %>% transmute(gene,uniprot) %>% left_join(receptor_fam,by=c("gene"="receptor")) %>%
  mutate(subfam = ifelse(is.na(subfam),"Other",subfam),
         CPDB = ifelse(uniprot %in% cpdb.receptor.transmem.name,T,F),
         KEGG = ifelse(gene %in% receptor_fam$receptor,T,F),
         in_plasma = ifelse(gene %in% measured.in.plasma.name,T,F))


mat <- df %>% 
  dplyr::select(-uniprot) %>% 
  column_to_rownames("gene") %>% 
  as.matrix()

col.anno.df <- data.frame(colnames = colnames(mat)) %>% 
  transmute(colnames,
            colanno = case_when(grepl("DC",colnames) ~ "DC",
                                grepl("monocytes",colnames) ~ "Monocytes",
                                grepl("CD4",colnames) ~ "CD4+ T",
                                grepl("CD8",colnames) ~ "CD8+ T",
                                grepl("B|Plasma",colnames) ~ "B",
                                grepl("NK",colnames) ~ "NK",
                                grepl("gdT",colnames) ~ "gdT",
                                .default = "undefined"),
            colanno = factor(colanno, levels= c("DC","Monocytes","NK","gdT","B","CD4+ T","CD8+ T","undefined")))

colAnn.top <- HeatmapAnnotation(df = col.anno.df %>% column_to_rownames("colnames"), 
                                which = "col",
                                col = list(colanno = L1_colors),
                                show_annotation_name = F,
                                show_legend = F,
                                annotation_name_gp = gpar(fontsize=6),
                                annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                               title_gp = gpar(fontsize = 6),
                                                               direction = "horizontal",
                                                               legend_height = unit(.1, "cm"),
                                                               grid_width = unit(.2, "cm")),
                                simple_anno_size = unit(1, "mm")
)

Figure 3F

m <-  mat %>% 
  t() %>% 
  as.data.frame() %>% 
  mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% 
  as.matrix() 

(pbmc_l2_acute_cellphonedb_hm.wide <- m %>% 
   ComplexHeatmap::Heatmap(name="average\ngene\nexpression",
                           column_split = geneAnno$subfam, 
                           cluster_columns = T,
                           cluster_column_slices = T,
                           bottom_annotation = HeatmapAnnotation(df=geneAnno %>% transmute(in_plasma),
                                                                 which="column",
                                                                 annotation_legend_param = list(title_gp = gpar(fontsize = 6), 
                                                                                                labels_gp = gpar(fontsize = 6)),
                                                                 annotation_name_gp = gpar(fontsize = 5),
                                                                 simple_anno_size = unit(1.5, "mm"),na_col = c("white","white","white"),
                                                                 show_legend = c(FALSE,FALSE,FALSE),
                                                                 gp = gpar(col = "grey90"),
                                                                 col=list(CPDB = c("TRUE" = "grey60", "FALSE" = "white","NA" = "white"),
                                                                          KEGG = c("TRUE" = "grey60", "FALSE" = "white","NA" = "white"),
                                                                          in_plasma = c("TRUE" = "darkred", "FALSE" = "white","NA" = "white"))),
                           show_row_dend = F,
                           row_title_side = "right",
                           row_title_rot = 0,
                           row_title_gp = gpar(fontsize = 5),
                           row_title = NULL,
                           col = scaled_01_col,
                           row_names_gp = gpar(fontsize = 4),
                           show_column_dend = T,
                           column_dend_height = unit(2,"mm"),
                           row_dend_width = unit(2, "mm"), 
                           row_dend_side = "left",
                           clustering_method_columns = "mcquitty",
                           right_annotation = rowAnnotation(df = col.anno.df %>% column_to_rownames("colnames"), 
                                                            
                                                            col = list(colanno = L1_colors),
                                                            show_annotation_name = F,
                                                            show_legend = F,
                                                            annotation_name_gp = gpar(fontsize=6),
                                                            annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                                                           title_gp = gpar(fontsize = 6),
                                                                                           direction = "horizontal",
                                                                                           legend_height = unit(.1, "cm"),
                                                                                           grid_width = unit(.2, "cm")),
                                                            simple_anno_size = unit(1, "mm")
                           ),
                           cluster_rows = F,
                           row_split = col.anno.df$colanno,
                           column_title_gp = gpar(fontsize=4),
                           column_title_rot = 45,
                           column_names_gp = gpar(fontsize = 4), 
                          heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                  title_gp = gpar(fontsize = 6),
                                  grid_width = unit(3, "mm")))
)

Supplemantary Figure S6

related to main Figure 3

Figure S6A

(rhapsody_cells_per_sample <- tibble(pbmc@meta.data) %>%
  #as.data.table %>% # the resulting md object has one "row" per cell
  rownames_to_column("CellID")  %>% 
  group_by(orig.ident,Time) %>% 
  dplyr::count() %>% 
  ggplot(aes(x=orig.ident,y=n, fill=Time)) +
  scale_fill_manual(values = TIME_colors,breaks = c("Acute","D10","Y1")) +
  scale_y_continuous(expand = c(0,0), trans = "sqrt") +
  coord_flip()+
  geom_bar(stat="identity", position="dodge", show.legend = TRUE) +
  geom_hline(yintercept=6000,lwd=.2) +
  labs(y="Number of cells",
       x="",
       fill="") + 
  theme_minimal())

Figure S6B

## integration
(rhapsody_umap_ggplot_int_orig.ident <- rhapsody_umap_coords %>% 
  ggplot(aes(x = wnnUMAP_1, y = wnnUMAP_2)) + 
  geom_point(aes(color = as.character(orig.ident)), size = 0.1, alpha=.1) +
  labs(x = 'wnnUMAP 1', y = 'wnnUMAP 2', color=NULL)  + 
  guides(color = guide_legend(override.aes = list(alpha = 1,size=.25))) +
  my_dimred_theme
)

Figure S6C

## integration
(rhapsody_umap_ggplot_int_time <- rhapsody_umap_coords %>% 
  ggplot(aes(x = wnnUMAP_1, y = wnnUMAP_2)) + 
  geom_point(aes(color = as.character(Time)), size = 0.25, alpha=.1) +
  labs(x = 'wnnUMAP 1', y = 'wnnUMAP 2', color=NULL)  + 
  scale_color_manual(values = TIME_colors,breaks = c("Acute","D10","Y1")) +
  guides(color = guide_legend(override.aes = list(alpha = 1,size=.25))) +
  my_dimred_theme
)

Figure S6D

(vln_adt.weight <- VlnPlot(pbmc, features = "adt.CCA.weight", group.by = 'CellType_L2', cols = L2_colors, sort = TRUE, pt.size = 0) +
  NoLegend() + 
  labs(title = "adt weight", y="ADT weight",x=NULL))

Figure S6E

rna.marker4dotplot <- c("S100A12","CD14","S100A9","VMO1","C1QA","FCGR3A", "KLRF1","KIR2DL1",
                        "GNLY","IL12RB2","IL18R1","GZMK","TYMS","TOP2A", "KIAA0101","CCR7","LEF1",
                        "MYC", "PASK","CD28","ICOS","RGS1","CTLA4","CCR5","LAG3","POU2AF1",
                        "FOXP3","IL2RA","CD8A","ZNF683","RORC","IKZF2","MS4A1","CD79A","IGKC",
                        "TCL1A","FCER2","CD200","TNFRSF17","FCER1A","CLEC10A","CD1C","NRP1","TLR9","TLR7")

(dotplot.rna <- DotPlot(pbmc,
        features = rna.marker4dotplot,
        assay = "RNA",
        cols = c("RdYlBu"),
        col.min = -2.5,
        col.max = 2.5,
        dot.min = 0,
        dot.scale = 1,
        idents = NULL,
        group.by = NULL,
        split.by = NULL,
        cluster.idents = F,
        scale = TRUE,
        scale.by = "radius",
        scale.min = NA,
        scale.max = NA) + 
  RotatedAxis() + 
  theme(axis.text.x=element_text(size=6), 
        axis.text.y=element_text(size=6),
        text = element_text(size=6)) + 
  labs(x="",y="", title="mRNA expression")
)

DotPlot(pbmc,
        features = rownames(pbmc@assays$ADT),
        assay = "ADT",
        cols = c("RdYlBu"),
        col.min = -2.5,
        col.max = 2.5,
        dot.min = 0,
        dot.scale = 1,
        idents = NULL,
        group.by = NULL,
        split.by = NULL,
        cluster.idents = F,
        scale = TRUE,
        scale.by = "radius",
        scale.min = NA,
        scale.max = NA) + 
  theme(axis.text.x=element_text(size=6), # cell subsets
        axis.text.y=element_text(size=6),
        text = element_text(size=6)) + 
  RotatedAxis() +
  labs(x="",y="", title="Surface protein expression")

Figure S6F

(cellnumbers_l2 <- tibble(pbmc_acute@meta.data) %>% 
   group_by(CellType_L2) %>% 
   count() %>% 
   
   ggplot(aes(fill = CellType_L2, y=n, x=fct_reorder(CellType_L2,n))) + 
   geom_col(show.legend = F) +
   scale_fill_manual(values = L2_colors) +
   scale_y_continuous(expand = c(0, 0),trans  = "log10", breaks=c(1,10,100,1000,5000)) + 
   coord_flip() +
   labs(x=NULL,
        y="Number of cells") +
   theme_bw() +
   theme(panel.grid.major = element_blank(),
         panel.border = element_blank()))

Figure S6G

genes.oi.timepoints = VlnPlot(pbmc,
                              features = c("CD163", "IL1B", "IL1RN", "ICAM1", "LILRB4", "CXCL10", "S100A12",  "NAMPT",
                                           "CCL2", "CXCL11", "CXCL9", "AZU1","VMO1", "TNFRSF8", "CHI3L1","CCL4", "GZMA",
                                           "GZMB","GZMH","CST7","TNFRSF9","IL2RA","IL1RL1","CD48", "CD27", "CD38", "HAVCR2"),
                              group.by = 'CellType_L2', assay = "RNA",
                              split.by = "Time", cols = time3_col, sort = F, pt.size = 0,stack = T,flip = F) +
  theme(axis.text.x = element_text(angle = 0, size=6),
        axis.text.y = element_text(size=6),
        strip.text.x = element_text(angle = 90, size = 5, face=NULL,hjust = .5),
        axis.title.y = element_blank(),
        axis.title.x = element_text(size=6),
        # strip.text.y = element_text(size = 6),
        # strip.text.x = element_text(size=6),
        legend.position = "right",
        legend.key.size = unit(.2, 'cm'), #change legend key size
        legend.key.height = unit(.2, 'cm'), #change legend key height
        legend.key.width = unit(.2, 'cm'), #change legend key width
        legend.title = element_text(size=5), #change legend title font size
        legend.text = element_text(size=5))

genes.oi.timepoints$layers[[1]]$aes_params$size = .1
genes.oi.timepoints

Supplementary Figure 7

related to main Figure 3

dooley <- readRDS("../data/data/ReAnalysis_DooleyNL_etal_bioRxiv_2022/annotated_Sabah_data_21Oct2022.rds")

dooley_colors <- setNames(randomcoloR::distinctColorPalette(length(unique(dooley@meta.data$celltype))),
                          unique(dooley@meta.data$celltype))
## Preliminary QC check

tibble(dooley@meta.data) %>% # the resulting md object has one "row" per cell
  rownames_to_column("CellID")  %>% 
  group_by(orig.ident,timepoint,sample.day,ID) %>% 
  dplyr::count() %>% 
  ungroup() %>% 
  ggplot(aes(x=fct_reorder(orig.ident, timepoint),y=n, fill=ID)) +
  scale_y_continuous(expand = c(0, 0)) +
  coord_flip()+
  geom_bar(stat="identity", position="dodge", show.legend = F) +
  labs(title = "Number of cells per sample",
       x=NULL) +
  theme_minimal()

Figure S7A

dooley_umap_coords <- data.table::data.table(dooley@meta.data, Embeddings(object = dooley, reduction = 'umap')) %>% rownames_to_column("CellID") 

lable_df <- dooley_umap_coords %>%
  dplyr::group_by(celltype) %>%
  dplyr::select(celltype, contains("UMAP")) %>%
  summarise_all(mean)

(dooley_umap_ggplot <- dooley_umap_coords %>% 
    ggplot(aes(x = UMAP_1, y = UMAP_2)) + 
    geom_point(aes(color = as.character(celltype)), size = 0.1, alpha=.5,show.legend = F) +
    ggrepel::geom_text_repel(data=lable_df,aes(x=UMAP_1,y=UMAP_2, label=celltype),size=2) +
    labs(x = 'UMAP 1', y = 'UMAP 2')  + 
    scale_color_manual(values=dooley_colors) +
    my_dimred_theme)

Figure S7B

## Percentage celltype in sample
(dooley_per_sample_perc <- tibble(dooley@meta.data) %>% 
   group_by(timepoint,orig.ident) %>% 
   count(celltype) %>% 
   # Stacked + percent
   ggplot(aes(fill = celltype, y=n, x=orig.ident)) + 
   geom_bar(position="fill", stat="identity",width = 0.9) +
   facet_grid(~timepoint,scales = "free_x",space = "free_x") +
   scale_y_continuous(labels = scales::percent) + 
   scale_fill_manual(values=dooley_colors) +
   scale_y_continuous(labels = scales::percent,expand = c(0,0)) + 
   labs(x = "",
        y = "Frequency",
        fill="") +
   theme_minimal() +
   theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
         legend.text = element_text(size=6),
         legend.position = "top",
         panel.grid.major = element_blank()))

get only acute malaria cells (Day0)

dooley_0 <- subset(dooley, subset=timepoint=="Day0")
#- RNA Normalization
dooley_0 <- NormalizeData(object = dooley_0, assay = 'RNA', normalization.method = 'LogNormalize', scale.factor = 10000)

Figure S7C

(dooley_0_cellnumbers <- 
   tibble(dooley_0@meta.data) %>% 
   group_by(celltype) %>% 
   count() %>% 
   ggplot(aes(fill = celltype, y=n, x=fct_reorder(celltype,n))) + 
   geom_col(show.legend = F) +
   scale_y_continuous(expand = c(0, 0),trans  = "log10") +
   coord_flip() +
   scale_fill_manual(values=dooley_colors) +
   labs(x=NULL,
        y="Number of cells") +
   theme_bw() +
   theme(panel.grid.major = element_blank(),
         panel.border = element_blank()))

## calculation of pseudobulk, for each identity based on count data
dooley_0.avg.wide <- log1p(AverageExpression(dooley_0, group.by = "celltype", slot = "counts", verbose = FALSE)$RNA) %>% 
  as.data.frame() %>% 
  rownames_to_column("gene") 

dooley_0.avg.long <- dooley_0.avg.wide %>% 
  pivot_longer(names_to = "celltype", values_to = "avgExp",cols = -gene) %>% filter(avgExp >0)
dooley.gene.match <- full_mapping %>% 
  filter(UniProt %in% wilcoxUp) %>% 
  filter(Symbol %in% unique(dooley_0.avg.long$gene))

mat_dooley_0 <- dooley_0.avg.wide %>% 
  filter(gene %in% dooley.gene.match$Symbol) %>% 
  column_to_rownames("gene") %>% 
  as.matrix() 

Figure S7D

## Rhapsody vs. Dooley
##binning of cell immune cell subsets

#dim(mat_dooley_0)
#dim(mat_pbmc_acute)

## gene overlap Rhapsody, Dooley et al, Explore
rhapsody_dooley_overlapp <- intersect(rownames(mat_dooley_0),rownames(mat_pbmc_acute))

compare_dooley_rhapsody <- data.frame(mat_dooley_0[rhapsody_dooley_overlapp,]) %>% 
  rownames_to_column("gene") %>%
  pivot_longer(cols = -gene) %>%
  mutate(origin = "dooley") %>% 
  bind_rows(
    data.frame(mat_pbmc_acute[rhapsody_dooley_overlapp,]) %>% 
      rownames_to_column("gene") %>% 
      pivot_longer(cols = -gene) %>%
      mutate(origin = "rhapsody")) %>%
  
  
  mutate(name.common = ifelse(grepl("CD14",name),"CD14mono",
                              ifelse(grepl("CD16.monocytes",name,ignore.case = T),"CD16mono",
                                     ifelse(grepl("pDC",name),"pDC",
                                            ifelse(grepl("mDC",name),"mDC",
                                                   ifelse(grepl("NKT",name),"NKT",
                                                          ifelse(grepl("gdT|γδ.T.cells",name),"gdTcell",
                                                                 ifelse(grepl("CD8",name),"CD8T",
                                                                        ifelse(grepl("CD4",name),"CD4T",
                                                                               ifelse(grepl("NK",name),"NK",
                                                                                      ifelse(grepl("B",name),"Bcell",
                                                                                             ifelse(grepl("Unknown|undefined",name),"undefined",
                                                                                                    name)))))))))))) 
common.celltypes <- intersect(filter(compare_dooley_rhapsody,origin=="dooley") %>% pull(name.common),
                              filter(compare_dooley_rhapsody,origin=="rhapsody") %>% pull(name.common))

dooley_hm <- compare_dooley_rhapsody %>% 
  filter(origin=="dooley", name.common %in% common.celltypes) %>% 
  pivot_wider(names_from = gene, values_from = value,id_cols = name.common) %>% 
  column_to_rownames("name.common") %>% 
  ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% 
    as.matrix() %>% 
    t() %>%

  Heatmap(name="Dooley",
          column_title = "Dooley et al.",
          column_title_gp = gpar(fontsize=6),
          
          column_order = common.celltypes,
          col = scaled_01_col,
          cluster_rows = TRUE,
          row_dend_reorder = TRUE,
          show_row_names = TRUE,
          show_heatmap_legend = F,
          row_title_gp = gpar(fontsize = 5),
          row_title_rot = 0,
          row_names_gp = gpar(fontsize = 4),
          row_dend_width = unit(5, "mm"), 
          column_names_gp = gpar(fontsize = 5), 
          column_names_rot = 90,
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 5),
                                      title_gp = gpar(fontsize = 5)),
          width = nrow(.)*unit(.3, "mm"), 
          height = ncol(.)*unit(6, "mm"),
  )

rhapsody_hm <- filter(compare_dooley_rhapsody, origin=="rhapsody", name.common %in% common.celltypes) %>%
  pivot_wider(names_from = gene, values_from = value,id_cols = name.common,values_fn = median) %>% 
  column_to_rownames("name.common") %>% 
  ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% #scale(.))) %>% 
    as.matrix() %>% 
    t() %>%

  Heatmap(name="average\ngene\nexpression",
          column_title = "This study",
          column_title_gp = gpar(fontsize=6),
          column_order = common.celltypes,
          col = scaled_01_col,
          cluster_rows = TRUE,
          row_dend_reorder = TRUE,
          show_row_names = TRUE,
          row_title_gp = gpar(fontsize = 5),
          row_title_rot = 0,
          row_names_gp = gpar(fontsize = 4),
          row_dend_width = unit(5, "mm"), 
          column_names_gp = gpar(fontsize = 5), 
          column_names_rot = 90,
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 5),
                                      title_gp = gpar(fontsize = 5),
                                       title_position = "topcenter"
          ),
          width = nrow(.)*unit(.3, "mm"), 
          height = ncol(.)*unit(6, "mm"),
  )

compare_dooley_rhapsody_hm_new <- dooley_hm + rhapsody_hm

draw(compare_dooley_rhapsody_hm_new, row_dend_side = "left", main_heatmap = "average\ngene\nexpression",auto_adjust = F)

Figure S7E

dim(mat_dooley_0)
## [1] 213  15
row.anno.df <- data.frame(Assay = rownames(mat_dooley_0)) %>% 
  left_join(dap.res,by=c("Assay")) %>% 
  left_join(hpa_24.0,by=c("Assay"="gene")) %>% 
  mutate(secretome_function = ifelse(is.na(secretome_function),"Not secreted", secretome_function)) %>% 
  filter(secretome_function != "Not secreted")

rowAnno <- HeatmapAnnotation(df = row.anno.df %>% transmute(Assay,secretome_location) %>% column_to_rownames("Assay"),
                             which = "row", 
                             show_legend = c(TRUE), 
                             show_annotation_name = F,
                             annotation_name_gp = gpar(fontsize = 5),
                             annotation_legend_param = list(title = "HPA\nclassification",
                                                            title_gp = gpar(fontsize = 5), 
                                                            labels_gp = gpar(fontsize = 5),
                                                            direction="horizontal",
                                                            legend_height = unit(1, "mm"), 
                                                            grid_width = unit(3, "mm"),
                                                            title_position = "topleft"),
                             col = list(secretome_location = secretome_location_cols),
                             simple_anno_size = unit(3, "mm"),
                             na_col = "grey90")

(dooley_day0_hm.hpa.mapping <- mat_dooley_0[row.anno.df$Assay,] %>% 
    t() %>% 
    ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% 
    as.matrix() %>% 
    t() %>% 
    ComplexHeatmap::Heatmap(
      name="average\ngene\nexpression\n",
      col = scaled_01_col,
      right_annotation = rowAnno,
      column_dend_height = unit(2, "mm"), 
      cluster_rows = TRUE,
      row_dend_reorder = TRUE,
      show_row_names = TRUE,
      row_split = row.anno.df$secretome_function,
      row_title_side = "right",
      row_title_gp = gpar(fontsize = 5),
      row_title_rot = 0,
      row_names_gp = gpar(fontsize = 4),
      row_dend_width = unit(4, "mm"), 
      column_names_gp = gpar(fontsize = 5), 
      column_names_rot = 90,
      heatmap_legend_param = list(labels_gp = gpar(fontsize = 5),
                                  title_gp = gpar(fontsize = 5)),
      height = ncol(.)*unit(8, "mm"),
      width = ncol(.)*unit(2,"mm"))
)

Figure S7F

mat_dooley_0 <- dooley_0.avg.wide %>% 
  filter(gene %in% dooley.gene.match$Symbol) %>% 
  column_to_rownames("gene") %>% 
  as.matrix() 

dim(mat_dooley_0)
## [1] 213  15
row.anno.df <- data.frame(Assay = rownames(mat_dooley_0)) %>% 
  left_join(dap.res,by=c("Assay")) %>% 
  left_join(hpa_24.0,by=c("Assay"="gene")) %>% 
  mutate(secretome_function = ifelse(is.na(secretome_function),"Not secreted", secretome_function)) %>% 
  filter(secretome_function == "Not secreted")


(dooley_day0_hm.no.hpa.mapping <- mat_dooley_0[row.anno.df$Assay,] %>% 
    t() %>% 
    ## scale values from 0-1
    as.data.frame() %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(0,1)))) %>% #scale(.))) %>% 
    as.matrix() %>% 
    t() %>% 
    ComplexHeatmap::Heatmap(name="average\ngene\nexpression",
                            col = scaled_01_col,
                            show_heatmap_legend = F,
                            column_dend_height = unit(2, "mm"), 
                            cluster_rows = TRUE,
                            row_dend_reorder = TRUE,
                            show_row_names = TRUE,
                            row_split = row.anno.df$secretome_function,
                            row_title_side = "right",
                            row_title_gp = gpar(fontsize = 5),
                            row_title_rot = 0,
                            row_names_gp = gpar(fontsize = 4),
                            row_dend_width = unit(4, "mm"), 
                            column_names_gp = gpar(fontsize = 5), 
                            column_names_rot = 90,
                            heatmap_legend_param = list(labels_gp = gpar(fontsize = 5),
                                                        title_gp = gpar(fontsize = 5)),
                            height = ncol(.)*unit(8, "mm"),
                            width = ncol(.)*unit(2,"mm"))
)

Figure 4

Protein profile-based patient stratification of disease severity

Supplementary Figure 8

** related to main Figure 4**

Figure S8A

clin_marker_cols <- c("CRP","Creatinine","Parasitemia","Platelets","Bilirubin","ASAT","ALAT","Hemoglobin")

clin_marker_cols <- setNames(brewer.pal(length(clin_marker_cols),name="Set3"), clin_marker_cols)



clinical_variables_4circos <-  subjectTable %>% 
    left_join(clinchem_study_pats_acute.wide, by="study_id") %>% 
    #inner_join(patient_clust,by="study_id") %>% 
    ungroup() %>% 
    pivot_longer(cols = c(plt_count_min,inf_rbc_max,crp_max,hb_min,bili_max,crea_max,"p_alat","p_asat"),
                 names_to = "clin.var", values_to="clin.val",
    ) %>% 
    drop_na(clin.val) %>% 
    group_by(clin.var) %>% 
 mutate(n_group= as.character(n()),
           label_group= factor(paste0('\n n = ', n_group))) %>% 
    mutate(clin.var = case_when(clin.var=="crp_max"~"CRP",
                          clin.var=="p_alat"~"ALAT",
                          clin.var=="p_asat"~"ASAT",
                          clin.var=="plt_count_min"~"Platelets",
                          clin.var=="inf_rbc_max" ~"Parasitemia",
                          clin.var=="bili_max"~"Bilirubin",
                          clin.var=="hb_min" ~"Hemoglobin",
                          clin.var=="crea_max"~"Creatinine",
                          .default=clin.var)) %>% 
    mutate(clin.var = factor(clin.var, levels=names(clin_marker_cols))) 
 
(clin_para_whole_cohort <- clinical_variables_4circos %>% 
    ggplot(aes(x=label_group, y=clin.val, fill=clin.var)) +
    geom_violin(trim=F, show.legend = F, width=.4,lwd=.25) +
    geom_jitter(size=0.05,width = .1, show.legend = F,lwd=.25) +
    geom_boxplot(alpha=.7, outlier.shape = NA, width=.2, show.legend = F,lwd=.25) +
    facet_wrap(~clin.var, scales = "free", nrow = 4,
    labeller = labeller(clin.var = c("Bilirubin"= "Bilirubin\n(\U003BCmol/L)",
                                     "ALAT"="ALT\n(U/L)",
                                     "ASAT"="AST\n(U/L)",
                                     "CRP"="CRP\n(mg/L)",
                                     "Parasitemia"="Parasitemia\n(%)", 
                                     "Creatinine"="Creatinine\n(\U003BCmol/L)",
                                     "Hemoglobin"="Hemoglobin\n(g/dL)",
                                     "Platelets"="Platelet\n(counts)"))) +
    theme_bw(base_size = 6)+
    labs(y="Clinical parameter value",
         x=NULL) +
  scale_fill_manual(values=clin_marker_cols))

Figure S8C

patient_SOFA <- subjectTable %>% dplyr::select(study_id, contains("SOFA"))

who22_severemalaria <- subjectTable %>% 
  transmute(study_id,
            respiratory_distress = case_when(pulm_edema == 1 |
                                               resp_distress == 1 |
                                               ards == 1 ~ 1, 
                                             .default = 0),
            circ_80,
            hb_70 = case_when(hb_min <= 70 ~ 1, 
                              hb_min >70 ~0,
                              .default = NA),
            bili_50,
            crea_265 = case_when(crea_max >= 265 ~ 1, 
                                 crea_max <265 ~ 0,
                                 .default = NA),
            parasitaemia_2 = case_when(inf_rbc_max >= 2 ~ 1,
                                       inf_rbc_max < 2 ~ 0,
                                       .default = NA),
            parasitaemia_5 = case_when(inf_rbc_max >= 5 ~ 1,
                                       inf_rbc_max < 5 ~ 0,
                                       .default = NA)
  )

mat <- who22_severemalaria %>% 
  column_to_rownames("study_id") %>% 
  as.matrix() %>% 
  t()

mat_sofa_total <- data.frame(study_id = colnames(mat)) %>% 
  left_join(patient_SOFA, by="study_id") 

study_id_SOFA.sorted <- mat_sofa_total %>% arrange(-SOFA_total) %>% pull(study_id)

mat <- mat[,study_id_SOFA.sorted]


severesign_count <- who22_severemalaria %>% 
  transmute(study_id,
            respiratory_distress,
            circ_80,
            hb_70,
            bili_50,
            crea_265,
            parasitaemia_5) %>% 
  replace(is.na(.), 0) %>% 
  rowwise() %>%
  mutate(nr_of_severe_signs = sum(c_across(where(is.numeric)))) %>% 
  transmute(study_id,
            nr_of_severe_signs) 

(hm.sofa.clin <- mat %>% 
  Heatmap(name = "Severe malaria symptoms\ndefined by WHO 2015",
          col = c("0"="white","1"="#C51B7D"),
          column_names_gp = gpar(fontsize = 6), 
          na_col = "grey90",
          cluster_columns = F,
          cluster_rows = F,
          show_row_dend = F, 
          show_column_dend = F,
          show_column_names = F,
          top_annotation = HeatmapAnnotation(df = data.frame(study_id = colnames(mat)) %>%
                                               left_join(severesign_count) %>%
                                               column_to_rownames("study_id"),
                                             gp = gpar(fontsize=6),
                                             annotation_legend_param = list(labels_gp = gpar(fontsize = 6),
                                                                            title_gp = gpar(fontsize = 6),
                                                                            direction = "horizontal",
                                                                            title_position = "topcenter",
                                                                            title = "Nr of\nsevere malaria\nsymptoms"),
                                             simple_anno_size = unit(2, "mm"),
                                             annotation_name_gp = gpar(fontsize=6),
                                             col = list(nr_of_severe_signs = circlize::colorRamp2(c(0,6), c("white","orange")))),
          row_title_side = "left",
          row_title_rot = 0,
          row_title_gp = gpar(fontsize = 6),
          column_title_side = "top",
          row_names_gp = gpar(fontsize = 6),
          row_dend_width = unit(0.5, "cm"), 
          column_title_gp = gpar(fontsize = 6),
          column_names_rot = 90,
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                      title_gp = gpar(fontsize = 6), 
                                      title_position = "topcenter",
                                      at = c(0,1),
                                      labels = c("no","yes")),
          bottom_annotation = HeatmapAnnotation(df = data.frame(study_id = colnames(mat)) %>% 
                                left_join(patient_SOFA, by="study_id") %>% 
                                dplyr::select(-study_id) %>% 
                                as.data.frame(),
                              which = 'col', 
                              gp = gpar(fontsize=6),
                              simple_anno_size = unit(2, "mm"),
                              annotation_name_gp = gpar(fontsize=6),
                              col = list(SOFA_total = colorRamp2(c(min(patient_SOFA$SOFA_total,na.rm = TRUE),
                                                                   median(patient_SOFA$SOFA_total,na.rm = TRUE),
                                                                   max(patient_SOFA$SOFA_total,na.rm = TRUE)),
                                                                 c(brewer.pal(3,name="PuBu"))),
                                         SOFA_liver = SOFA_sub_col,
                                         SOFA_cns = SOFA_sub_col,
                                         SOFA_coag = SOFA_sub_col,
                                         SOFA_resp = SOFA_sub_col,
                                         SOFA_cardio = SOFA_sub_col,
                                         SOFA_renal = SOFA_sub_col),
                              show_legend = c(T,F,F,F,F,F), 
                              annotation_legend_param = list(SOFA_total = list(title = "SOFA (total)",
                                                                               labels_gp = gpar(fontsize = 6),
                                                                               title_gp = gpar(fontsize = 6),
                                                                               direction = "horizontal",
                                                                               title_position = "topcenter"
                                                                               ),
                                                             SOFA_cns = list(title="SOFA (subcategorical)",
                                                                             labels_gp = gpar(fontsize = 6),
                                                                             title_gp = gpar(fontsize = 6),
                                                                             direction = "horizontal",
                                                                             title_position = "topcenter"))),
          width = ncol(.)*unit(1.3, "mm"), 
          height = nrow(.)*unit(1.6, "mm"),
          rect_gp = gpar(col = "grey80", lwd = .2),
          border_gp = gpar(col = "black", lty = .5)))

Figure S8D-E

data4_pcaRes_FCmedian <- fc_over_median_M12 %>% 
  filter(Assay %in% c(dap.res %>% filter(FDR==TRUE, abs(logFC)>1) %>% pull(Assay))) %>% 
  pivot_wider(values_from = dNPX, names_from = Assay, id_cols = study_id) %>% column_to_rownames("study_id") 

## PC calculation
pcaRes_FCmedian <- prcomp(data4_pcaRes_FCmedian, center = TRUE, scale. = TRUE)

varExp_FCmedian <- round(pcaRes_FCmedian$sdev^2 / sum(pcaRes_FCmedian$sdev^2) * 100)

#sum(varExp_FCmedian[1:6])

pcaDF_FCmedian <- data.frame(pcaRes_FCmedian$x) %>% 
  rownames_to_column("study_id") %>% dplyr::select(1:10) %>% 
  inner_join(data4_pcaRes_FCmedian %>% rownames_to_column("study_id"), by="study_id")

(pca_FCmedian <- pcaDF_FCmedian %>% 
    ggplot(aes(x=PC1,y=PC2)) +
    geom_point(size=.5) + 
    my_dimred_theme +
    coord_fixed(ratio = 1.75) +
    labs(x=paste0("PC1 (",varExp_FCmedian[1],"%)"),
         y=paste0("PC2 (",varExp_FCmedian[2],"%)"),
         title = "dNPX (delta NPX of acute over convalescence median)",
         caption = paste0("# samples: ",dim(data4_pcaRes_FCmedian)[1],
                          "\n # proteins: ",dim(data4_pcaRes_FCmedian)[2],
                          "\nlogFC>1")
    ))

(acute.dnpx.ellbow <- data.frame(PC = 1:10,
           varExp = varExp_FCmedian[1:10]) %>% 
  ggplot(aes(x=PC, y=varExp)) +
  scale_y_continuous(breaks = seq(0, 35, by = 5)) +
  geom_point(size=.2) +
  geom_line(lwd=.2) +
  theme_minimal() +
  scale_x_continuous(limits=c(1,10), breaks = c(1:10)))

df <- pcaDF_FCmedian %>% 
  dplyr::select(study_id,PC1:PC6) %>% 
  column_to_rownames("study_id") 

set.seed(2023L)
km <- kmeans(df, centers = 3, nstart = 25,iter.max = 100) 

km.res <- data.frame(study_id = rownames(df)) %>% inner_join(data.frame(cluster = km$cluster) %>% rownames_to_column("study_id"), by="study_id") 
patient_clust <- km.res %>%
  inner_join(subjectTable %>% transmute(study_id, SOFA_total),by="study_id") %>% 
  group_by(cluster) %>% 
  summarise(meanSOFA_total = mean(SOFA_total)) %>% 
  arrange(-meanSOFA_total) %>% 
  mutate(severity_lab = c("severe","moderate","mild")) %>% 
  rownames_to_column("rowname") %>% 
  mutate(rowname = as.numeric(rowname)) %>% 
  left_join(km.res %>% transmute(study_id,cluster)) %>% 
  mutate(cluster.orig =  fct_reorder(as.factor(cluster),rowname),
         severity_lab = fct_reorder(as.factor(severity_lab),rowname),
         cluster = fct_reorder(as.factor(rowname),rowname))

patient_clust %>% write_tsv(file = paste0(result.dir,"PatientClustering.tsv"))
patient_clust %>% saveRDS(file = paste0(result.dir,"PatientClustering.rds"))

Figure S8D-F

pca_FCmedian

acute.dnpx.ellbow

(pcaDF_FCmedian_PC1_6_hm <- pcaDF_FCmedian %>% 
  dplyr::select(study_id,PC1:PC6) %>% 
  column_to_rownames("study_id") %>% 
  t() %>% 
  Heatmap(name="PC value",
          column_km = 3,
          show_column_names = F,
          row_names_gp = gpar(fontsize=6),
          row_dend_width = unit(5, "mm"), 
          column_dend_height = unit(5,"mm"),
          column_title_gp = gpar(fontsize = 6), 
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                      title_gp = gpar(fontsize = 6),
                                      legend_height = unit(5, "mm"), 
                                      title_position = "topcenter"))
)

Figure S8G

df_acute_patclust_incl_conv <- data.long %>% 
  inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),by="sample_id") %>% 
  inner_join(patient_clust,by="study_id") %>% 
  
  filter(Time=="Acute") %>% 
  ## adding data for M12 time point
  bind_rows(data.long %>% 
              inner_join(sampleTable_simple %>% dplyr::select(DAid,Time,sample_id,study_id),by="sample_id") %>% 
              inner_join(patient_clust,by="study_id") %>% 
              filter(Time=="M12") %>% 
              mutate(severity_lab = "convalescence")) %>% 
  mutate(severity_lab = factor(as.factor(severity_lab),
                               levels=c("severe","moderate","mild","convalescence"),
                               labels=c("severe","moderate","mild","convalescence"))) 
my_comparisons_severe_conv <- list(c("severe", "moderate"), c("moderate", "mild"), c("severe", "mild"),c("mild","convalescence"))

(liver.tissueleakage.severity.plot <- df_acute_patclust_incl_conv %>%
  filter(Assay %in% c("AGXT","HAO1")) %>% 
  ggplot(aes(x=severity_lab, y=NPX, color=severity_lab, fill=severity_lab)) + 
  geom_violin(trim = F,alpha=.9) +
  geom_jitter(size=0.25,show.legend = F, width = 0.05, alpha=1, color="grey20") +
  geom_boxplot(alpha=.7,width=0.25,outlier.shape = NA,color="black", fatten = 2,lwd=.25,show.legend = F) +
  stat_compare_means(method = "wilcox.test",
                     label.sep = "\n",
                     hide.ns = T,
                     label = "p.signif" ,
                     vjust = .5,
                     size=2,
                     lwd = .2,
                     comparisons =my_comparisons_severe_conv,
                     show.legend = F) +
  facet_wrap(~Assay,ncol = 8,scales = "free_y") +
  theme_minimal() +
  theme(legend.position="bottom",
        axis.text.x = element_blank()) +
  labs(x="",
       color=NULL,
       fill=NULL) +
  scale_color_manual(values= c(patient_kclust3_lab_conv)) + 
    scale_fill_manual(values= c(patient_kclust3_lab_conv))
)

Figure 4A

(acute.dnpx.pca.clustered <- pcaDF_FCmedian %>% 
  inner_join(patient_clust) %>% 
  ggplot(aes(x=PC1,y=PC2, color=cluster)) +
  geom_point(size=.5) +
    scale_color_manual(values=patient_kclust3) +

  labs(color="Cluster",
       title="dNPX") +
  coord_equal(ratio = 1.5)  + theme_minimal())

acute.dnpx.pca.clustered


 ggExtra::ggMarginal(acute.dnpx.pca.clustered, type="density",groupColour = TRUE, groupFill = TRUE)

Figure 4B

my_comparisons <- list(c("1", "2"), c("2", "3"), c("1", "3"))

(clusters_sofa <- subjectTable %>% 
    inner_join(patient_clust,by="study_id") %>% 
    
    ggplot(aes(x=cluster, y=SOFA_total, color=cluster, fill=cluster)) +
    geom_jitter(width = 0.2,show.legend = T, size=0.5,alpha=.7) +
    geom_boxplot(alpha=1,width=0.3,color="black",outlier.colour = NA, fatten = 2,lwd=.25,show.legend = F) +
    labs(title = paste0("Sequential Organ Failure Assessment (SOFA) score")) + 
    scale_color_manual(values=patient_kclust3)+
    scale_fill_manual(values=patient_kclust3) +
    scale_y_continuous(limits = c(0,16)) +
    stat_compare_means(method = "wilcox.test",
                       label.sep = "\n",
                       hide.ns = T,
                       label = "p.signif" ,
                       vjust = .5,
                       size=2,
                       lwd = .2,
                       comparisons =my_comparisons) +
    theme_minimal()+
    theme(legend.position ="none"))

Figure 4C

prot.data.4.corr <- data.long %>%
  inner_join(dap.res,by=c("Assay", "UniProt")) %>% 
  filter(p.adj<=0.05,
         abs(logFC)>1,
  ) %>% 
  pivot_wider(values_from = NPX, names_from = Assay,id_cols = sample_id) %>% 
  inner_join(sampleTable_simple %>% filter(Time=="Acute") %>% transmute(sample_id,study_id), by="sample_id") %>%
  dplyr::select(-sample_id) %>% 
  dplyr::select(study_id, everything()) 


clinical.feat.list <- c("inf_rbc_max", "resp_rate_max","sat", "syst_bp_min",
                        "p_alat", "p_asat",
                        "hb_min","wbc_count","plt_count_min","crp_max","bili_max","crea_max","SOFA_cns","SOFA_liver","SOFA_renal","SOFA_coag","SOFA_resp","SOFA_total")
  
clin.data.4.corr <-
  subjectTable %>% 
      left_join(clinchem_study_pats_acute.wide, by="study_id") %>% 

  dplyr::select(study_id, all_of(clinical.feat.list))


my_comparisons_severe <- list(c("severe", "moderate"), c("moderate", "mild"), c("severe", "mild"))

df <- clin.data.4.corr %>% 
  dplyr::select(study_id, clinical.feat.list, -contains("SOFA")) %>% 
  pivot_longer(cols= -study_id) %>% 
  inner_join(patient_clust) %>% 
  na.omit() %>% 
  group_by(name, severity_lab) %>% 
  mutate(n_group= as.character(n()),
                  label_group= factor(paste0('n = ', n_group))) %>% 
    ungroup() %>% 
  group_by(name) %>% 
   mutate(label_pos = min(value),
          subcat = case_when(name %in% c("bili_max", "p_alat","p_asat") ~ "Liver function",
                             name %in% c("hb_min","wbc_count", "plt_count") ~ "Blood cells",
                             name %in% c("resp_rate_max","sat","syst_bp_min") ~ "Circulation",
                             .default=NA)) %>% 
   ungroup() %>% 
  mutate(name = factor(name, levels = c("crp_max","crea_max","inf_rbc_max",
                                         "hb_min","wbc_count","plt_count_min",
                                         "bili_max","p_asat","p_alat",
                                         "resp_rate_max","sat","syst_bp_min"
                                         ))) 

single_facet_fun = function(data)( 
  data %>% 
    ggplot(aes(x=severity_lab, y=value, fill= severity_lab)) +
    geom_violin(trim=F, show.legend = F, width=.6,lwd=.25) +
    geom_jitter(size=0.05,width = .1, show.legend = F) +
    geom_boxplot(aes(fill=severity_lab),alpha=.7, outlier.shape = NA,width=.2, show.legend = F,lwd=.25) +
    theme_bw(base_size = 6) +
    scale_y_continuous(expand=c(.2,0))+
    facet_grid(~label_name) +
    theme(axis.title.x = element_blank()) +
    scale_fill_manual(values=patient_kclust3_lab) +
    stat_compare_means(method = "wilcox.test",
                       label.sep = "\n",
                       hide.ns = T,
                       label = "p.signif", 
                       vjust = 0.5,
                       size=2,
                       comparisons = my_comparisons_severe) +
    labs(fill=NULL,
         x=NULL) +
    scale_x_discrete(labels=data$label_group))


## 
p_list <- df %>% 
  mutate(name = factor(name, levels = c("crp_max","crea_max","inf_rbc_max",
                                         "hb_min","wbc_count","plt_count_min",
                                         "bili_max","p_asat","p_alat",
                                         "resp_rate_max","sat","syst_bp_min"
                                         )),
         label_name = case_when(name == "bili_max" ~ "Bilirubin\n(\U003BCmol/L)",
                                name == "crea_max" ~ "Creatinine\n(\U003BCmol/L)",
                                name == "crp_max" ~ "CRP\n(mg/L)",
                                name == "hb_min" ~ "Hemoglobin\n(g/L)",
                                name == "inf_rbc_max" ~ "Parasitemia\n(%)",
                                name == "plt_count_min" ~ "Platelet\n(counts)",
                                name == "sat" ~ "Saturation\n(%)",
                                name == "p_asat" ~ "AST\n(U/L)",
                                name == "p_alat" ~ "ALT\n(U/L)",
                                name == "resp_rate_max" ~ "Respirations rate\n(bpm)",
                                name == "wbc_count" ~ "White blood cells\n(counts)",
                                name == "syst_bp_min" ~ "Systolic blood\npressure (mmHg)"
               ),
         label_unit = case_when(name == "bili_max" ~ "unit",
                                name == "crea_max" ~ "unit",
                                name == "crp_max" ~ "mg/L",
                                name == "hb_min" ~ "g/dL",
                                name == "inf_rbc_max" ~ "%",
                                name == "plt_count_min" ~ "counts",
                                name == "sat" ~ "%",
                                name == "p_asat" ~ "unit",
                                name == "p_alat" ~ "unit",
                                name == "resp_rate_max" ~ "bpm",
                                name == "wbc_count" ~ "counts",
                                name == "syst_bp_min" ~ "mmHg"
               )) %>% 
  arrange(name) %>% 
  group_by(name) %>% 
  nest() %>% 
  mutate(single_plot = purrr::map(data, single_facet_fun))
         

clin.data.severity.groups.new <- wrap_plots(p_list$single_plot, ncol=3)

clin.data.severity.groups.new.data <- p_list %>%
  unnest(data) %>% 
  compare_means(
    value ~ severity_lab, data = ., group.by = "name",
    method = "wilcox.test") %>% 
  transmute(name, group1, group2, p, p.adj, p.signif, method) 

## show plot
clin.data.severity.groups.new

Figure 4D

data_nested.patclust <- data.long %>% 
  inner_join(sampleTable_simple, by="sample_id") %>% 
  inner_join(patient_clust,by="study_id") %>% 
  mutate(all_vs_1 = ifelse(cluster.orig %in% c("2","3"),"rest",
                           ifelse(cluster.orig =="1","1",NA)),
         all_vs_2 = ifelse(cluster.orig %in% c("1","3"),"rest",
                           ifelse(cluster.orig =="2","2",NA)),
         all_vs_3 = ifelse(cluster.orig %in% c("2","1"),"rest",
                           ifelse(cluster.orig =="3","3",NA))) %>% 
  group_by(UniProt,Assay) %>% 
  nest()

g_vs_conv <- data_nested.patclust %>%
   mutate(lme.res = purrr::map(data, ~ lmer(NPX ~ Time * severity_lab + (1|study_id), REML = F,
                                           data = .x %>% dplyr::filter(Time!="D10"))),
         lme.tidy = purrr::map(lme.res, ~ broom.mixed::tidy(.)),
         posthoc.time_exposure = purrr::map(lme.res, ~ summary(contrast(emmeans(., ~ Time * severity_lab), method = "pairwise")) %>% tibble())
         )

g_vs_conv_padj <- g_vs_conv %>% 
  unnest(cols="posthoc.time_exposure") %>% 
  filter(contrast %in%c("Acute severe - M12 severe",
                        "Acute moderate - M12 moderate",
                        "Acute mild - M12 mild")) %>% 
      transmute(Assay, UniProt, contrast, estimate,SE,df,t.ratio,p.value) %>% 
  ungroup() %>% 
    group_by(contrast) %>% 
  mutate(p.adj = p.adjust(p.value, method="fdr"),
                  FDR = ifelse(p.adj <= 0.01, TRUE,FALSE)) %>% 
    ungroup() %>% 
  arrange(p.adj)



(severity_groups_conv_volc <- g_vs_conv_padj %>% 
  group_by(contrast) %>% 
  mutate(severity_lab = case_when(grepl("severe",contrast) ~ "severe",
                                    grepl("moderate",contrast) ~ "moderate",
                                    grepl("mild",contrast) ~ "mild",
                                    .default = NA),
         severity_lab = factor(severity_lab, levels=c("severe","moderate","mild")),
         sig_col = case_when(FDR==T ~ severity_lab,
                             .default = NA)) %>% 
  #slice_max(order_by = estimate, n=1) %>% 
    ggplot(aes(x=severity_lab, y= estimate, color=sig_col)) +
    geom_jitter(width=.1,alpha=.2, show.legend = F,size=.5, shape=16) +
    ggrepel::geom_text_repel(data= . %>% 
                               group_by(severity_lab) %>% slice_max(n=8,order_by = estimate), aes(label=Assay), show.legend = F,force = .5,
                             segment.size=0.2,
                            segment.alpha=.1,
                            size=1.5,max.overlaps = 15, color="gray35") +
    ggrepel::geom_text_repel(data= . %>% 
                               group_by(severity_lab) %>% slice_min(n=8,order_by = estimate), aes(label=Assay), show.legend = F,force = .5,
                             segment.size=0.2,
                            segment.alpha=.1,
                            size=1.5, max.overlaps = 15, color="gray35") +
    geom_hline(yintercept=0, 
               linetype = 3) +
    scale_color_manual(values = patient_kclust3_lab,na.value = "grey") +
    labs(x=NULL,
         title="Each group vs convalecence",
         subtitle = "mixed effect model approach - acute_severity vs m12_severity",
         caption="FDR < 0.01"))

Figure 4E

require(UpSetR) # https://cran.r-project.org/web/packages/UpSetR/vignettes/basic.usage.html

g_vs_conv_padj_tmp.list <- g_vs_conv_padj %>% 
  group_by(contrast) %>% 
  mutate(severity_lab = case_when(grepl("severe",contrast) ~ "severe",
                                    grepl("moderate",contrast) ~ "moderate",
                                    grepl("mild",contrast) ~ "mild",
                                    .default = NA),
         severity_lab = factor(severity_lab, levels=c("severe","moderate","mild")),
         sig_col = case_when(FDR==T ~ severity_lab,
                             .default = NA)) %>%
    filter(estimate>1) %>% 
  group_by(severity_lab) %>%
  summarise(list = list(Assay)) %>%
  mutate(list = setNames(list, severity_lab)) %>%
  pull(list)

severe_log1 <- intersect(setdiff(g_vs_conv_padj_tmp.list$severe, g_vs_conv_padj_tmp.list$mild),
                         setdiff(g_vs_conv_padj_tmp.list$severe, g_vs_conv_padj_tmp.list$moderate))

pdf(paste0(result.tmp.dir,"severity_daps_upset.pdf"),width = 7, height = 3) 
(UpSetR::upset(fromList(g_vs_conv_padj_tmp.list),
              order.by = "freq",point.size = 2,
              text.scale = 1.2,
             #mb.ratio = c(0.6, 0.4),
              sets.bar.color = c("severe" = "#ca0020","moderate" = "#f4a582", "mild" = "#92c5de"),
              keep.order = TRUE,
              mainbar.y.label = "Number of Proteins", 
              sets.x.label = "Proteins per group"))
dev.off()
## quartz_off_screen 
##                 2

Supplementary Table S3

library(gtsummary)
(severityTable <- subjectTable %>% 
  mutate(wbc_count = as.numeric(wbc_count),
         sat = as.numeric(sat)) %>% 
  left_join(patient_clust, by="study_id") %>% 
    tbl_summary(include = c(inf_rbc_max,
                            crp_max,
                            bili_max,
                            crea_max,
                            sat,
                            resp_rate_max,
                            syst_bp_min,
                            plt_count_min,
                            hb_min),
              by = severity_lab, # split table by group
              statistic = list(
                all_continuous() ~ "{median} ({min}-{max})",
                all_categorical() ~ "{n} / {N} ({p}%)"
              ),
              digits = all_continuous() ~ 2,
              missing_text = "(Missing)") %>% 
  add_n() %>% # add column with total number of non-missing observations
  add_p() %>% # test for a difference between groups
  modify_header(label = "**Variable**") %>% # update the column header
  bold_labels())
Variable N severe, N = 171 moderate, N = 361 mild, N = 191 p-value2
inf_rbc_max 72 3.00 (0.01-8.00) 0.80 (0.10-5.00) 0.20 (0.01-1.80) 0.003
crp_max 72 208.00 (96.00-326.00) 156.50 (28.00-381.00) 101.00 (14.00-246.00) 0.002
bili_max 64 25.00 (12.00-135.00) 21.00 (10.00-100.00) 19.00 (5.00-173.00) 0.3
    (Missing) 0 4 4
crea_max 72 108.00 (68.00-828.00) 95.00 (47.00-193.00) 86.00 (49.00-133.00) 0.3
sat 72 0.8
    92 0 / 17 (0%) 0 / 36 (0%) 2 / 19 (11%)
    93 0 / 17 (0%) 2 / 36 (5.6%) 0 / 19 (0%)
    94 0 / 17 (0%) 1 / 36 (2.8%) 0 / 19 (0%)
    95 2 / 17 (12%) 4 / 36 (11%) 2 / 19 (11%)
    96 1 / 17 (5.9%) 4 / 36 (11%) 0 / 19 (0%)
    97 2 / 17 (12%) 5 / 36 (14%) 4 / 19 (21%)
    98 6 / 17 (35%) 10 / 36 (28%) 6 / 19 (32%)
    99 4 / 17 (24%) 4 / 36 (11%) 4 / 19 (21%)
    100 2 / 17 (12%) 6 / 36 (17%) 1 / 19 (5.3%)
resp_rate_max 72 20.00 (14.00-48.00) 20.00 (12.00-32.00) 18.00 (13.00-42.00) 0.3
syst_bp_min 72 100.00 (70.00-120.00) 106.50 (70.00-139.00) 108.00 (76.00-125.00) 0.13
plt_count_min 71 32.00 (14.00-112.00) 63.00 (28.00-134.00) 99.00 (51.00-183.00) <0.001
    (Missing) 0 0 1
hb_min 72 108.00 (64.00-157.00) 122.00 (66.00-165.00) 113.00 (66.00-159.00) 0.2
1 Median (Minimum-Maximum); n / N (%)
2 Kruskal-Wallis rank sum test; Fisher’s exact test
subjectTable %>% 
  mutate(wbc_count = as.numeric(wbc_count),
         sat = as.numeric(sat)) %>% 
  left_join(patient_clust, by="study_id") %>% 
  transmute(study_id, 
            severity_lab,
            diff_acuteSample_treatment,diff_acuteSample_treatment.abs,
            diff_acuteSample_spt_current,diff_acuteSample_spt_current.abs) %>% 
  pivot_longer(cols = -c(study_id,severity_lab)) %>% 

compare_means(
    value ~ severity_lab, data = ., group.by = "name",
    method = "wilcox.test")
## # A tibble: 12 × 9
##    name                 .y.   group1 group2     p p.adj p.format p.signif method
##    <chr>                <chr> <chr>  <chr>  <dbl> <dbl> <chr>    <chr>    <chr> 
##  1 diff_acuteSample_tr… value severe moder… 0.329     1 0.33     ns       Wilco…
##  2 diff_acuteSample_tr… value severe mild   0.289     1 0.29     ns       Wilco…
##  3 diff_acuteSample_tr… value moder… mild   0.657     1 0.66     ns       Wilco…
##  4 diff_acuteSample_tr… value severe moder… 0.220     1 0.22     ns       Wilco…
##  5 diff_acuteSample_tr… value severe mild   0.289     1 0.29     ns       Wilco…
##  6 diff_acuteSample_tr… value moder… mild   0.801     1 0.80     ns       Wilco…
##  7 diff_acuteSample_sp… value severe moder… 0.904     1 0.90     ns       Wilco…
##  8 diff_acuteSample_sp… value severe mild   0.335     1 0.34     ns       Wilco…
##  9 diff_acuteSample_sp… value moder… mild   0.219     1 0.22     ns       Wilco…
## 10 diff_acuteSample_sp… value severe moder… 0.904     1 0.90     ns       Wilco…
## 11 diff_acuteSample_sp… value severe mild   0.335     1 0.34     ns       Wilco…
## 12 diff_acuteSample_sp… value moder… mild   0.219     1 0.22     ns       Wilco…

Supplemementary Table S4

#clin.data.severity.groups.new.data %>%
 # write_tsv(paste0(result.dir,"Supplementary_TableS4_ClinicalChemistry_severity_groups.tsv"))

clin.data.severity.groups.new.data %>% head()
## # A tibble: 6 × 7
##   name     group1   group2          p p.adj p.signif method  
##   <fct>    <chr>    <chr>       <dbl> <dbl> <chr>    <chr>   
## 1 crp_max  severe   moderate 0.0191   0.53  *        Wilcoxon
## 2 crp_max  severe   mild     0.000781 0.027 ***      Wilcoxon
## 3 crp_max  moderate mild     0.0860   1     ns       Wilcoxon
## 4 crea_max severe   moderate 0.281    1     ns       Wilcoxon
## 5 crea_max severe   mild     0.124    1     ns       Wilcoxon
## 6 crea_max moderate mild     0.381    1     ns       Wilcoxon

Figure S8A

prot.input <- prot.data.4.corr %>% column_to_rownames("study_id")
clin.input <- clin.data.4.corr %>% dplyr::select(study_id,c(plt_count_min,inf_rbc_max,crp_max,hb_min,bili_max,crea_max,p_alat,p_asat)) %>% #,contains("SOFA")) %>%
  column_to_rownames("study_id")

cor.res <- prot.input[rownames(clin.input),] %>% 
  correlation::correlation(data2 = clin.input,
                           method = "spearman", 
                           redundant = F, 
                           p_adjust = "fdr") %>% 
  tibble()
df <- cor.res %>%
  filter(n_Obs >= 37, 
         p<=0.05,
         abs(rho)>=0.45
         ) %>% 
  transmute(from=Parameter2, 
            to=Parameter1,
            value=rho) %>% 
  group_by(to) %>% 
  mutate(n_prot =n()) %>% 
  ungroup() %>% 
  group_by(from) %>% 
  mutate(n_clin = n()) %>% 
  ungroup() %>% 
  arrange(desc(n_prot),n_clin) %>% 
   mutate(from = case_when(from=="crp_max"~"CRP",
                          from=="p_alat"~"ALT",
                          from=="p_asat"~"AST",
                          from=="plt_count_min"~"Platelets",
                          from=="inf_rbc_max" ~"Parasitemia",
                          from=="bili_max"~"Bilirubin",
                          from=="hb_min" ~"Hemoglobin",
                          from=="crea_max"~"Creatinine",
                          .default=from)) 
  
df
## # A tibble: 171 × 5
##    from  to    value n_prot n_clin
##    <chr> <chr> <dbl>  <int>  <int>
##  1 CRP   CTSL  0.471      3     22
##  2 CRP   ICAM1 0.489      3     22
##  3 CRP   KYNU  0.467      3     22
##  4 CRP   PTS   0.462      3     22
##  5 CRP   PVR   0.450      3     22
##  6 ALT   CTSL  0.463      3     36
##  7 ALT   ICAM1 0.557      3     36
##  8 ALT   KYNU  0.467      3     36
##  9 ALT   PTS   0.525      3     36
## 10 ALT   PVR   0.528      3     36
## # ℹ 161 more rows
#string <- unique(df$from) 
#string <- setdiff(unique(df$from),names(clin_marker_cols))
#col.grid_clin <- setNames(sample(brewer.pal(length(string),name="Set1")),string)

string_proteins <- unique(df$to)
col.grid.prot <- setNames(rep("grey80",length(string_proteins)), string_proteins)



col.grid <- c(clin_marker_cols,
              #col.grid_clin, 
              col.grid.prot)

## highlight
# three-column data frame in which the first two columns correspond to row names and column names in the matrix, and the third column corresponds to the graphic parameters
border_df = data.frame(c("Parasitemia"), c("CALCA"), c(1))


pdf(paste0(result.tmp.dir,"chordDiagram.pdf")) #width 6.9

circos.par(gap.after = c(rep(1, length(unique(df[[1]]))-1), 15, 
                         rep(1, length(unique(df[[2]]))-1), 15))
chordDiagram(df,
            #  big.gap = 25,
             grid.col = col.grid,
             #annotationTrack = "grid",
                        big.gap = 10,
            small.gap = 1,
link.border = border_df,
             annotationTrack = NULL,
             preAllocateTracks = list(track.height = .1))#max(strwidth(unlist(dimnames(df))))))
circos.track(track.index = 1, panel.fun = function(x, y) {
  circos.text(CELL_META$xcenter, 
              CELL_META$ylim[1],
              CELL_META$sector.index,
              facing = "clockwise",
              cex = 0.6,
              niceFacing = TRUE, 
              adj = c(0, 0.9))
},
bg.border = NA)

#
dev.off()
## quartz_off_screen 
##                 2
circos.clear()

Figure 5

Identification of severity-associated plasma proteomic profiles

## WGCNA
## https://bioinformaticsworkbook.org/tutorials/wgcna.html#gsc.tab=0
#install.packages("BiocManager")
#BiocManager::install("WGCNA")

## data wrangling
selected.assays.wcna <- dap.res %>% filter(p.adj <= 0.01) %>% pull(Assay)

## requires: rows = treatments and columns = gene probes
input_mat <- data.wide %>% 
  inner_join(sampleTable_simple %>% dplyr::select(DAid,study_id,Time, sample_id),by="sample_id") %>% 
  inner_join(subjectTable %>% dplyr::select(study_id),by="study_id") %>% 
  filter(Time=="Acute") %>% 
  column_to_rownames("sample_id") %>% 
  ## restricting to proteins, significant abundant over convalescence (m12 samples)
  dplyr::select(selected.assays.wcna) %>% 
  as.matrix() %>%
  scale()

input_mat[1:5,1:10]
##                   TNFRSF8       IL10      CXCL9        CD74   TNFRSF1B
## 2011PT01|Acute -0.7370011 -1.1852994 -1.4157459  0.08771475 -1.9048313
## 2011PT04|Acute -0.6779312  0.3667134 -0.0943544 -0.19212623  0.2678492
## 2011PT05|Acute  0.1403045  1.0528265  0.5657621  1.29297919  0.3504350
## 2011PT06|Acute  0.2332304 -1.7527932 -1.0945056 -0.41377242 -0.4221094
## 2011PT07|Acute  0.9822293  1.4187290  0.7498430  1.43859264  1.2466066
##                     VCAM1     PLA2G2A     IL18BP       CSF1     B4GALT1
## 2011PT01|Acute -1.1412591 -1.01940457 -1.4608293 -1.6021606 -0.54555371
## 2011PT04|Acute -0.3286294  0.09020523 -0.5969576 -0.3028854 -0.45244260
## 2011PT05|Acute  0.4595043  0.74644622  0.5612046  0.1410837  1.00463269
## 2011PT06|Acute -0.2196398  0.29812935 -0.9891447 -0.5298451  0.04218177
## 2011PT07|Acute  0.9852817  1.00324357  1.1329858  1.2435433  1.42461678
dim(input_mat)
## [1]  72 703

Set up

allowWGCNAThreads()          # allow multi-threading (optional)
## Allowing multi-threading with up to 10 threads.
#> Allowing multi-threading with up to 4 threads.

# Choose a set of soft-thresholding powers
powers = c(c(1:10), seq(from = 12, to = 20, by = 2))

# Call the network topology analysis function
sft = pickSoftThreshold(input_mat,             # <= Input data
                        #blockSize = 30,
                        powerVector = powers,
                        verbose = 5
)
## pickSoftThreshold: will use block size 703.
##  pickSoftThreshold: calculating connectivity for given powers...
##    ..working on genes 1 through 703 of 703
##    Power SFT.R.sq  slope truncated.R.sq  mean.k. median.k. max.k.
## 1      1   0.0295 -0.368          0.716 162.0000  1.62e+02 289.00
## 2      2   0.4720 -1.210          0.864  58.7000  5.39e+01 158.00
## 3      3   0.6750 -1.480          0.913  26.3000  2.17e+01  97.20
## 4      4   0.7360 -1.680          0.962  13.4000  9.78e+00  63.90
## 5      5   0.7860 -1.700          0.969   7.4900  4.66e+00  44.00
## 6      6   0.8160 -1.740          0.958   4.4600  2.44e+00  31.30
## 7      7   0.8150 -1.770          0.918   2.7900  1.34e+00  22.90
## 8      8   0.8560 -1.770          0.973   1.8200  7.88e-01  17.10
## 9      9   0.8840 -1.780          0.968   1.2200  4.80e-01  13.00
## 10    10   0.8860 -1.790          0.940   0.8480  2.91e-01  10.10
## 11    12   0.2960 -2.610          0.144   0.4370  1.13e-01   6.27
## 12    14   0.3000 -2.550          0.150   0.2430  4.86e-02   4.08
## 13    16   0.3440 -3.540          0.322   0.1440  2.05e-02   2.74
## 14    18   0.3370 -3.380          0.298   0.0904  8.94e-03   1.91
## 15    20   0.3340 -3.270          0.307   0.0595  4.31e-03   1.43
#sft$powerEstimate

#### Scale independence & mean connectivity

sft_tibble <- as_tibble(sft$fitIndices)

plot.si <- sft_tibble %>% 
  ggplot(aes(x=Power,
             y=-sign(slope)*SFT.R.sq)) +
  geom_point() +
  geom_label(aes(label=Power)) +
  geom_hline(yintercept = 0.9, color="darkred") +
  theme_minimal() +
  labs(title = "Scale independence",
       y="Scale Free Topology Model fit\n signed R^2",
       x= "Soft Threshold (power")

plot.meank <- sft_tibble %>% 
  ggplot(aes(x=Power,
             y=mean.k.)) +
    geom_label(aes(label=Power)) +
    theme_minimal() +
  labs(title="Mean connectivity",
       x="Soft Threshold (power)",
       y="Mean Connectivity")

plot.si + plot.meank

##Build co-expression network

picked_power = 6#sft$powerEstimate#6
temp_cor <- cor       
cor <- WGCNA::cor         # Force it to use WGCNA cor function (fix a namespace conflict issue)
netwk <- blockwiseModules(input_mat,  # <= input here
                          # == Adjacency Function ==
                          power = picked_power,  # <= power here
                          networkType = "signed",#"signed hybrid",#"signed",
                          # == Tree and Block Options ==
                          deepSplit = 4, #sensitive module detection should be to module splitting, 0 least and 4 most sensitive
                          pamRespectsDendro = F,
                          # detectCutHeight = 0.75,
                          minModuleSize = 30, 
                          maxBlockSize =ncol(input_mat),#4000, 
                          # == Module Adjustments ==
                          reassignThreshold = 0,
                          mergeCutHeight = 0.25,
                          # == TOM == Archive the run results in TOM file (saves time)
                          saveTOMs = T,
                          saveTOMFileBase = "ER",
                          # == Output Options
                          numericLabels = T,
                          verbose = 3)
##  Calculating module eigengenes block-wise from all genes
##    Flagging genes and samples with too many missing values...
##     ..step 1
##  ..Working on block 1 .
##     TOM calculation: adjacency..
##     ..will use 10 parallel threads.
##      Fraction of slow calculations: 0.000000
##     ..connectivity..
##     ..matrix multiplication (system BLAS)..
##     ..normalization..
##     ..done.
##    ..saving TOM for block 1 into file ER-block.1.RData
##  ....clustering..
##  ....detecting modules..
##  ....calculating module eigengenes..
##  ....checking kME in modules..
##      ..removing 82 genes from module 1 because their KME is too low.
##      ..removing 5 genes from module 2 because their KME is too low.
##      ..removing 13 genes from module 3 because their KME is too low.
##      ..removing 2 genes from module 6 because their KME is too low.
##  ..merging modules that are too close..
##      mergeCloseModules: Merging modules whose distance is less than 0.25
##        Calculating new MEs...
cor <- temp_cor     # Return cor function to original namespace
##### Cluster Dendrogram
# Convert labels to colors for plotting
mergedColors = labels2colors(netwk$colors)
# Plot the dendrogram and the module colors underneath
(cluster_dendro <- plotDendroAndColors(
  netwk$dendrograms[[1]],
  mergedColors[netwk$blockGenes[[1]]],
  "Module colors",
  dendroLabels = FALSE,
  hang = 0.03,
  addGuide = TRUE,
  guideHang = 0.05 ))

## $mar
## [1] 1 5 0 1
module_df <- data.frame(
  assay_id = names(netwk$colors),
  Assay = gsub("\\_.*","",names(netwk$colors)),
  colors = labels2colors(netwk$colors)
)

module_df[1:5,]
##   assay_id    Assay    colors
## 1  TNFRSF8  TNFRSF8 turquoise
## 2     IL10     IL10     brown
## 3    CXCL9    CXCL9     brown
## 4     CD74     CD74     brown
## 5 TNFRSF1B TNFRSF1B turquoise
tmp <- unique(module_df$colors)
module.cols <- setNames(tmp, tmp)

Supplementary Figure 9

Figure S9A

## how many proteis in each module
(module_overview <- module_df %>% 
  group_by(colors) %>% 
  count() %>% 
  
  ggplot(aes(x = fct_reorder(colors,-n), y = n, fill = colors, label = n)) +
         geom_bar(stat = "summary", position = "dodge", show.legend = F) +
  geom_text(stat = "sum", vjust = -0.5,show.legend = F, size=2) +
  scale_y_continuous(#limits=c(0,300),
                     expand = c(0, 20)) +
   scale_x_discrete(expand = c(0,-1)) +
  scale_fill_manual(values=module.cols) +
  theme_minimal() +
  theme(axis.text.x = element_blank(),
    axis.text = element_text(size=6), 
    axis.title = element_text(size=6), 
    axis.ticks.x = element_blank()
    ) + 
  labs(title = "WGCNA analysis - protein network modules",
       subtitle = paste0("based on ",dim(input_mat)[2]," proteins (differential abundant proteins)\n",
                         "profiled in ",dim(input_mat)[1]," acute malaria samples"),
       x="WGCNA protein modules",
       y="n Proteins") 
)

#### generate and export networks for all modules

assays_of_interest = module_df #%>%
  #subset(colors %in% c("turquoise"))

npx_of_interest = input_mat[,assays_of_interest$assay_id]
npx_of_interest[1:5,1:5]
##                   TNFRSF8       IL10      CXCL9        CD74   TNFRSF1B
## 2011PT01|Acute -0.7370011 -1.1852994 -1.4157459  0.08771475 -1.9048313
## 2011PT04|Acute -0.6779312  0.3667134 -0.0943544 -0.19212623  0.2678492
## 2011PT05|Acute  0.1403045  1.0528265  0.5657621  1.29297919  0.3504350
## 2011PT06|Acute  0.2332304 -1.7527932 -1.0945056 -0.41377242 -0.4221094
## 2011PT07|Acute  0.9822293  1.4187290  0.7498430  1.43859264  1.2466066
## columns: Assays
## rows: sample_id

TOM = TOMsimilarityFromExpr(npx_of_interest,
                            power = picked_power)
## TOM calculation: adjacency..
## ..will use 10 parallel threads.
##  Fraction of slow calculations: 0.000000
## ..connectivity..
## ..matrix multiplication (system BLAS)..
## ..normalization..
## ..done.
# Add gene names to row and columns
row.names(TOM) = colnames(npx_of_interest)
colnames(TOM) = colnames(npx_of_interest)

edge_list = data.frame(TOM) %>%
  rownames_to_column("Assay1") %>% 
  pivot_longer(cols=-Assay1,names_to = "Assay2",values_to = "adjacency") %>% 
  distinct() %>%
    filter(Assay1!=Assay2) %>% 
  right_join(module_df %>% transmute(module1 = colors,
                                     Assay1 = Assay)) %>% 
  right_join(module_df %>% transmute(module2 = colors,
                                     Assay2 = Assay)) %>% 
  na.omit()

Figure 5A

##Heatmap - protein adjacency

mat <- cor(npx_of_interest, method = "pearson")
row.anno.df <- data.frame(assay_id = rownames(mat)) %>% left_join(module_df) %>% dplyr::rename(Module = colors) 

(assay_adj_hm <- mat %>% 
  Heatmap(name="protein-protein correlation r",
          right_annotation = HeatmapAnnotation(df = row.anno.df %>% transmute(Module),
                                               col = list(Module = module.cols), 
                                               which = "row",
                                               simple_anno_size = unit(1, "mm"),
                                               show_annotation_name = F,
                                               annotation_name_rot = 0,
                                               annotation_name_gp = gpar(fontsize=6),

                                               annotation_name_side = "top",
                                               show_legend = F,
                                               annotation_legend_param = list(title_gp = gpar(fontsize = 6), 
                                                                              labels_gp = gpar(fontsize = 6))),
          row_split = row.anno.df$Module,
          column_split = row.anno.df$Module,
          row_gap = unit(0, "mm"),
          column_gap = unit(0, "mm"), 
          row_dend_width = unit(3, "mm"),
          row_dend_gp = gpar(lwd=.1),
          column_dend_gp = gpar(lwd=.1),
          column_dend_height = unit(3, "mm"), 
          border = TRUE,
          border_gp = gpar(lwd=.1),
          column_title = NULL,
          row_title = NULL,
          show_row_names = F,
          show_column_names = F,
          heatmap_legend_param = list(labels_gp = gpar(fontsize = 6),
                                      title_gp = gpar(fontsize = 6),
                                      direction = "horizontal",
                                      legend_width = unit(2, "cm"),
                                      grid_height = unit(.2, "cm"))
          ))

# Get Module Eigengenes per cluster
MEs0 <- moduleEigengenes(input_mat, mergedColors)$eigengenes

# Reorder modules so similar modules are next to each other
MEs0 <- orderMEs(MEs0)
module_order = names(MEs0) %>% gsub("ME","", .)

# Add treatment names
#MEs0$DAid <- row.names(MEs0)

# tidy data
mME <- MEs0 %>%
  rownames_to_column("sample_id") %>% 
  pivot_longer(names_to = "module", values_to = "module_eigengenes" ,cols = -sample_id) %>%
      separate(sample_id, "\\|", into = c("study_id","Time"),remove = F) %>% 
  mutate(module = gsub("ME", "", module),
         module = factor(module, levels = module_order)) %>% 
  inner_join(subjectTable, 
             by="study_id") 

Figure 5B

## Module-trait relationship

corr_module_eigengene_meta_res <- mME %>% 
  dplyr::select(module, module_eigengenes,contains("SOFA")) %>% 
  group_by(module) %>% 
  correlation(p_adjust = "fdr") 

df <- tibble(corr_module_eigengene_meta_res) %>% 
  filter(Parameter1=="module_eigengenes") %>% 
    mutate(r4fill = case_when(p>0.05 ~ 0,
                              .default=r))  
(module_trait_plot <- ggplot(data = df, 
                             aes(x=Parameter2, y=Group, fill=r4fill,lable=r)) +
    geom_tile() +
    geom_text(aes(label = paste0(r %>% round(2)),
                  color = ifelse(r4fill==0, "grey20", "black")),
              size=1) +
    scale_colour_identity() +
    theme_bw() +
    scale_fill_gradient2(
      low = "blue",
      high = "red",
      mid = "white",
      midpoint = 0,
      limit = c(-1,1)) +
    labs(title = "Module-trait Relationships",
         y="WGCNA modules",
         x = NULL, 
         fill="rho") +
    theme(#axis.text.y = element_text(color= rev(c("yellow","turquoise","red","grey","green","brown","blue"))),
      axis.text.y = element_text(color= rev(c("yellow","turquoise","red","grey","green","brown","blue"))),
          axis.text.x = element_text(angle=45, hjust=1)))

#### Module membership

###  Get Module Eigengenes per cluster
MEs <- moduleEigengenes(input_mat, mergedColors)$eigengenes

## calculate Module membership
geneModuleMembership <- as.data.frame(cor(input_mat, MEs, use = "p")) 

geneModuleMembership.tidy <- geneModuleMembership %>%
  rownames_to_column("Assay") %>% 
  pivot_longer(cols = -Assay) %>% 
  transmute(Assay,
            Module = str_remove(name, "ME"),
            gMM = value)

## calculate pvalue for geneModuleMembership
MMPvalue.tidy <- as.data.frame(corPvalueStudent(as.matrix(geneModuleMembership), nrow(input_mat))) %>%
  rownames_to_column("Assay") %>% 
  pivot_longer(cols = -Assay) %>% 
  transmute(Assay,
            Module = str_remove(name, "ME"),
            pvalue = value) 

gMM.tidy <- geneModuleMembership.tidy %>% right_join(MMPvalue.tidy,by=c("Assay","Module")) 

module_specific_MM <- module_df %>% 
  transmute(Assay,
            Module = colors) %>% 
  inner_join(gMM.tidy)

Supplementary Figur S9B

(turquoise_module_restrictions_density <- module_specific_MM %>% 
   mutate("-log10(pvalue)" = -log10(pvalue)) %>% 
   pivot_longer(cols = c(gMM,"-log10(pvalue)")) %>% 
   mutate(name_label = case_when(name=="gMM"~"threshold > 0.6",
                                 name=="-log10(pvalue)"~"threshold < 0.05",
                                 .default = NA),
          name_label = factor(name_label),
          cutoff = case_when(name=="gMM"~ 0.6,#0.75,
                             name=="-log10(pvalue)"~ -log10(0.05),
                             .default = NA),
          cutoff_pos_y = case_when(name=="gMM"~ 1,
                                   name=="-log10(pvalue)"~ 0.04,
                                   .default = NA)
   ) %>% 
   ggplot(aes(x=value)) +
   geom_density(show.legend = F,linewidth=.2,fill="turquoise") +
   theme_minimal() +
   facet_wrap(~name, ncol = 1,labeller = labeller(name=c("gMM" = "Module membership", "-log10(pvalue)" = "-log10(pvalue)")),scales = "free") +
   geom_vline(aes(xintercept=cutoff),linetype="dashed") +
   geom_text(aes(x=cutoff,
                 y=cutoff_pos_y,
                 label=name_label), 
             size=1,
             check_overlap = TRUE) +
   labs(y="density",
        x=""))

Figure 5C

restricted_module_turquoise <- module_specific_MM %>% 
  filter(Module=="turquoise",
         gMM > 0.6,#0.75,
         pvalue < 0.05
         ) %>% 
  arrange(-pvalue) %>% 
  pull(Assay) 

length(restricted_module_turquoise)
## [1] 158
data.frame(Assay = restricted_module_turquoise) %>% 
  left_join(dap.res %>% 
              transmute(Assay, UniProt)) %>%
  transmute(UniProt) %>% 
  write_tsv(paste0(result.tmp.dir,"restricted_module_turquoise.tsv"))
  #head()
##Online reactome
#reactome_result<- read_delim("../Manuscript/20250226_restricted_module_turquoise_ReactomeORA_Result.txt") %>% janitor::clean_names()
reactome_result<- read_delim("../Manuscript/20250325_restricted_module_turquoise_ReactomeORA_Result.txt") %>% janitor::clean_names()


(reactome_ora <- reactome_result %>% 
  arrange(entities_fdr) %>% 
  head(n=10) %>% 
    mutate(facet_lab = "turquoise module") %>% 

   ggplot(aes(x=fct_reorder(pathway_name,-log10(entities_fdr)), 
              y=-log10(entities_fdr))) +

    geom_bar(stat = "identity", width = 0.1) +
    geom_point(aes(color=-log10(entities_fdr)),
               size=2) +
    geom_text(aes(label=number_entities_found),
              size=2, nudge_y = .1, color="black")+
    scale_y_continuous(trans="log10") +
    scale_x_discrete(labels = function(x) str_wrap(x, width = 45)) +
        scale_color_viridis() +
    theme_minimal() +
    theme(text = element_text(size=6 ),
          axis.text.y = element_text(size = 6),
          axis.ticks.x = element_blank()) +
    coord_flip() +
    facet_grid(~facet_lab) +
    guides(size = guide_legend(reverse=TRUE),
           ) +
     labs(title = "Reactome database v86",
       color="-log10\n(FDR)",
       y="-log10(FDR)",
       x=NULL)
)

Figure 5D

wrapper <- function(x, ...) 
{
  paste(strwrap(x, ...), collapse = "\n")
}

a = "Immunoregulatory interactions between a Lymphoid and a non-Lymphoid cell"
df <- reactome_result %>% 
  arrange(entities_fdr) %>% 
  head(n=10) %>% 
  filter(pathway_name==a) %>% 
  transmute(pathway_name, submitted_entities_found) %>% 
  separate_rows(submitted_entities_found, sep=";\\s*") %>% 
  left_join(
    data.long %>% inner_join(sampleTable_simple, by="sample_id") %>% transmute(Assay,NPX,UniProt,sample_id,study_id,Time) %>% filter(Time=="Acute"),
    by=c("submitted_entities_found"="UniProt")
  ) %>% 
  inner_join(patient_clust,by="study_id")

(reactome_ora_IIBLNL <- df %>%  group_by(Assay, severity_lab) %>% 
    summarise(NPXmean = mean(NPX),
              NPXmedian = median(NPX),
              NPXsd = sd(NPX),
              NPXn = n(),
              NPXse = NPXsd / sqrt(NPXn)
    ) %>% 
    mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
    ggplot(aes(x=Assay, y=NPXmean, group=severity_lab, color=severity_lab)) +
    geom_point(size=.25) +
    geom_polygon(fill=NA, show.legend = F, lwd=0.2) +
    geom_errorbar(aes(x = Assay,
                      ymin=NPXmean-NPXci95, 
                      ymax=NPXmean+NPXci95, ),
                  linewidth=.5, 
                  width=.2,
                  alpha=.5) +
    # Make it circular!
    coord_polar(clip = "off") +
    theme_minimal() +
    labs(x="",
         y="mean (NPX) +- 95% CI",

         title = wrapper(a, width = 40),
                  color="mean (NPX) +- 95% CI") +
    scale_color_manual(values=patient_kclust3_lab) +
    # Annotate the bars and the lollipops so the reader understands the scaling
    annotate(x = 0, y = 0, label = "0", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 1, label = "1", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 2, label = "2", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 3, label = "3", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    theme(
      axis.title = element_blank(),
      axis.ticks = element_blank(),
      axis.text.y = element_blank(),
      axis.text.x = element_text(color = "gray12", size = 4),
      legend.position = "right",
      legend.text = element_text(size=6),
      legend.title = element_text(size=6),
      title = element_text(size=5, face='bold'),
      plot.title = element_text(hjust = 0.5))
  )

a = "Neutrophil degranulation"
df <- reactome_result %>% 
  arrange(entities_fdr) %>% 
  head(n=10) %>% 
  filter(pathway_name==a) %>% 
  transmute(pathway_name, submitted_entities_found) %>% 
  separate_rows(submitted_entities_found, sep=";\\s*") %>% 
  left_join(
    data.long %>% inner_join(sampleTable_simple, by="sample_id") %>% transmute(Assay,NPX,UniProt,sample_id,study_id,Time) %>% filter(Time=="Acute"),
    by=c("submitted_entities_found"="UniProt")
  ) %>% 
  inner_join(patient_clust,by="study_id")

(reactome_ora_ND <- df %>%  group_by(Assay, severity_lab) %>% 
    summarise(NPXmean = mean(NPX),
              NPXmedian = median(NPX),
              NPXsd = sd(NPX),
              NPXn = n(),
              NPXse = NPXsd / sqrt(NPXn)
    ) %>% 
    mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
    ggplot(aes(x=Assay, y=NPXmean, group=severity_lab, color=severity_lab)) +
    geom_point(size=.25) +
    geom_polygon(fill=NA, show.legend = F, lwd=0.2) +
    geom_errorbar(aes(x = Assay,
                      ymin=NPXmean-NPXci95, 
                      ymax=NPXmean+NPXci95, ),
                  linewidth=.5,    
                  width=.2,
                  alpha=.5) +
    # Make it circular!
    coord_polar(clip = "off") +
    theme_minimal() +
    labs(x="",
         title = wrapper(a, width = 40),
                  color="mean (NPX) +- 95% CI") +
    scale_color_manual(values=patient_kclust3_lab) +
    # Annotate the bars and the lollipops so the reader understands the scaling
    annotate(x = 0, y = 0, label = "0", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 1, label = "1", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 2, label = "2", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 3, label = "3", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    theme(
      axis.title = element_blank(),
      axis.ticks = element_blank(),
      axis.text.y = element_blank(),
      axis.text.x = element_text(color = "gray12", size = 4),
      legend.position = "right",
      legend.text = element_text(size=6),
      legend.title = element_text(size=6),
      title = element_text(size=5, face='bold'),
      plot.title = element_text(hjust = 0.5))
  )

a = "TNFR2 non-canonical NF-kB pathway"
df <- reactome_result %>% 
  arrange(entities_fdr) %>% 
  head(n=10) %>% 
  filter(pathway_name==a) %>% 
  transmute(pathway_name, submitted_entities_found) %>% 
  separate_rows(submitted_entities_found, sep=";\\s*") %>% 
  left_join(
    data.long %>% inner_join(sampleTable_simple, by="sample_id") %>% transmute(Assay,NPX,UniProt,sample_id,study_id,Time) %>% filter(Time=="Acute"),
    by=c("submitted_entities_found"="UniProt")
  ) %>% 
  inner_join(patient_clust,by="study_id")

(reactome_ora_TNFR2 <- df %>%  group_by(Assay, severity_lab) %>% 
    summarise(NPXmean = mean(NPX),
              NPXmedian = median(NPX),
              NPXsd = sd(NPX),
              NPXn = n(),
              NPXse = NPXsd / sqrt(NPXn)
    ) %>% 
    mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
    ggplot(aes(x=Assay, y=NPXmean, group=severity_lab, color=severity_lab)) +
    geom_point(size=.25) +
    geom_polygon(fill=NA, show.legend = F, lwd=0.2) +
    geom_errorbar(aes(x = Assay,
                      ymin=NPXmean-NPXci95, 
                      ymax=NPXmean+NPXci95),
                  linewidth=.5,
                  width=.2,
                  alpha=.5) +
    # Make it circular!
    coord_polar(clip = "off") +
    theme_minimal() +
    labs(x=NULL,
         color="mean (NPX) +- 95% CI",
         title = wrapper(a, width = 40)) +
    scale_color_manual(values=patient_kclust3_lab) +
    # Annotate the bars and the lollipops so the reader understands the scaling
    annotate(x = 0, y = 0, label = "0", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 1, label = "1", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 2, label = "2", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    annotate(x = 0, y = 3, label = "3", fontface =2, geom = "text", color = "gray12", size = 1.5) +
  annotate(x = 0, y = 4, label = "4", fontface =2, geom = "text", color = "gray12", size = 1.5) +
    theme(
      axis.ticks = element_blank(),
      axis.title = element_blank(),
      axis.text.y = element_blank(),
      axis.text.x = element_text(color = "gray12", size = 4),
      legend.position = "right",
      legend.text = element_text(size=6),
      legend.title = element_text(size=6),
      title = element_text(size=5, face='bold'),
      plot.title = element_text(hjust = 0.5))
)

Figure 6

Severity-associated profiles of condensed 11- protein signature in malaria and other febrile infections.

library(mixOmics)
data.mo <- df_acute_patclust_incl_conv %>% 
  filter(Assay %in% restricted_module_turquoise) %>% 
  pivot_wider(names_from = Assay, values_from = NPX, id_cols=c(severity_lab,sample_id)) %>% 
  column_to_rownames("sample_id")

X <- data.mo %>% dplyr::select(-c(severity_lab))
Y <- data.mo$severity_lab
#####
data.pca <- mixOmics::pca(X, ncomp=10, center = TRUE, scale = TRUE)
plot(data.pca)

plotIndiv(data.pca, 
          group = Y,
          ind.names = F,
          legend = TRUE, 
          col.per.group = patient_kclust3_lab_conv,
          title = 'PCA on all NPX data')

#####
### PLS-Discriminant Analysis based on severity groups

data.plsda <- mixOmics::plsda(X, Y, ncomp = 10)
# takes a couple of minutes to run
perf.data.plsda <- perf(data.plsda, 
                        validation = "Mfold",
                        folds = 5,
                        progressBar = F,
                        auc = TRUE, 
                        nrepeat = 10) #100
################
(plot(perf.data.plsda, col = color.mixo(1:3), sd = TRUE, legend.position = "horizontal"))

## NULL
######
list.keepX <- c(1:10) # grid of possible keepX values that will be tested for each component
tune.splsda <- tune.splsda(X,
                           Y, 
                           ncomp = 3, 
                           validation = "Mfold",
                           folds = 5, 
                           progressBar = TRUE, 
                           dist = "centroids.dist",
                           measure = "BER",
                           test.keepX = list.keepX, 
                           nrepeat = 10, 
                           cpus = 8)
## 
## comp 1 
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |======================================================================| 100%
## comp 2 
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |======================================================================| 100%
## comp 3 
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |======================================================================| 100%
#####
## The classification error rates for each component conditional on the last component are represented below, for all components specified in the tune function.
plot(tune.splsda)

error <- tune.splsda$error.rate  # error rate per component for the keepX grid
ncomp <- tune.splsda$choice.ncomp$ncomp
ncomp
## [1] 2
ncomp = 2
#####
select.keepX <- tune.splsda$choice.keepX[1:ncomp]  # optimal number of variables to select
select.keepX
## comp1 comp2 
##     7     4
#####

splsda.data <- mixOmics::splsda(X, Y, ncomp = ncomp, keepX = select.keepX) 

#####

plotIndiv(splsda.data, 
          comp = c(1,2),
          group = Y, 
          ind.names = F, 
          ellipse = TRUE,
          #col.per.group =  patient_kclust3_lab,
          legend = T, 
          title = 'sPLS-DA on data, comp 1 & 2')

plotLoadings(splsda.data, comp = 1,ndisplay=20, title = 'Loadings on comp 1',legend.color =  patient_kclust3_lab_conv, 
             contrib = 'max', method = 'mean')

plotLoadings(splsda.data, comp = 2,ndisplay = 10, title = 'Loadings on comp 2', legend.color =  patient_kclust3_lab_conv, 
             contrib = 'max', method = 'mean')

auc.splsda <- auroc(splsda.data, roc.comp = 2, print = FALSE) # AUROC for the first component

auc.splsda$graph.Comp1
## NULL
auroc(splsda.data, roc.comp = 1, print = FALSE) 

Figure 6A

splsda.kclust.clusters <- plotIndiv(splsda.data, 
                                 comp = c(1,2),
                                 group = Y, 
                                 ind.names = F, 
                                 ellipse = TRUE,
                                 col.per.group = patient_kclust3_lab_conv,
                                 legend = F, 
                                 title = 'sPLS-DA on data, comp 1 & 2')

(splsda.kclust.clusters.ggplot <- splsda.kclust.clusters$df %>% 
    mutate(group = factor(group, levels=c("severe","moderate","mild","convalescence"))) %>%  
    
    ggplot(aes(x=x,y=y,color=group)) +
    ggforce::geom_mark_ellipse(aes(color = as.factor(group), fill=group),alpha=.1,show.legend = F, expand = unit(0.5,"mm")) +
    geom_point(size=0.5) + 
    scale_color_manual(values=patient_kclust3_lab_conv) +
    scale_fill_manual(values=patient_kclust3_lab_conv) +
    
    theme_minimal() +
    labs(title = "sparse PLS-DA",
         color= NULL,
         x=paste0("X-variate 1: ",round(splsda.data$prop_expl_var$X[[1]]*100,1),"% expl. var"),
         y=paste0("X-variate 2: ",round(splsda.data$prop_expl_var$X[[2]]*100,1),"% expl. var")) +
    theme(legend.position = "right") 
)

Figure 6B

plsda_loadings.df <-   
  data.frame(splsda.data$loadings$X) %>% 
  rownames_to_column("Assay") %>% 
  pivot_longer(names_to = "comp",values_to = "values",cols = -Assay) %>% 
  filter(values != 0,
         comp %in% c("comp1","comp2")) %>% 
  group_by(comp) %>% 
  mutate(values = scales::rescale(values, to=c(-1,1))) %>% 
  ungroup() 

(plsda_loadings.volcano.alt <-  plsda_loadings.df %>% 
    ggplot(aes(x=fct_reorder(Assay,values,.desc = T), y=values, color=comp,fill=comp)) +
    geom_point(size=0.5,alpha=1) +
    geom_col(width = 0.01) +
    coord_flip() +
    theme_minimal() +
    scale_color_manual(values=c(comp1 = "#1f78b4",comp2 = "#b2df8a")) +
    scale_fill_manual(values=c(comp1 = "#1f78b4",comp2 = "#b2df8a")) +
    labs(x="",
         fill=NULL,
         color=NULL,
         y="scaled loading values",
         title="sPLSDA loadings") +
    theme(legend.title = element_text(size=6),
          axis.text.x = element_text(size=6),
          legend.position = "right",
          legend.justification="right", 
          legend.box.spacing = unit(0, "pt")))

malaria.severity.siganture <- data.frame(splsda.data$loadings$X) %>% 
  rownames_to_column("Assay") %>% 
  pivot_longer(names_to = "comp",values_to = "values",cols = -Assay) %>% 
  filter(values != 0,
         comp %in% c("comp1","comp2")
         )

Figure 6C

my_comparisons_severe_conv <- list(c("severe", "moderate"), c("moderate", "mild"), c("severe", "mild"),c("mild","convalescence"))

splsda.c1.top9 <- plsda_loadings.df %>% 
  #filter(comp=="comp1") %>% 
  slice_max(n=9, order_by = abs(values)) %>% 
  #arrange(comp) %>% 
  #slice_min(n=9, order_by = values) %>% 
    pull(Assay)# %>% 

(splsda.c1.top9 <- df_acute_patclust_incl_conv %>% 

    dplyr::filter(Assay %in% c(splsda.c1.top9)) %>% 
    mutate(Assay = factor(Assay, levels = c(splsda.c1.top9))) %>% 
    ggplot(aes(x=severity_lab, y=NPX, color=severity_lab, fill=severity_lab)) + 
    geom_violin(trim = F,alpha=.9) +
    geom_jitter(size=0.25,show.legend = F, width = 0.05, alpha=1, color="grey20") +
    geom_boxplot(alpha=.7,width=0.25,outlier.shape = NA,color="black", fatten = 2,lwd=.25,show.legend = F) +
    stat_compare_means(method = "wilcox.test",
                       label.sep = "\n",
                       hide.ns = T,
                       label = "p.signif" ,
                       vjust = .5,
                       size=2,
                       lwd = .2,
                       comparisons =my_comparisons_severe_conv,
                       show.legend = F) +
    facet_wrap(~Assay,ncol = 3,scales = "free_y") +
    theme_minimal() +
    theme(legend.position="bottom",
          axis.text.x = element_blank()) +
    labs(x="",
         color=NULL,
         fill=NULL) +
    scale_color_manual(values= patient_kclust3_lab_conv) +
    scale_fill_manual(values= patient_kclust3_lab_conv))

plsda.selection <- malaria.severity.siganture %>% pull(Assay)

data.frame(Assay = plsda.selection) %>% 
  left_join(universe.proteins,by="Assay") %>% 
  transmute(Assay, UniProt)# %>% 
##        Assay UniProt
## 1      HMOX1  P09601
## 2      IL2RA  P01589
## 3      VCAM1  P19320
## 4      ICAM1  P05362
## 5     IFNGR1  P15260
## 6    B4GALT1  P15291
## 7       LAYN  Q6UX15
## 8  TNFRSF10B  O14763
## 9      CALCA  P01258
## 10    SPINK1  P00995
## 11  TNFRSF1B  P20333
  #write_tsv(paste0(result.dir,"MIP_Severity_Protein_signature_uniprotid.tsv"))

Figure 6D

## Explore 1536 data set - MGH Covid-19 study, Filbin et al. 2021
#### Make data ready
# identify proteins with NPX below LOD in more than 70% of samples
assays2rm <- covid_NPXdata %>% 
  mutate(belowLOD = LOD>NPX) %>% 
  group_by(Assay) %>% 
  count(belowLOD,sort=TRUE) %>% 
  filter(belowLOD==T,
         n > length(unique(covid_NPXdata$SampleID))*0.7) %>% 
  pull(Assay)

# remove proteins identified above from data
covid_NPXdata_rm <- covid_NPXdata %>% 
  filter(!Assay%in%assays2rm, Timepoint=="D0") %>%
  dplyr::select(SampleID, subject_id, Assay, NPX, Panel)

# identify proteins with different values in different panels
assays2rm <- covid_NPXdata_rm %>%
  group_by(subject_id, Assay) %>%
  summarise(n = n(), .groups = "drop") %>%
  filter(n > 1L) %>%
  pull(Assay) %>%
  unique()

# one example of the proteins identified above
covid_NPXdata_rm %>% filter(subject_id==1,Assay=="CXCL8")
## # A tibble: 4 × 5
##   SampleID subject_id Assay   NPX Panel          
##   <chr>         <dbl> <chr> <dbl> <chr>          
## 1 1_D0              1 CXCL8  1.46 CARDIOMETABOLIC
## 2 1_D0              1 CXCL8  4.40 INFLAMMATION   
## 3 1_D0              1 CXCL8  4.59 NEUROLOGY      
## 4 1_D0              1 CXCL8  3.52 ONCOLOGY
# convert data to wide format
covid_NPXdata_wide <- covid_NPXdata_rm %>%
  ## values_fn calculates median values for duplicated features (duplicated because part of every olink panel)
  pivot_wider(names_from = Assay, values_from = NPX,id_cols = subject_id, values_fn = median)

# make data ready for GSVA
covid_NPXdata_mat <- covid_NPXdata_wide %>%  
  column_to_rownames("subject_id") %>%
  as.matrix() %>% 
  t()
#### Run single sample gene set enrichment analysis
library(GSVA)
# run ssgsea on signature from sPLSDA
GSE_results <- gsva(expr = covid_NPXdata_mat,
                    gset.idx.list = list(sig=plsda.selection),verbose=F,
                    method="zscore")

#data_plot_sPLSDA <- data.frame(group=as.factor(covid_clinicalData$WHO.0),score=as.vector(GSE_results))

GSEA_result_df <- data.frame(subject_id = colnames(covid_NPXdata_mat),
                             ssES = as.vector(GSE_results)) %>% 
  right_join(mgh.covid.meta %>% transmute(subject_id= as.character(subject_id),
                                          who_0 = as.factor(who_0)), by="subject_id")

# show results
(MGH_covid_ssES <- GSEA_result_df %>% 
  ggplot(aes(x=who_0, y=ssES, fill=who_0)) +
    geom_jitter(width=0.15,size=.3,alpha=.2) +
 # geom_violin(width=1.5, trim = F, alpha=0.7,show.legend = F,lwd=.25) +
  geom_boxplot(width=.3,alpha=.6, fatten = 2,lwd=.25,outlier.colour = NA) +
  #geom_boxplot(alpha=0.6, width=.2, show.legend = F)+
  theme_minimal()+
    theme(legend.position = "none") +
  labs(y="ssES score (zscore)",x="Severity group",fill=""))

Figure 6E

#### Make data ready

MIP.long <- data.long %>% 
  left_join(sampleTable_simple) %>%
  filter(!grepl("D10",sample_id)) %>% 
    left_join(patient_clust) %>% 
  mutate(sample_type = case_when(Time=="Acute" ~ paste0(severity_lab," malaria"),
                                 .default = paste0(#Time,
                                   "Malaria",
                                   " convalescence"))) %>% 
  transmute(sample_id, sample_type, Assay, NPX)


data_tf_mip_wide <- TF.long %>% 
  bind_rows(MIP.long) %>% 
  pivot_wider(names_from = Assay, values_from = NPX, id_cols = c(sample_id,sample_type), values_fn = median) 

all.mat <- data_tf_mip_wide %>%
  dplyr::select(-c(sample_type)) %>% 
  column_to_rownames("sample_id") %>% 
  as.matrix() %>% 
  t()
#### Run single sample gene set enrichment analysis
library(GSVA)
# run ssgsea on signature from sPLSDA
GSE_results <- gsva(expr = all.mat,
                    gset.idx.list = list(sig=plsda.selection),#list(sig=severity_signature_proteins),
                    verbose=F,
                    method="zscore")


GSEA_result_df <- data.frame(sample_id = colnames(all.mat),
                             ssES = as.vector(GSE_results)) %>% 
  left_join(data_tf_mip_wide %>% dplyr::select(sample_id,sample_type), by="sample_id") %>% 
  left_join(
  TF_SOFA %>% transmute(sample_id = paste0(study_id,"|Acute"), SOFA_total) %>%
  bind_rows(
    subjectTable %>% transmute(sample_id = paste0(study_id,"|Acute"), SOFA_total)
  )) %>% 
  mutate(sample_type = case_when(sample_type == "Influensa A" ~ "Influenza A",
                                 sample_type == "Influensa B" ~ "Influenza B",
                                 .default = sample_type))

# show results

(TF_ssES_plot <- GSEA_result_df %>% 
ggplot(aes(x=fct_reorder(sample_type,ssES, median,.desc = T), y=ssES, fill=sample_type)) +
  geom_jitter(width=0.15,size=.3,alpha=.2) +
  geom_boxplot(width=.3,alpha=.6, fatten = 2,lwd=.25,outlier.colour = NA) +
  theme_minimal() +
    scale_fill_manual(values=c("severe malaria"=patient_kclust3_lab[[3]],
                               "moderate malaria"=patient_kclust3_lab[[2]],
                               "mild malaria"=patient_kclust3_lab[[1]],
                               "Malaria convalescence"=patient_kclust3_lab_conv[[4]]),
                      na.value = "#8dd3c7") +
  geom_hline(yintercept = 0,linetype="dotted") +
  labs(title="Evaluation of malaria disease severity signature",
       x=NULL,
       y="Gene Set Variation Analysis\nsingle sample enrichment score\n(zscore)",
       fill="") +
    theme(legend.position = "none") +
      scale_x_discrete(labels = label_wrap(8)) )

Supplementary Table S5

malaria.severity.siganture %>% 
  arrange(values) %>% 
  dplyr::rename(importance = values) %>% 
  head()
## # A tibble: 6 × 3
##   Assay     comp  importance
##   <chr>     <chr>      <dbl>
## 1 LAYN      comp2     -0.816
## 2 TNFRSF1B  comp1     -0.704
## 3 SPINK1    comp2     -0.487
## 4 IL2RA     comp1     -0.472
## 5 B4GALT1   comp1     -0.434
## 6 TNFRSF10B comp2     -0.283
  #write_tsv(paste0(result.dir,"Supplementary_TableS5_SeveritySignature.tsv"))

Supplementary Table S6

TF cohort - sampleTable

##gtsummary
library(gtsummary)

TF_sampleTable %>% 
  dplyr::select(-sample_type) %>% 
  inner_join(GSEA_result_df, by="sample_id") %>% 
  transmute(sample_type, 
            SOFA_total = as.numeric(SOFA_total),
            age = as.numeric(age),
            gender) %>% 
  filter(!grepl("Malaria|malaria", sample_type)) %>% 
  
  tbl_summary(include = c(sample_type, age, gender,
                          SOFA_total),
              by = sample_type,
              statistic = list(all_continuous() ~ "{median} ({min}-{max})",
                               all_categorical() ~ "{n} / {N} ({p}%)"
              ),
              #digits = all_continuous() ~ 2
              digits = c(age ~ 0)
              )
Characteristic Campylobacter, N = 171 Dengue, N = 191 E.coli -pyelonefriter, N = 91 Influenza A, N = 171 Influenza B, N = 181 Mycoplasma pneumonier, N = 51 Salmonella (only feces), N = 121 Shigella, N = 31
age 32 (26-61) 34 (22-66) 56 (24-87) 45 (23-88) 38 (26-68) 40 (18-72) 38 (22-61) 40 (29-50)
gender 11 / 17 (65%) 11 / 19 (58%) 2 / 9 (22%) 5 / 17 (29%) 7 / 18 (39%) 3 / 5 (60%) 8 / 12 (67%) 1 / 3 (33%)
SOFA_total
    0 15 / 17 (88%) 12 / 19 (63%) 4 / 5 (80%) 14 / 17 (82%) 15 / 18 (83%) 3 / 4 (75%) 11 / 12 (92%) 2 / 3 (67%)
    1 2 / 17 (12%) 3 / 19 (16%) 0 / 5 (0%) 3 / 17 (18%) 1 / 18 (5.6%) 1 / 4 (25%) 1 / 12 (8.3%) 0 / 3 (0%)
    2 0 / 17 (0%) 4 / 19 (21%) 0 / 5 (0%) 0 / 17 (0%) 2 / 18 (11%) 0 / 4 (0%) 0 / 12 (0%) 1 / 3 (33%)
    3 0 / 17 (0%) 0 / 19 (0%) 1 / 5 (20%) 0 / 17 (0%) 0 / 18 (0%) 0 / 4 (0%) 0 / 12 (0%) 0 / 3 (0%)
    Unknown 0 0 4 0 0 1 0 0
1 Median (Minimum-Maximum); n / N (%)

Figure 7

A protein-centric view on integrated analysis to ascertain immune cell communication associated with disease severity

Figure 7A

similar_modules <- c(restricted_module_turquoise,
                     module_df %>% filter(colors=="brown") %>% pull(Assay),
                     module_df %>% filter(colors=="blue") %>% pull(Assay))
library(eulerr)
euler_plot <- euler(
  list(
    "Differential\nabundant\nproteins\nin\nacute malaria"=selected.assays.wcna,
    "Severity associated\nproteins in plasma" = restricted_module_turquoise)
)

plot(euler_plot,
     fills = c("white",
               "turquoise"),
               
     quantities = TRUE,
     lty = 1,#1:3,
     fontsize=6,
     labels = list(fontsize=5),
     shape = "ellipse") 

Figure 7B

secretome_location_dap_severity <- dap.res %>% 
  filter(Assay %in% restricted_module_turquoise) %>% 
  inner_join(hpa_24.0, by=c("Assay"="gene","UniProt"="uniprot")) %>% 
  mutate(secretome_location_tissue_spec = case_when(secretome_location=="Not secreted"~ paste0(secretome_location," - ",rna_tissue_specificity),
                                                   .default = secretome_location)) %>% 
  group_by(secretome_location_tissue_spec) %>% 
 mutate(n_secretome_location_tissue_spec = n()) #count(sort = TRUE) 


## plot everything
(hpa.protein.origin.overview_severity <- secretome_location_dap_severity %>% 
    ungroup() %>% 
    transmute(secretome_location_tissue_spec = factor(secretome_location_tissue_spec,
                                                     levels = rev(c("Secreted to blood",
                                                                    "Intracellular and membrane",
                                                                    "Secreted in other tissues",
                                                                    "Secreted to extracellular matrix",  
                                                                    "Secreted to digestive system", 
                                                                    "Secreted in brain",
                                                                    "Secreted - unknown location",
                                                                    "Secreted in female reproductive system",
                                                                    "Secreted in male reproductive system",
                                                                    "Not secreted - Tissue enriched", 
                                                                    "Not secreted - Tissue enhanced",
                                                                    "Not secreted - Group enriched",
                                                                    "Not secreted - Low tissue specificity"))),
              n_secretome_location_tissue_spec) %>% 
    distinct() %>% 
    ggplot(aes(x = secretome_location_tissue_spec, y = n_secretome_location_tissue_spec, fill = secretome_location_tissue_spec)) +
    geom_col(width = 0.5) +
    geom_text(aes(label=n_secretome_location_tissue_spec),size=2, nudge_y = -.2) +
    coord_flip() +
    scale_y_continuous(trans="pseudo_log",name = "Number of proteins\nassociated with severity",
                       sec.axis = sec_axis(~.,labels = NULL,breaks = NULL,
                                           #name = "Number of DAPs"
                                           ), 
                       #expand=c(0,.15)
                       expand = c(0,0)
                       ) +
    theme_bw() +
    theme(axis.text.y = element_text(size = 6),
          axis.text.x = element_text(size = 6),
          legend.text=element_text(size=6),
          legend.title=element_text(size=6),
          plot.title = element_text(size=6),
          legend.position = "none")+

    scale_fill_manual(values=secretome_location_tissue_spec_cols,
                      limits = secretome_location_dap.order) +
    labs(fill="Protein\norigin\nby HPA",
         x=NULL))

## plot everything
(hpa.protein.origin.overview_severity <- secretome_location_dap_severity %>% 
    ungroup() %>% 
    transmute(secretome_location_tissue_spec = factor(secretome_location_tissue_spec,
                                                     levels = c("Secreted to blood",
                                                                    "Intracellular and membrane",
                                                                    "Secreted in other tissues",
                                                                    "Secreted to extracellular matrix",  
                                                                    "Secreted to digestive system", 
                                                                    "Secreted in brain",
                                                                    "Secreted - unknown location",
                                                                    "Secreted in female reproductive system",
                                                                    "Secreted in male reproductive system",
                                                                    "Not secreted - Tissue enriched", 
                                                                    "Not secreted - Tissue enhanced",
                                                                    "Not secreted - Group enriched",
                                                                    "Not secreted - Low tissue specificity")),
              n_secretome_location_tissue_spec) %>% 
    distinct() %>% 
    ggplot(aes(x = secretome_location_tissue_spec, y = n_secretome_location_tissue_spec, fill = secretome_location_tissue_spec)) +
    geom_col(width = 0.5) +
    geom_text(aes(label=n_secretome_location_tissue_spec),size=2, nudge_y =1.5) + #0.1
    #coord_flip() +
    scale_y_continuous(#trans="pseudo_log",
                       name = "Number of proteins",
                       sec.axis = sec_axis(~.,labels = NULL,breaks = NULL,
                                           #name = "Number of DAPs"
                                           ), 
                       #expand=c(0,.15)
                       #expand = c(0,0.1),
                       limits = c(0,51)
                       ) +
    theme_bw() +
    theme(axis.text.y = element_text(size = 6),
          axis.text.x = element_text(size = 6,angle=90,hjust = 1,vjust = 0.5),
          #axis.text.x = element_text(size = 6,angle=45,hjust = 1),
          axis.title.y = element_text(size=6),

          legend.text=element_text(size=6),
          legend.title=element_text(size=6),
          plot.title = element_text(size=6),
          legend.position = "none")+

    scale_fill_manual(values=secretome_location_tissue_spec_cols,
                      limits = secretome_location_dap.order) +
    labs(fill="Protein\norigin\nby HPA",
         x=NULL))

Figure 7C

proteins2label <- df_acute_patclust_incl_conv %>% 
  group_by(UniProt,Assay, severity_lab) %>% 
  summarise(NPXmean = mean(NPX),
            NPXmedian = median(NPX),
            NPXsd = sd(NPX),
            NPXn = n(),
            NPXse = NPXsd / sqrt(NPXn)
  ) %>% 
  #ungroup() %>% 
  mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
  left_join(
    secretome_location_dap_severity %>%
    filter(Assay %in% restricted_module_turquoise) %>%
  transmute(Assay,secretome_location_tissue_spec), by="Assay"
  ) %>% 
  filter(severity_lab=="severe",
         Assay %in% restricted_module_turquoise,
         !is.na(secretome_location_tissue_spec)) %>% 
  
  group_by(secretome_location_tissue_spec) %>% 
  #transmute(Assay,NPX, severity_lab, secretome_location_tissue_spec) %>% 
  distinct() %>% 
  slice_max(order_by = NPXmean,n = 3) %>% pull(Assay)
tmp.df <- df_acute_patclust_incl_conv %>% 
  group_by(UniProt,Assay, severity_lab) %>% 
  summarise(NPXmean = mean(NPX),
            NPXmedian = median(NPX),
            NPXsd = sd(NPX),
            NPXn = n(),
            NPXse = NPXsd / sqrt(NPXn)
  ) %>% 
  #ungroup() %>% 
  mutate(NPXci95 = NPXse * qt(.975, NPXn - 1)) %>% 
  filter(Assay%in%restricted_module_turquoise) %>% 
  left_join(
    secretome_location_dap_severity%>% 
      transmute(Assay, secretome_location_tissue_spec), by="Assay")

(turqoise_allProteins_lab <- tmp.df %>% 
  ggplot(aes(x=fct_reorder(Assay,NPXmean,.desc = F), y=NPXmean)) +
  geom_point(shape=16,size=.5,aes(color=severity_lab)) +
  geom_errorbar(aes(x = Assay,#reorder(str_wrap(Assay, 5), estimate),
                    ymin=NPXmean-NPXci95, 
                    ymax=NPXmean+NPXci95,
                    color=severity_lab),
                linewidth=.2,    # Thinner lines
                width=.2,
                alpha=.5) +
  geom_hline(yintercept = 0,lty=5, lwd=.2) +
    ggrepel::geom_text_repel(data = . %>% filter(Assay %in% proteins2label,#c("LGALS9","HAVCR2","IL4","IL4R","CD70","PDCD1","CD274"),
                                                 severity_lab == "severe"),
                             aes(label = Assay, colour=secretome_location_tissue_spec, nudge_y=NPXmean),
                             size = .9,
                             force_pull = 3, # do not pull toward data points
                             force = .15, # Strength of the repulsion force.

                             nudge_x = 0,
                             # Do not repel from top or bottom edges.
                             ylim = c(1, Inf),
                             direction    = "y",
                             angle        = 90,
                             hjust        = 0,
                             segment.size = 1/20,    ## segment width
                             segment.linewidth = 1/12,#0.01,
                             arrow = arrow(length = unit(0.04, 'npc')),     # Draw an arrow from the label to the data point.
                             
                             
                             max.overlaps = 50,
                             max.iter = 3e3,     # Maximum iterations of the naive repulsion algorithm O(n^2).
                             color = "grey10"
  ) +
  scale_y_continuous(limits=c(-1.5,8.5),expand = c(0,0)) +
  scale_color_manual(values = patient_kclust3_lab_conv) +
      coord_cartesian(clip = "off") +

  #coord_flip() +
  
  labs(x="Severity associated proteins in plasma",
       y="NPX",
       color=NULL,
       caption = "meanNPX +- ci95") +
  theme(legend.position = "top",
        axis.text.x = element_text(colour = "black",angle=90,hjust=1,vjust=.5,size = 2),
        axis.text.y = element_text(size = 6),
        panel.grid.minor = element_line(size = 0.1),
        panel.grid.major = element_line(size = .1),
        #axis.text.x = element_blank()
        )
)

require(patchwork)
(p_annotation <- #secretome_location_dap_severity%>% 
    #transmute(Assay, secretome_location_tissue_spec) %>% 
   # left_join(tmp.df,by="Assay") %>% 
    tmp.df %>% 
    mutate(dummy.y = "HPA") %>% 
    ggplot(aes(x = fct_reorder(Assay,NPXmean,.desc = F), y = dummy.y, fill = secretome_location_tissue_spec)) +
    geom_tile(linejoin = "round") +
    scale_fill_manual(values = secretome_location_tissue_spec_cols) +
    theme_void() +
    theme(legend.position = "none") 
  #scale_y_discrete(expand=c(0,-0.1))
   # theme(aspect.ratio = 1/100)
  )

test_plot <- p_annotation / turqoise_allProteins_lab + plot_layout(height = c(.5, 4))
test_plot

Figure 7D

## create a gene name - uniprot dictionary
name_up_dict <- hpa_24.0 %>% transmute(gene, uniprot)

ligand.q <- dap.res %>% filter(p.adj <=0.01, logFC > .1) %>% 
  left_join(cpdb.protein_input,
            by=c("UniProt"="uniprot")) #%>% 
  #pull(UniProt)

length(ligand.q)
## [1] 32
interaction_dict <- cpdb.interaction_input %>% 
  filter(partner_a %in% ligand.q$UniProt,
         directionality == "Ligand-Receptor"
        #directionality %in% c("Ligand-Receptor","Receptor-Receptor","Ligand-Ligand")
         ) %>% 
  mutate(protein_name_b_strip = gsub("_HUMAN","",protein_name_b),
         protein_name_a = gsub("_HUMAN","",protein_name_a)) %>% 
  mutate(protein_name_b_complex = case_when(is.na(protein_name_b) ~ str_remove(interactors,paste0(protein_name_a,"-")),
                                    .default = protein_name_b)) %>%
   separate_longer_delim(protein_name_b_complex, delim = "+") %>% 
   left_join(hpa_24.0 %>% transmute(protein_name_b_complex = gene,
                                      uniprot_b_complex = uniprot), by=c("protein_name_b_complex")) %>% 
  mutate(protein_name_b = case_when(is.na(protein_name_b) ~ protein_name_b_complex,
                                        .default = protein_name_b),
         partner_b_new = case_when(is.na(uniprot_b_complex) ~ partner_b,
                                   .default = uniprot_b_complex)) %>% 
  transmute(partner_a, partner_b, partner_b_new) %>% 
  mutate(uniprot_a = partner_a,
         uniprot_b = partner_b_new) %>% 
  transmute(source = uniprot_a,
            recipient = uniprot_b) %>% 
  left_join(name_up_dict %>% dplyr::rename(source_gene = gene), by=c("source" = "uniprot")) %>% 
  left_join(name_up_dict %>% dplyr::rename(recipient_gene = gene), by=c("recipient" = "uniprot"))
interaction_dict
## # A tibble: 265 × 4
##    source recipient source_gene recipient_gene
##    <chr>  <chr>     <chr>       <chr>         
##  1 P19022 P06734    CDH2        FCER2         
##  2 P05362 P20701    ICAM1       ITGAL         
##  3 P05362 P20701    ICAM1       ITGAL         
##  4 P05362 P05107    ICAM1       ITGB2         
##  5 P05362 P11215    ICAM1       ITGAM         
##  6 P05362 P05107    ICAM1       ITGB2         
##  7 P05362 P20702    ICAM1       ITGAX         
##  8 P05362 P05107    ICAM1       ITGB2         
##  9 P13598 Q9NNX6    ICAM2       CD209         
## 10 P13598 P20701    ICAM2       ITGAL         
## # ℹ 255 more rows
celltype_l2_freq <- tibble(pbmc_acute@meta.data) %>% 
  group_by(CellType_L2) %>% 
  summarise(n = n()) %>%
  mutate(freq = n / sum(n),
         Percentage = freq*100) 

celltype_l2_of_l1_freq <- tibble(pbmc_acute@meta.data) %>% 
  group_by(CellType_L1,CellType_L2) %>% 
  summarise(n = n()) %>%
  group_by(CellType_L1) %>% 
  mutate(freq = n / sum(n),
         Percentage = freq*100) 

circosplot function

my_nice_circosplot <- function(assays2plot_circos, scale_range, expression_threshold, pdf_file_name){
  
pbmc_acute.avg.long_tourquoise <- pbmc_acute.avg.long %>% 
  filter(celltype != "undefined",
         gene %in% assays2plot_circos,
         ) %>% 
  mutate(gene_ct = paste0(gene,"_",celltype)) %>% 
  group_by(gene) %>% 
  mutate(avgExp = scales::rescale(avgExp, to=scale_range)) %>%  #c(0,1)
  ungroup() 

mat <- pbmc_acute.avg.long_tourquoise %>% 
    filter(avgExp >expression_threshold) %>% #.5
  left_join(tibble(pbmc@meta.data) %>% transmute(celltype_1 = CellType_L1,
                                                celltype = CellType_L2) %>% distinct(), by="celltype") %>% 
  mutate(celltype_1 = factor(celltype_1, levels= c("DC","Monocytes","NK","gdT","B","CD4+ T","CD8+ T")),
         celltype = factor(celltype, levels = c("mDC", "pDC", 
                                                "CD14 monocytes", "CD16 monocytes",
                                                "NK CD56dim CD16+", "NK CD56dim","NK CD56bright","NK prolif.",
                                                "Vd2+ gdT", "Vd2- gdT",
                                                "B naive", "B memory", "Plasma cells",
                                                "CD4 naive", "CD4 Treg CD80+", "CD4 Treg CD80-", "CD4 Tfh",
                                                "CD4 effect. activated", "CD4 effect. memory",
                                                "CD4 trans. memory","CD4 central memory",
                                                "CD8 naive", "CD8 trans. memory", "CD8 Tfh",
                                                "NKT", "CD8 effect. memory"))) %>% 
  add_rownames() 


tmp <- mat %>% dplyr::rename(index = rowname) 

df_link <- interaction_dict %>% 
  transmute(source_gene, recipient_gene) %>% 
  left_join(tmp %>% 
               filter(gene %in% interaction_dict$source_gene) %>%
               transmute(from_index = index,
                         gene), 
             by=c("source_gene"="gene")) %>% 
  filter(!is.na(from_index)) %>% 
  left_join(tmp %>% 
               transmute(to_index = index,
                         gene), 
             by=c("recipient_gene"="gene")) %>% 
  filter(!is.na(to_index)) %>% 
  distinct() %>% 
  right_join(mat %>% transmute(gene, celltype) %>% 
               left_join(data.frame(celltype = names(L2_colors), 
                                    source_celltype_colors = L2_colors)),
              by=c("source_gene"="gene")) %>% 
  
  transmute(from_index = as.integer(from_index),
            to_index = as.integer(to_index),
            source_celltype = celltype,
            source_gene,
            recipient_gene) %>% 
  na.omit() %>% 
  distinct()

## goal
## from_index; to_index data frame


mat_gex <- mat %>% arrange(celltype) %>%
  column_to_rownames("gene_ct") %>% 
  dplyr::select(avgExp)

mat_npx <- mat %>%
  transmute(gene_ct, gene) %>% 
  left_join(df_acute_patclust_incl_conv %>% 
              transmute(Assay, NPX,severity_lab) %>% 
              #filter(Assay %in% restricted_module_turquoise) %>% 
              pivot_wider(names_from = severity_lab, values_from = NPX,values_fn = median)
            , by=c("gene"="Assay")) %>% 
  dplyr::select(-gene) %>% 
  distinct() %>%
  column_to_rownames("gene_ct") %>%
  relocate(severe, moderate, mild, convalescence)


## legends
col_npx <- colorRamp2(c(min(mat_npx,na.rm = T),
                        0,
                        max(mat_npx,na.rm = T)/2,
                        max(mat_npx,na.rm = T)),
                      c("#edf8e9","#bae4b3", "#74c476","#238b45"))

#mat_npx <- mat_npx %>% mutate(across(where(is.numeric), ~ scales::rescale(., to=c(4,0))))
cell_freq_color <- colorRamp2(c(0,
                                min(celltype_l2_freq$Percentage,na.rm = T),
                                mean(celltype_l2_freq$Percentage,na.rm=T),
                                max(celltype_l2_freq$Percentage,na.rm = T)),
                              c("#f2f0f7","#cbc9e2","#9e9ac8","#6a51a3"))

lgd_npx = Legend(title = "NPX", col_fun = col_npx,
                 title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

lgd_gex = Legend(title = "GEX", col_fun = scaled_01_col,
                 title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

lgd_celltype_freq = Legend(title = "Cell frequency\nof CD45+",
                           col_fun = cell_freq_color,
                 title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

lgd_severity = Legend(title = "Severity group", 
                      at = c("severe","moderate","mild","convalescence"),
                      legend_gp = gpar(fill = c("#ca0020","#f4a582","#92c5de","grey50")),
                      title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))


lgd_celltype = Legend(title = "Celltypes", 
                      at = c("DC","Monocytes","NK","gdT","B","CD4+ T","CD8+ T"),
                      legend_gp = gpar(fill = c("#ca5369","#688bcc","#8761cc", "#ae953e",
                                                "#c361aa","#68a748","#cc693d")),
                      ncol = 1,
                      #nrow = 1,
                      title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

lgd_celltype_2 = Legend(title = "Celltypes", 
                      at = c("mDC","pDC",
                             "CD14 monocytes","CD16 monocytes",
                             "NK CD56dim CD16+","NK CD56dim","NKCD56bright","NK prolif.","NKT",
                             "Vd2+ gdT","Vd2- gdT",
                             "B naive",
                             "B memory",
                             "Plasma cells",
                             "CD4 naive", "CD4 Treg CD80+", "CD4 Treg CD80-", "CD4 Tfh",
                             "CD4 effect. activated","CD4 effect. memory","CD4 trans.memory","CD central memory",
                             "CD8 naive", "CD8 trans. memory","CD8Tfh","CD8 effect. memory"),
                             #,(L2_colors),
                      legend_gp = gpar(fill = L2_colors),
                      
                      ncol=1,
                      #nrow = 4,
                      title_gp = gpar(fontsize=6,fontface="bold"),
                      labels_gp = gpar(fontsize=6))

circle_size = unit(1, "snpc") # snpc unit gives you a square region

## == circos.heatmap.get.x start ====

## A function to extract row indicies, useful for labelling

## source: https://rdrr.io/github/jokergoo/circlize/src/R/circos.heatmap.R
# == title
# Get the x-position for heatmap rows
#
# == param
# -row_ind A vector of row indicies.
#
# == value
# A three-column data frame of the sector, the x-positions on the corresponding sectors, and the original row indicies.
circos.heatmap.get.x = function(row_ind) {
    env = circos.par("__tempenv__")
    split = env$circos.heatmap.split

    row_ind_lt = split(row_ind, split[row_ind])
    row_ind_lt = row_ind_lt[sapply(row_ind_lt, length) > 0]
    
    x = NULL
    for(i in row_ind_lt) {

        subset = get.cell.meta.data("subset", sector.index = split[i[1]])
        order = get.cell.meta.data("row_order", sector.index = split[i[1]])
        
        x = c(x, which((1:length(split))[subset][order] %in% i))
    }
    df = data.frame(sector = rep(names(row_ind_lt), times = sapply(row_ind_lt, length)), 
        x = x - 0.5, row_ind = unlist(row_ind_lt))
    rownames(df) = NULL
    df
}
## == circos.heatmap.get.x end ====

total_sections <- length(levels(mat$celltype))


## the function to make the plot
circlize_plot = function() {
    circos.clear()

  circos.par(gap.after = c(rep(2,total_sections-1),10), 
             points.overflow.warning = T)
#circos.par(start.degree = 90, gap.degree = 10,gap.after = c(3))

## dummy track, invisible, needed for split
circos.heatmap(mat_gex,
               cluster = F,
               split = droplevels(mat$celltype),
               col = colorRamp2(c(-2, 0, 2), c("white", "white", "white")), 
               track.height = 0.21,#0.000000001,
               )

## celltype annotation track
circos.heatmap(mat %>% column_to_rownames("gene_ct") %>% dplyr::select(celltype), 
               col = L2_colors, 
               track.height = 0.08,
               rownames.side = "none",
 )

## celltype frequency track
circos.heatmap(mat %>% column_to_rownames("gene_ct") %>% transmute(CellType_L2 = celltype) %>% left_join(celltype_l2_freq, by="CellType_L2") %>% pull(Percentage), col = cell_freq_color, track.height = 0.01)

## celltype annotation tack naming
circos.trackPlotRegion(track.index = 1, panel.fun = function(x, y) {
  xlim = get.cell.meta.data("xlim")
  ylim = get.cell.meta.data("ylim")
  sector.name = get.cell.meta.data("sector.index")
  circos.text(mean(xlim),
              ylim[1] + .1, 
              sector.name, 
              facing = "clockwise", 
              niceFacing = TRUE, cex=.6,
              adj = c(0, 0.5), col = "grey40")
}, bg.border = NA)

## celltype gene expression track
circos.heatmap(mat_gex,
               cluster = F, 
               col = scaled_01_col, 
               track.height = 0.04,
               # rownames.side = "outside",
               bg.border = "grey80", 
               bg.lwd = .1,
               bg.lty = .1, 
               show.sector.labels = F
)

## plasma NPX trac
circos.heatmap(mat_npx, col = col_npx, track.height = 0.09)

## add annotation to row of npx data
circos.track(track.index = get.current.track.index(), panel.fun = function(x, y) {
    if(CELL_META$sector.numeric.index == total_sections) { # the last sector #26
      ## conval
        circos.rect(CELL_META$cell.xlim[2] + convert_x(1, "mm"), 0,
                    CELL_META$cell.xlim[2] + convert_x(4, "mm"), 1, #10
                    col = "grey50", border = NA)
      ## mild  
      circos.rect(CELL_META$cell.xlim[2] + convert_x(1, "mm"), 1,
                    CELL_META$cell.xlim[2] + convert_x(4, "mm"), 2, #5
                    col = "#92c5de", border = NA)
      ## moderate
        circos.rect(CELL_META$cell.xlim[2] + convert_x(1, "mm"), 2,
                    CELL_META$cell.xlim[2] + convert_x(4, "mm"), 3, #10
                    col = "#f4a582", border = NA)
        ## severe
        circos.rect(CELL_META$cell.xlim[2] + convert_x(1, "mm"), 3,
                    CELL_META$cell.xlim[2] + convert_x(4, "mm"), 4, #10
                    col = "#ca0020", border = NA)
       
    }
}, bg.border = NA)

## Annotate source genes
row_ind <- mat %>% filter(gene%in%df_link$source_gene) %>% mutate(rowname = as.integer(rowname)) %>% pull(rowname)
pos_so = circos.heatmap.get.x(row_ind)
pos_so <- pos_so %>% right_join(mat %>% filter(gene%in%df_link$source_gene) %>% mutate(row_ind = as.integer(rowname)), by="row_ind")

## Annotate recipient genes
row_ind <- mat %>% filter(gene%in%df_link$recipient_gene) %>% mutate(rowname = as.integer(rowname)) %>% pull(rowname)
pos_rec = circos.heatmap.get.x(row_ind)
pos_rec <- pos_rec %>% right_join(mat %>% filter(gene%in%df_link$recipient_gene) %>% mutate(row_ind = as.integer(rowname)), by="row_ind")

pos <- bind_rows(pos_so, pos_rec)

## lable all other genes

## Annotate source genes
row_ind_allothers <- mat %>% filter(!gene %in% c(df_link$source_gene,df_link$recipient_gene)) %>% mutate(rowname = as.integer(rowname)) %>% pull(rowname)

pos_allothers = circos.heatmap.get.x(row_ind_allothers) %>% 
  left_join(mat %>% mutate(row_ind = as.integer(rowname)), by="row_ind")

## join all lable info
pos_all <- bind_rows(pos %>% mutate(col = "black",
                                    size = .4),
                     pos_allothers %>% mutate(col = "grey",
                                              size=.2))

circos.labels(pos_all$sector, 
              pos_all$x,
              connection_height =.01,
              cex =pos_all$size,
              side="inside",
              col = pos_all$col, 
              labels = pos_all$gene)

## add connections
for(i in seq_len(nrow(df_link))) {

        circos.heatmap.link(df_link$from_index[i],
                        df_link$to_index[i],
                        col = rand_color(1),
                        
                        lwd = 1.5,
                        directional = 1,
                        arr.width = .125,
                        arr.length = .2,
                        arr.lwd = .1,
                       arr.col = "black")
}


  circos.clear()
}

library(gridBase)
pdf(paste0(result.tmp.dir,pdf_file_name,".pdf"))#,paper = "a4r")
plot.new()

circle_size = unit(1, "snpc") # snpc unit gives you a square region

pushViewport(viewport(x = 0.5, y = 1,#0.5,
                      width = circle_size, 
                      height = circle_size,
    just =  c("center", "top")))
par(omi = gridOMI(), new = TRUE)
circlize_plot()
upViewport()

draw(packLegend(lgd_gex, lgd_npx,
                direction = "horizontal"),
     y = unit(1, "npc") - circle_size*.1, 
     x = unit(1.04,"npc") - circle_size*0.1,
     just = c("center","right"))

draw(packLegend(lgd_celltype_freq,
                direction = "horizontal"),
     #y = unit(1, "npc") - circle_size*.1, 
     x = unit(1.04,"npc") - circle_size*0.1,
     just = c("center","right"))


draw(packLegend(lgd_severity,
                direction = "horizontal"),
     y = unit(1, "npc") - circle_size*.8, 
     x = unit(1.0,"npc") - circle_size*0.11,
     just = c("bottom","left"))
dev.off()
return(circlize_plot())
}
my_nice_circosplot(assays2plot_circos = restricted_module_turquoise,
                   scale_range = c(0,1),
                   expression_threshold = 0.5,
                   pdf_file_name = "ImmuneCell_Protein_CircosPlot_severitymodule"
                   )

Figure 7E

my_comparisons_severe_conv <- list(c("severe", "moderate"), c("moderate", "mild"), c("severe", "mild"),c("mild","convalescence"))

selection <- c("LGALS9","IL4","CD274","CD70")

(severity_ligand_npx <- df_acute_patclust_incl_conv %>% 

    dplyr::filter(Assay %in% c(selection)) %>% 
    mutate(Assay = factor(Assay, levels = c(selection))) %>% 
    ggplot(aes(x=severity_lab, y=NPX, color=severity_lab, fill=severity_lab)) + 
    geom_violin(trim = F,alpha=.9) +
    geom_jitter(size=0.25,show.legend = F, width = 0.05, alpha=1, color="grey20") +
    geom_boxplot(alpha=.7,width=0.25,outlier.shape = NA,color="black", fatten = 2,lwd=.25,show.legend = F) +
    stat_compare_means(method = "wilcox.test",
                       label.sep = "\n",
                       hide.ns = T,
                       label = "p.signif" ,
                       vjust = .5,
                       size=2,
                       lwd = .2,
                       comparisons =my_comparisons_severe_conv,
                       show.legend = F) +
    facet_wrap(~Assay,nrow = 2,scales = "free_y") +
    theme_minimal() +
    theme(legend.position="bottom",
          axis.text.x = element_blank()) +
    labs(x="",
         color=NULL,
         fill=NULL) +
    scale_color_manual(values= patient_kclust3_lab_conv) +
    scale_fill_manual(values= patient_kclust3_lab_conv))

Figure 7F

#FACs_data %>% distinct(feature)

cellsubset.order <- FACs_data %>% 
  filter(feature%in%c("CD4+CD38+HLADR+ T cells","CD8+CD38+HLADR+ T cells"),
#    grepl("Treg",feature)
    ) %>% distinct(feature) %>% pull()

test_correlation_input <- FACs_data %>% 
  filter(Time=="Acute",
         feature%in%
           c(
           "CD4+CD38+HLADR+ T cells",
           "CD8+CD38+HLADR+ T cells"
         )
  ) %>% 
  transmute(sample_id = sampleID,
            type_feature = paste0("FACS_",feature),
            value) %>% 
  pivot_wider(values_from = value, names_from = type_feature) %>% 
  inner_join(
    ## Plasma protein data from this paper
    data.long %>% 
      inner_join(sampleTable_simple) %>% 
      filter(Assay %in% restricted_module_turquoise) %>% 
      transmute(
        sample_id,
        type_assay = paste0("PEA_",Assay),
        NPX) %>% 
      pivot_wider(values_from = NPX, names_from = type_assay),
    by="sample_id")
test_correlation_res <- test_correlation_input %>% 
  column_to_rownames("sample_id") %>% 
  correlation(p_adjust = "fdr",method = "spearman",redundant = F) %>% 
  tibble()
cor.g <- test_correlation_res %>% 
  filter(Parameter1!=Parameter2) %>% 
  filter(
    !grepl("PEA",Parameter1),
    !grepl("FACS",Parameter2)
  ) %>% 
   arrange(-abs(rho)) %>% 
  filter(p<=0.05) %>% 
     transmute(from = Parameter1,# = str_remove(Parameter1, "FACS_"),
            to = Parameter2,# = str_remove(Parameter2, "PEA_"),
            rho,
            p
            ) %>% 
  as_tbl_graph(directed = F)

node_table <- as_tibble(cor.g) %>% 
  separate(name, into=c("omics","feature"),sep = "_",remove = F) 
(protein_cellnum_cornet <- cor.g %>% 
  inner_join(node_table,by="name") %>% 
    activate(nodes) %>%  # Sets context to nodes -> subsequent operations are performed on nodes
  mutate(deg = centrality_degree()) %>% 
  filter(!node_is_isolated()) %>%  # Removes nodes that are isolated/do not have any follower edges
# create_layout(layout = "igraph", algorithm = "fr") %>% 
  create_layout(layout = "stress") %>%  #fr
  ggraph() +
    geom_edge_link(aes(color = rho),
                   #    alpha = 0.9
                   ) +  
  scale_edge_color_continuous(low="thistle2",
                              high="darkred") +
  geom_node_point(aes(color = omics,
                      size= ifelse(omics=="FACS",3,1)),
                  show.legend = F) +
  geom_node_text(aes(label = feature,
                     alpha= ifelse(deg>1,1,.5)
                     ),
                 color="black",
                 size=1.5,
                 repel = T,show.legend = F
                     ) +
  scale_alpha_continuous(range = c(0.5, 1)) +
  theme_void() +
    guides(color= guide_colorbar(barheight = 1, barwidth = .1)) +

   theme(legend.position = "right",
         plot.title = element_text(size=6),
         legend.title = element_text( size=6),
         legend.text=element_text(size=6)) 

)

Session Info

sessionInfo()
## R version 4.3.2 (2023-10-31)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS Sonoma 14.7.4
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: Europe/Berlin
## tzcode source: internal
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] gridBase_0.4-7        GSVA_1.48.3           UpSetR_1.4.0         
##  [4] see_0.8.0             pathview_1.40.0       ggtext_0.1.2         
##  [7] gtsummary_1.7.2       emmeans_1.8.7         lmerTest_3.1-3       
## [10] lme4_1.1-34           eulerr_7.0.2          mixOmics_6.24.0      
## [13] lattice_0.21-8        MASS_7.3-60           WGCNA_1.72-1         
## [16] fastcluster_1.2.3     dynamicTreeCut_1.63-1 scales_1.2.1         
## [19] ggraph_2.1.0          tidygraph_1.2.3       umap_0.2.10.0        
## [22] clusterProfiler_4.8.2 SeuratObject_4.1.3    Seurat_4.3.0.1       
## [25] ggalluvial_0.12.5     ggrepel_0.9.3         correlation_0.8.4    
## [28] ggpubr_0.6.0          igraph_1.5.0.1        broom_1.0.5          
## [31] circlize_0.4.15       ComplexHeatmap_2.16.0 RColorBrewer_1.1-3   
## [34] viridis_0.6.4         viridisLite_0.4.2     gridExtra_2.3        
## [37] patchwork_1.1.2       Matrix_1.6-0          DT_0.28              
## [40] readxl_1.4.3          lubridate_1.9.2       forcats_1.0.0        
## [43] stringr_1.5.0         dplyr_1.1.2           purrr_1.0.1          
## [46] readr_2.1.4           tidyr_1.3.0           tibble_3.2.1         
## [49] ggplot2_3.4.2         tidyverse_2.0.0      
## 
## loaded via a namespace (and not attached):
##   [1] graph_1.78.0                ica_1.0-3                  
##   [3] plotly_4.10.2               Formula_1.2-5              
##   [5] zlibbioc_1.46.0             tidyselect_1.2.0           
##   [7] bit_4.0.5                   doParallel_1.0.17          
##   [9] clue_0.3-64                 rjson_0.2.21               
##  [11] blob_1.2.4                  broom.helpers_1.13.0       
##  [13] S4Arrays_1.0.5              pbkrtest_0.5.2             
##  [15] parallel_4.3.2              Biobase_2.60.0             
##  [17] png_0.1-8                   cli_3.6.3                  
##  [19] ggplotify_0.1.1             bayestestR_0.13.1          
##  [21] askpass_1.1                 openssl_2.1.0              
##  [23] goftest_1.2-3               broom.mixed_0.2.9.4        
##  [25] uwot_0.1.16                 shadowtext_0.1.2           
##  [27] curl_5.0.1                  mime_0.12                  
##  [29] evaluate_0.21               tidytree_0.4.4             
##  [31] leiden_0.4.3                V8_4.3.3                   
##  [33] stringi_1.7.12              backports_1.4.1            
##  [35] XML_3.99-0.14               httpuv_1.6.11              
##  [37] AnnotationDbi_1.62.2        magrittr_2.0.3             
##  [39] splines_4.3.2               org.Hs.eg.db_3.17.0        
##  [41] sctransform_0.3.5           ggbeeswarm_0.7.2           
##  [43] DBI_1.1.3                   ggExtra_0.10.1             
##  [45] HDF5Array_1.28.1            jquerylib_0.1.4            
##  [47] withr_2.5.0                 corpcor_1.6.10             
##  [49] enrichplot_1.20.0           lmtest_0.9-40              
##  [51] GSEABase_1.62.0             htmlwidgets_1.6.2          
##  [53] S4Vectors_0.38.1            SingleCellExperiment_1.22.0
##  [55] ggvenn_0.1.10               labeling_0.4.2             
##  [57] cellranger_1.1.0            MatrixGenerics_1.12.3      
##  [59] annotate_1.78.0             reticulate_1.30            
##  [61] zoo_1.8-12                  XVector_0.40.0             
##  [63] knitr_1.43                  BiocGenerics_0.46.0        
##  [65] gt_0.9.0                    timechange_0.2.0           
##  [67] foreach_1.5.2               fansi_1.0.4                
##  [69] data.table_1.14.8           ggtree_3.8.0               
##  [71] rhdf5_2.44.0                RSpectra_0.16-1            
##  [73] irlba_2.3.5.1               ggrastr_1.0.2              
##  [75] gridGraphics_0.5-1          commonmark_1.9.0           
##  [77] ellipsis_0.3.2              lazyeval_0.2.2             
##  [79] yaml_2.3.7                  survival_3.5-7             
##  [81] scattermore_1.2             crayon_1.5.2               
##  [83] RcppAnnoy_0.0.21            progressr_0.13.0           
##  [85] tweenr_2.0.2                later_1.3.1                
##  [87] Rgraphviz_2.44.0            ggridges_0.5.4             
##  [89] codetools_0.2-19            base64enc_0.1-3            
##  [91] GlobalOptions_0.1.2         KEGGREST_1.40.0            
##  [93] ggfittext_0.10.1            Rtsne_0.16                 
##  [95] shape_1.4.6                 estimability_1.4.1         
##  [97] foreign_0.8-85              pkgconfig_2.0.3            
##  [99] KEGGgraph_1.60.0            xml2_1.3.5                 
## [101] GenomicRanges_1.52.0        IRanges_2.34.1             
## [103] aplot_0.1.10                spatstat.sparse_3.0-2      
## [105] ape_5.7-1                   xtable_1.8-4               
## [107] car_3.1-2                   highr_0.10                 
## [109] plyr_1.8.8                  polylabelr_0.2.0           
## [111] httr_1.4.6                  tools_4.3.2                
## [113] globals_0.16.2              beeswarm_0.4.0             
## [115] htmlTable_2.4.1             checkmate_2.2.0            
## [117] nlme_3.1-163                HDO.db_0.99.1              
## [119] digest_0.6.33               numDeriv_2016.8-1.1        
## [121] furrr_0.3.1                 farver_2.1.1               
## [123] tzdb_0.4.0                  reshape2_1.4.4             
## [125] yulab.utils_0.0.6           rpart_4.1.21               
## [127] glue_1.6.2                  cachem_1.0.8               
## [129] polyclip_1.10-4             Hmisc_5.1-0                
## [131] generics_0.1.3              Biostrings_2.68.1          
## [133] stats4_4.3.2                mvtnorm_1.2-2              
## [135] parallelly_1.36.0           impute_1.74.1              
## [137] ScaledMatrix_1.8.1          carData_3.0-5              
## [139] minqa_1.2.5                 pbapply_1.7-2              
## [141] randomcoloR_1.1.0.1         SummarizedExperiment_1.30.2
## [143] vroom_1.6.3                 gson_0.1.0                 
## [145] utf8_1.2.3                  graphlayouts_1.0.0         
## [147] datawizard_0.8.0            preprocessCore_1.62.1      
## [149] ggsignif_0.6.4              shiny_1.7.4.1              
## [151] GenomeInfoDbData_1.2.10     rhdf5filters_1.12.1        
## [153] parameters_0.21.1           RCurl_1.98-1.12            
## [155] memoise_2.0.1               rmarkdown_2.23             
## [157] downloader_0.4              future_1.33.0              
## [159] RANN_2.6.1                  Cairo_1.6-1                
## [161] spatstat.data_3.0-1         rstudioapi_0.15.0          
## [163] cluster_2.1.4               janitor_2.2.0              
## [165] spatstat.utils_3.0-3        hms_1.1.3                  
## [167] fitdistrplus_1.1-11         munsell_0.5.0              
## [169] cowplot_1.1.1               colorspace_2.1-0           
## [171] ellipse_0.5.0               rlang_1.1.1                
## [173] GenomeInfoDb_1.36.1         DelayedMatrixStats_1.22.6  
## [175] sparseMatrixStats_1.12.2    ggforce_0.4.1              
## [177] mgcv_1.9-0                  xfun_0.39                  
## [179] coda_0.19-4                 iterators_1.0.14           
## [181] matrixStats_1.0.0           rARPACK_0.11-0             
## [183] abind_1.4-5                 GOSemSim_2.26.1            
## [185] treeio_1.25.2               Rhdf5lib_1.22.1            
## [187] bitops_1.0-7                promises_1.2.0.1           
## [189] scatterpie_0.2.1            RSQLite_2.3.1              
## [191] qvalue_2.32.0               fgsea_1.26.0               
## [193] DelayedArray_0.26.7         GO.db_3.17.0               
## [195] compiler_4.3.2              beachmat_2.16.0            
## [197] boot_1.3-28.1               listenv_0.9.0              
## [199] Rcpp_1.0.11                 BiocSingular_1.16.0        
## [201] tensor_1.5                  BiocParallel_1.34.2        
## [203] insight_0.19.3              gridtext_0.1.5             
## [205] spatstat.random_3.1-5       R6_2.5.1                   
## [207] fastmap_1.1.1               fastmatch_1.1-3            
## [209] rstatix_0.7.2               vipor_0.4.5                
## [211] ROCR_1.0-11                 rsvd_1.0.5                 
## [213] nnet_7.3-19                 gtable_0.3.3               
## [215] KernSmooth_2.23-22          miniUI_0.1.1.1             
## [217] deldir_1.0-9                htmltools_0.5.5            
## [219] bit64_4.0.5                 spatstat.explore_3.2-1     
## [221] lifecycle_1.0.3             nloptr_2.0.3               
## [223] sass_0.4.7                  vctrs_0.6.3                
## [225] spatstat.geom_3.2-4         snakecase_0.11.0           
## [227] DOSE_3.26.1                 ggfun_0.1.1                
## [229] sp_2.0-0                    future.apply_1.11.0        
## [231] bslib_0.5.0                 pillar_1.9.0               
## [233] magick_2.8.1                jsonlite_1.8.7             
## [235] markdown_1.7                GetoptLong_1.0.5

Figure Panels

includes also saving data for supplementary

#eval=FALSE
source_rmd <- function(rmd_file){
  knitr::knit(rmd_file, output = tempfile())
}

source_rmd("Make_my_figurepanels.Rmd")

## make one Pdf
library(qpdf)
qpdf::pdf_combine(
  input = c("../Manuscript/Figure_1.pdf", 
            "../Manuscript/Figure_2.pdf",
            "../Manuscript/Figure_3.pdf", 
            "../Manuscript/Figure_4.pdf", 
            "../Manuscript/Figure_5.pdf", 
            "../Manuscript/Figure_6.pdf",
            "../Manuscript/Figure_7.pdf"),
  output = "../Manuscript/Lautenbach_etal_mainfigures.pdf"
)

qpdf::pdf_combine(
  input = c("../Manuscript/Figure_1_S1.pdf", 
            "../Manuscript/Figure_1_S2.pdf", 
            "../Manuscript/Figure_1_S3.pdf", 
            
            "../Manuscript/Figure_2_S4.pdf",
            "../Manuscript/Figure_2_S5.pdf", 
            
            "../Manuscript/Figure_3_S6.pdf", 
            "../Manuscript/Figure_3_S7.pdf", 
            
            "../Manuscript/Figure_4_S8.pdf",
            
            "../Manuscript/Figure_5_S9.pdf"
            ),
  output = "../Manuscript/Lautenbach_etal_supplementaryfigures.pdf"
)
LS0tCnRpdGxlOiAiSW50ZWdyYXRlZCBwcm90ZW9taWNzIGFuZCBzaW5nbGUtY2VsbCB0cmFuc2NyaXB0b21pY3MgcmV2ZWFsIGltbXVuZSBkeW5hbWljcyBhbmQgc2V2ZXJpdHkgbWFya2VycyBpbiBhY3V0ZSBQbGFzbW9kaXVtIGZhbGNpcGFydW0gbWFsYXJpYSIKYXV0aG9yOiAiTWF4aW1pbGlhbiBKdWxpdXMgTGF1dGVuYmFjaCIKZGF0ZTogJzIwMjQtMDMtMjgnCm91dHB1dDoKICAgaHRtbF9kb2N1bWVudDoKICAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIgogICAgIHRvYzogdHJ1ZQogICAgIGRlcHRoOiAyCiAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgIGdpdGh1Yl9kb2N1bWVudDoKICAgICAgIHByZXZpZXdfaHRtbDogZmFsc2UKICAgICAgIAogICAgICAgYWJzdHJhY3Q6IFRoaXMgbWFya2Rvd24gY29udGFpbnMgYWxsIGNvZGUgcmVsYXRlZCB0byBkb3duc3RyZWFtIGFuYWx5c2lzIGFuZCBmaWd1cmVzIG9mIHRoZSBtYW51c2NyaXB0LgotLS0KCiMgU2V0IHVwCmBgYHtyIHNldHVwLWNodW5rLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSkKYGBgCgoqKkxvYWQgbGlicmFyaWVzKioKCmBgYHtyIGxpYnJhcmllcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KGJyb29tKQojbGlicmFyeShicm9vbS5taXhlZCkKbGlicmFyeShpZ3JhcGgpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGNvcnJlbGF0aW9uKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoZ2dhbGx1dmlhbCkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpsaWJyYXJ5KHVtYXApICMjIGh0dHBzOi8vZ2l0aHViLmNvbS90a29ub3BrYS91bWFwL2Jsb2IvbWFzdGVyL3ZpZ25ldHRlcy91bWFwLlJtZApsaWJyYXJ5KHRpZHlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KFdHQ05BKQpsaWJyYXJ5KG1peE9taWNzKQpsaWJyYXJ5KGV1bGVycikKbGlicmFyeShsbWVyVGVzdCkKI2xpYnJhcnkoYnJvb20ubWl4ZWQpCmxpYnJhcnkoZW1tZWFucykKYGBgCgoqKkxvYWQgZGF0YSoqCgpgYGB7ciBsb2FkLWRhdGEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgTWFsYXJpYSBFeHBsb3JlIDE1MzYgZGF0YQpkYXRhIDwtIHV0aWxzOjpyZWFkLmRlbGltKCIuLi9kYXRhL2RhdGEvZXhwbG9yZTE1MzYvMjAyMzA0MTFfaW5mZWN0aW91c19vbGluay50c3YiKSAKIyBNYWxhcmlhIHNhbXBsZVRhYmxlCnNhbXBsZVRhYmxlX3NpbXBsZSA8LSByZWFkUkRTKCIuLi9kYXRhL21ldGFEYXRhX2NsZWFuL0V4cGxvcmUxNTM2X01hbGFyaWFfc2FtcGxlVGFibGVfc2ltcGxlLnJkcyIpCiMgTWFsYXJpYSBzdWJqZWN0VGFibGUKc3ViamVjdFRhYmxlIDwtIHJlYWRSRFMoIi4uL2RhdGEvbWV0YURhdGFfY2xlYW4vTWFsYXJpYVJlc291cmNlX3N1YmplY3RUYWJsZS5yZHMiKQojIE1hbGFyaWEgY2xpbmNoZW0gZGF0YQpjbGluY2hlbV9zdHVkeV9wYXRzX2FjdXRlLndpZGUgPC0gcmVhZFJEUygiLi4vZGF0YS9tZXRhRGF0YV9jbGVhbi9FeHBsb3JlMTUzNl9DbGluaWNhbENoZW1pc3RyeV9hY3V0ZS5yZHMiKQoKIyBUcm9waWNhbCBmZXZlciBFeHBsb3JlIDE1MzYgZGF0YQpURi5sb25nIDwtIHJlYWRSRFMoIi4uL2RhdGEvZGF0YV9jbGVhbi9FeHBsb3JlMTUzNl9URl90aWR5X2xvbmcucmRzIikKIyBUcm9waWNhbCBmZXZlciBzYW1wbGVUYWJsZQpURl9zYW1wbGVUYWJsZSA8LSByZWFkUkRTKCIuLi9kYXRhL21ldGFEYXRhX2NsZWFuL0V4cGxvcmUxNTM2X1RGX3NhbXBsZVRhYmxlLnJkcyIpCgoKIyBIUEEgdjI0CmhwYV8yNC4wIDwtIHJlYWRfdHN2KCIuLi9kYXRhL2hwYS9wcm90ZWluYXRsYXNfdjI0LnRzdiIpICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JSAKICBtdXRhdGUoc2VjcmV0b21lX2xvY2F0aW9uID0gaWZlbHNlKGlzLm5hKHNlY3JldG9tZV9sb2NhdGlvbiksIk5vdCBzZWNyZXRlZCIsc2VjcmV0b21lX2xvY2F0aW9uKSkKIyBIUEEgdGlzc3VlIGV4cHJlc3Npb24gdjIzCmhwYS50aXNzdWUgPC0gcmVhZF90c3YoIi4uL2RhdGEvaHBhL3JuYV90aXNzdWVfY29uc2Vuc3VzLnRzdiIpICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpCgoKIyBMb2FkIGNsZWFuZWQgbWFsYXJpYSBkYXRhCiMtICAgYXNzYXlzIHdpdGggUUMgd2FybiBpbiBtb3JlIHRoYW4gNzAlIG9mIGFsbCBhc3NheXMKIy0gICBzYW1wbGVzIHdpdGggbW9yZSB0aGFuIDcwJSBiZWxvdyBMT0QKZGF0YS53aWRlIDwtIHJlYWRSRFMoIi4uL2RhdGEvZGF0YV9jbGVhbi9FeHBsb3JlMTUzNl90aWR5X3dpZGUucmRzIikKZGF0YS5sb25nIDwtIHJlYWRSRFMoIi4uL2RhdGEvZGF0YV9jbGVhbi9FeHBsb3JlMTUzNl90aWR5X2xvbmcucmRzIikKCiMjIEV4cGxvcmUgMTUzNiBkYXRhIHNldCAtIE1HSCBDb3ZpZC0xOSBzdHVkeSwgRmlsYmluIGV0IGFsLiAyMDIxCmNvdmlkX05QWGRhdGEgPC0gcmVhZF9kZWxpbSgiLi4vZGF0YS9NR0hfT0xJTktfQ09WSUQvTUdIX0NPVklEX09MSU5LX05QWC50eHQiLGNvbW1lbnQgPSAiIyMiKQptZ2guY292aWQubWV0YSA8LSByZWFkX2RlbGltKCIuLi9kYXRhL01HSF9PTElOS19DT1ZJRC9NR0hfQ09WSURfQ2xpbmljYWxfSW5mby50eHQiLCBjb21tZW50PSIjIyIpICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpCm1naC5jb3ZpZC5tZXRhLmtleSA8LSByZWFkX2V4Y2VsKCIuLi9kYXRhL01HSF9PTElOS19DT1ZJRC92YXJpYWJsZV9kZXNjcmlwdGlvbnMueGxzeCIpCgojIyBsb2FkIHRyb3BpY2FsIGZldmVyIGNvaG9ydCBkYXRhClRGX1NPRkEgPC0gcmVhZFJEUygiLi4vZGF0YS9tZXRhRGF0YV9jbGVhbi8yMDIxMjEzX1RGX0RBX1RST1BfU09GQXNjb3Jlcy5yZHMiKSAlPiUgZmlsdGVyKGRpYWdub3NlX2NsZWFuIT0iUC5mYWxjaXBhcnVtIikKVEYubG9uZyA8LSByZWFkUkRTKCIuLi9kYXRhL2RhdGFfY2xlYW4vRXhwbG9yZTE1MzZfVEZfdGlkeV9sb25nLnJkcyIpCgojIyBsb2RpbmcgIE1JUCBDb2hvcnQgRkFDUyBkYXRhIC0gTGF1dGVuYmFjaCBldCBhbC4gQ2VsbCBSZXBvcnRzIDIwMjIKCkZBQ3NfZGF0YSA8LSByZWFkX2RlbGltKCIuLi8uLi9NYWxhcmlhVHJhdmVsbGVycy9kYXRhL1RyYXZlbGxlckNvaG9ydF9GQUNTX2xvZzJjcHVfbG9uZy5jc3YiKQpGQUNTX21ldGEgPC0gcmVhZF9kZWxpbSgiLi4vLi4vTWFsYXJpYVRyYXZlbGxlcnMvZGF0YS9UcmF2ZWxsZXJDb2hvcnRfU3ViamVjdFRhYmxlLmNzdiIpCgpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CnJlc3VsdC5kaXIgPC0gIi4uL01hbnVzY3JpcHQvIgpyZXN1bHQudG1wLmRpciA8LSAiLi4vTWFudXNjcmlwdC90bXAvIgppZmVsc2UoaXNGQUxTRShkaXIuZXhpc3RzKHJlc3VsdC50bXAuZGlyKSksIAogICAgICAgZGlyLmNyZWF0ZShyZXN1bHQudG1wLmRpcixyZWN1cnNpdmUgPSBUUlVFKSxOQSkKYGBgCgoqKlNldCB0aGVtZSAmIGNvbG9ycyoqCgpgYGB7cn0KdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gNikpCgp0aW1lM19jb2wgPC0gYygiQWN1dGUiID0gIiNDNTFCN0QiLCAKICAgICAgICAgICAgICAgIkQxMCIgPSAiI0U5QTNDOSIsCiAgICAgICAgICAgICAgICJNMTIiID0gIiM0RDkyMjEiKQoKc2V4Ml9jb2wgPC0gYyhtYWxlID0gIiNjNWI4ZGMiLAogICAgICAgICAgICAgIGZlbWFsZSA9ICIjYjlkMmIxIikKCmVuZGVtaWMyX2NvbCA8LSBjKHByaW1hcnlfaW5mZWN0ZWQgPSAiIzk5OEVDMyIsCiAgICAgICAgICAgICAgICAgIHByZXZpb3VzbHlfZXhwb3NlZCA9ICIjRjFBMzQwIikKc2V2ZXJlXzVfY29sID0gYygiMSI9InRvbWF0byIsCiAgICAgICAgICAgICAgICAgIjAiPSJncmV5ODAiKQoKc2VjcmV0b21lX2xvY2F0aW9uX2NvbHMgPC0gYygiU2VjcmV0ZWQgdG8gYmxvb2QiID0gIiNGQjgwNzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbnRyYWNlbGx1bGFyIGFuZCBtZW1icmFuZSIgPSAiIzhERDNDNyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIG90aGVyIHRpc3N1ZXMiID0gIiNCM0RFNjkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCB0byBleHRyYWNlbGx1bGFyIG1hdHJpeCIgPSAiIzgwQjFEMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIGJyYWluIiA9ICIjYjlkMmIxIiwjIiNGQ0NERTUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCB0byBkaWdlc3RpdmUgc3lzdGVtIiA9ICIjRkRCNDYyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgLSB1bmtub3duIGxvY2F0aW9uIiA9ICIjRkZGRjAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gbWFsZSByZXByb2R1Y3RpdmUgc3lzdGVtIiA9IHNleDJfY29sW1sxXV0sIyIjQkVCQURBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gZmVtYWxlIHJlcHJvZHVjdGl2ZSBzeXN0ZW0iID0gc2V4Ml9jb2xbWzJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm90IHNlY3JldGVkIiA9ICIjRDlEOUQ5IikKCnNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlY19jb2xzIDwtIGMoc2VjcmV0b21lX2xvY2F0aW9uX2NvbHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiTm90IHNlY3JldGVkIC0gVGlzc3VlIGVucmljaGVkIiA9ICIjODg0MTlkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBUaXNzdWUgZW5oYW5jZWQiID0gIiM4Yzk2YzYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBzZWNyZXRlZCAtIEdyb3VwIGVucmljaGVkIiA9ICIjYjNjZGUzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBMb3cgdGlzc3VlIHNwZWNpZmljaXR5IiA9ICIjZWRmOGZiIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpTT0ZBX3N1Yl9jb2wgPSBjb2xvclJhbXAyKGMoMCw0KSwgYygid2hpdGUiLCJyZWQiKSkKCnBhdGllbnRfa2NsdXN0MyA8LSBjKCczJyA9ICIjOTJjNWRlIiwgJzInID0gIiNmNGE1ODIiLCAnMScgPSAiI2NhMDAyMCIpCnBhdGllbnRfa2NsdXN0M19sYWIgPC0gYygibWlsZCI9IiM5MmM1ZGUiLCAibW9kZXJhdGUiPSIjZjRhNTgyIiwgInNldmVyZSI9IiNjYTAwMjAiKQpwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYgPC0gYygibWlsZCI9IiM5MmM1ZGUiLCAibW9kZXJhdGUiPSIjZjRhNTgyIiwgInNldmVyZSI9IiNjYTAwMjAiLCJjb252YWxlc2NlbmNlIiA9ImdyZXk1MCIpCgoKClNPRkFfc3ViX2NvbCA9IGNvbG9yUmFtcDIoYygwLDQpLCBjKCJ3aGl0ZSIsInJlZCIpKQoKU09GQV90b3RhbF9jb2wgPSBjb2xvclJhbXAyKGMobWluKHN1YmplY3RUYWJsZSRTT0ZBX3RvdGFsLG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbihzdWJqZWN0VGFibGUkU09GQV90b3RhbCxuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoc3ViamVjdFRhYmxlJFNPRkFfdG90YWwsbmEucm0gPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKGJyZXdlci5wYWwoMyxuYW1lPSJQdUJ1IikpKQoKIyMgZGltZW5zaW5hbGl0eSByZWR1Y3Rpb24gdGhlbWUKbXlfZGltcmVkX3RoZW1lIDwtIHRoZW1lX2NsYXNzaWMoKSArIAogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICN0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgI2xlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgCgojIyBhNCBwZGYgdGhlbWUKdGhlbWVfYTRfcGRmIDwtIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICMjIGxlZ2VuZAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgxLCAnY20nKSwgI2NoYW5nZSBsZWdlbmQga2V5IHNpemUKICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjI1LCAnY20nKSwgI2NoYW5nZSBsZWdlbmQga2V5IGhlaWdodAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC4yNSwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSB3aWR0aAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksICNjaGFuZ2UgbGVnZW5kIHRpdGxlIGZvbnQgc2l6ZQogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICMjIGxhYmVsCiAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICBwbG90LmNhcHRpb24gPSAgZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgIyMgZmFjZXRfZ3JpZAogICAgICAgICAgICAgICAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LGZhY2U9ImJvbGQiKSwKICAgICAgICAgICAgICAgICAgICAgICNzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiCikKCiMjIHBhdGNod29yayBwYW5lbCBhNCBwZGYgdGhlbWUKcGF0Y2h3b3JrX3BhbmVsX2E0X3BkZiA8LSBwYXRjaHdvcms6OnBsb3RfYW5ub3RhdGlvbih0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNixmYWNlID0gJ2JvbGQnKQopLAp0YWdfbGV2ZWxzID0gJ0EnKSAKYGBgCgpgYGB7ciBleHRyYS1zYW1wbGUtaW5mb30KYXN5bV9zdHVkeV9pZCA8LSBjKCIyMDIxMDA0IikKCiMjIDIwMTMwMDQgLSBMaWIgMQojIyAyMDEzMDA3IC0gTGliIDIKIyMgMjAxMzAwOCAtIExpYiAzCiMjIDIwMTgwMDIgLSBMaWIgNAoKcmhhcHNvZHlfc3R1ZHlfaWRzIDwtIGMoIjIwMTMwMDQiLCIyMDEzMDA3IiwiMjAxMzAwOCIsIjIwMTgwMDIiKQpgYGAKCgpgYGB7ciBtYXBwaW5nLXVuaXByb3QtZW5zZW1ibCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI3JlcXVpcmUoY2x1c3RlclByb2ZpbGVyKQoKI2xlbmd0aCh1bmlxdWUoZGF0YSRVbmlQcm90KSkgIyMgMTQ2MwptYXBwaW5nX3VuaXByb3RfZW5zZW1ibCA8LSBiaXRyKHVuaXF1ZShkYXRhJFVuaVByb3QpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tVHlwZT0iVU5JUFJPVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9UeXBlPWMoIlNZTUJPTCIsICJFTlNFTUJMIiwiRU5UUkVaSUQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT3JnRGI9Im9yZy5Icy5lZy5kYiIpICU+JSAKICBkcGx5cjo6cmVuYW1lKFVuaVByb3QgPSBVTklQUk9ULAogICAgICAgICAgICAgICAgU3ltYm9sID0gU1lNQk9MLAogICAgICAgICAgICAgICAgRW5zZW1ibCA9IEVOU0VNQkwsCiAgICAgICAgICAgICAgICBFbnRyZXogPSBFTlRSRVpJRCkgJT4lCiAgaW5uZXJfam9pbihkYXRhICU+JSBkcGx5cjo6c2VsZWN0KEFzc2F5LFVuaVByb3QpICU+JSBkcGx5cjo6ZGlzdGluY3QoKSxieT0iVW5pUHJvdCIpCgojd3JpdGVfZGVsaW0obWFwcGluZ191bmlwcm90X2Vuc2VtYmwsICIuLi8uLi8yMDIyX0V4cGxvcmUxNTM2RmFybmVydExhYi9kYXRhL01hcHBpbmdfRXhwbG9yZV9VbmlQcm90MkVuc2VtYmwudHh0IikKYGBgCgoKIyBGaWd1cmUgMSAKKipQbGFzbWEgcHJvdGVvbWljIHBlcnR1cmJhdGlvbiBkdXJpbmcgY2xpbmljYWwgbWFsYXJpYSoqCi0gQ29ob3J0IGNoYXJhY3RlcmlzdGljcwpgYGB7cn0KZmlnMS5saXN0IDwtIGxpc3QoKQpgYGAKCiMjIEZpZ3VyZSAxQgpgYGB7cn0KKGZpZzEubGlzdFtbImdlbmVyYWxfc2V4X2FnZV9kaXN0Il1dIDwtIHN1YmplY3RUYWJsZSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9YWdlLCBmaWxsPXNleCkpICsKICAgIGdlb21fZGVuc2l0eShhbHBoYT0uNikgKwogICAgI3RoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXNleDJfY29sKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXNleDJfY29sKSArCiAgICAKICAgIGxhYnMoZmlsbD0iU2V4IiwKICAgICAgICAgeD0iYWdlIFt5ZWFyc10iLAogICAgICAgICB5PSJkZW5zaXR5IikKKQpgYGAKCiMjIEZpZ3VyZSAxQwpgYGB7cn0KKGZpZzEubGlzdFtbInRpbWVwb2ludF9zZXhfcGVyYyJdXSA8LXNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgCiAgICBpbm5lcl9qb2luKHN1YmplY3RUYWJsZSxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICBncm91cF9ieShUaW1lLHNleCkgJT4lIAogICAgdGFsbHkoKSAlPiUgCiAgICBncm91cF9ieShUaW1lKSAlPiUgCiAgICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQ9bi9zdW0obikpICU+JSAKICAgIGdncGxvdChhZXMoeD1UaW1lLHk9bixmaWxsPXNleCkpICsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSJmaWxsIikgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZTAoc3ByaW50ZigiJTEuMWYiLCBwZXJjZW50KjEwMCksIiUiKSksCiAgICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZmlsbCh2anVzdD0wLjUpLCBjb2xvdXI9IndoaXRlIiwgc2l6ZSA9MS41KSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LGV4cGFuZCA9IGMoMCwuMDEpKSArIAogICAgI3RoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1zZXgyX2NvbCkgKwogICAgbGFicyhmaWxsPU5VTEwsCiAgICAgICAgIHg9TlVMTCwKICAgICAgICAgeT0iUGVyY2VudGFnZSIpCikKYGBgCgojIyBGaWd1cmUgMUQKCmBgYHtyfQooZmlnMS5saXN0W1sidGltZXBvaW50X2V4cG9zdXJlIl1dIDwtIHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgCiAgICBpbm5lcl9qb2luKHN1YmplY3RUYWJsZSxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICBncm91cF9ieShUaW1lLGVuZGVtaWMpICU+JSAKICAgIHRhbGx5KCkgJT4lIAogICAgZ3JvdXBfYnkoVGltZSkgJT4lIAogICAgZHBseXI6Om11dGF0ZShwZXJjZW50PW4vc3VtKG4pKSAlPiUgCiAgbXV0YXRlKGVuZGVtaWMgPSBmYWN0b3IoZW5kZW1pYywgbGV2ZWxzPWMoInByaW1hcnlfaW5mZWN0ZWQiLCJwcmV2aW91c2x5X2V4cG9zZWQiKSkpICU+JSAKICAgIGdncGxvdChhZXMoeD1UaW1lLHk9bixmaWxsPWVuZGVtaWMpKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0iZmlsbCIpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUwKHNwcmludGYoIiUxLjFmIiwgcGVyY2VudCoxMDApLCIlIikpLAogICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2ZpbGwodmp1c3Q9MC41KSwgY29sb3VyPSJ3aGl0ZSIsIHNpemUgPTEuNSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCxleHBhbmQgPSBjKDAsLjAxKSkgKyAKICAgICN0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9ZW5kZW1pYzJfY29sLGxhYmVscz1jKCJwcmltYXJ5X2luZmVjdGVkIj0icHJpbWFyeSBpbmZlY3RlZCIsInByZXZpb3VzbHlfZXhwb3NlZCI9InByZXZpb3VzbHkgZXhwb3NlZCIpKSArCiAgICBsYWJzKGZpbGw9TlVMTCwKICAgICAgICAgeD1OVUxMLAogICAgICAgICB5PSJQZXJjZW50YWdlIikKKQpgYGAKCiMjIEZpZ3VyZSAxRQoKYGBge3J9CmRmIDwtIGRhdGEud2lkZSAlPiUgCiAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIAogICAgICAgICAgICAgICB0cmFuc211dGUoc2FtcGxlX2lkKSwKICAgICAgICAgICAgIGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKQoKIyMgUEMgY2FsY3VsYXRpb24KcGNhUmVzIDwtIHN0YXRzOjpwcmNvbXAoZGYsY2VudGVyID0gVFJVRSwgc2NhbGUuID0gVFJVRSkKdmFyRXhwIDwtIHJvdW5kKHBjYVJlcyRzZGV2XjIgLyBzdW0ocGNhUmVzJHNkZXZeMikgKiAxMDApCnBjYURGIDwtIGRhdGEuZnJhbWUoUEMxID0gcGNhUmVzJHhbLCAxXSwKICAgICAgICAgICAgICAgICAgICBQQzIgPSBwY2FSZXMkeFssIDJdKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAKCiMjIFByZXAgZm9yIHBsb3R0aW5nCmRhdGE0cGxvdCA8LSBwY2FERiAlPiUgCiAgZHBseXI6OmlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikKCgoocGNhX2ZpZzEgPC0gZGF0YTRwbG90ICU+JSAKICAgIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gVGltZSxmaWxsPU5VTEwsIGxhYmVsID0gTlVMTCkpICsKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjksIHNpemUgPSAxKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSB0aW1lM19jb2wpICsKICAgIGxhYnMoeCA9IHBhc3RlMCgiUEMxICgiLCAgdmFyRXhwWzFdLCAiICUpIiksCiAgICAgICAgIHkgPSBwYXN0ZTAoIlBDMiAoIiwgIHZhckV4cFsyXSwgIiAlKSIpKSArCiAgICB0aGVtZV9taW5pbWFsKCkgICsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksIAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSkKYGBgCgojIyBGaWd1cmUgMUYKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIG5lc3QgZGF0YQpkYXRhX25lc3RlZCA8LSBkYXRhLmxvbmcgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIGdyb3VwX2J5KFVuaVByb3QsQXNzYXkpICU+JSAKICBuZXN0KCkKYGBgCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMjIG5lc3QgZGF0YQpkYXRhX25lc3RlZCA8LSBkYXRhLmxvbmcgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIGxlZnRfam9pbihzdWJqZWN0VGFibGUgJT4lIHRyYW5zbXV0ZShzdHVkeV9pZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9zdXJlID0gZmFjdG9yKGVuZGVtaWMsIGxldmVscz1jKCJwcmltYXJ5X2luZmVjdGVkIiwicHJldmlvdXNseV9leHBvc2VkIikpKSwKICAgICAgICAgICAgYnk9InN0dWR5X2lkIikgJT4lIAogIGdyb3VwX2J5KFVuaVByb3QsQXNzYXkpICU+JSAKICBuZXN0KCkKCmxtZV9yZXMgPC0gZGF0YV9uZXN0ZWQgJT4lIAogIG11dGF0ZShsbWUucmVzLnNpbXBsZSA9IHB1cnJyOjptYXAoZGF0YSwgfiBsbWVyVGVzdDo6bG1lcihOUFggfiBUaW1lICsgZXhwb3N1cmUgKyAoMXxzdHVkeV9pZCksIFJFTUwgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbG1lNDo6bG1lckNvbnRyb2woY2hlY2suY29udi5zaW5ndWxhciA9ICJpZ25vcmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAueCAlPiUgZHBseXI6OmZpbHRlcihUaW1lIT0iRDEwIikpKSwKICAgICAgICAgbG1lLnJlcy5jb21wbGV4ID0gcHVycnI6Om1hcChkYXRhLCB+IGxtZXJUZXN0OjpsbWVyKE5QWCB+IFRpbWUgKiBleHBvc3VyZSArICgxfHN0dWR5X2lkKSwgUkVNTCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbG1lNDo6bG1lckNvbnRyb2woY2hlY2suY29udi5zaW5ndWxhciA9ICJpZ25vcmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAueCAlPiUgZHBseXI6OmZpbHRlcihUaW1lIT0iRDEwIikpKSwKICAgICAgICAgbG1lLnNpbXBsZS50aWR5ID0gcHVycnI6Om1hcChsbWUucmVzLnNpbXBsZSwgfiBicm9vbS5taXhlZDo6dGlkeSguLCkpLAogICAgICAgICBsbWUuY29tcGxleC50aWR5ID0gcHVycnI6Om1hcChsbWUucmVzLmNvbXBsZXgsIH4gYnJvb20ubWl4ZWQ6OnRpZHkoLikpLAoKICAgICAgICAgcG9zdGhvYy50aW1lID0gcHVycnI6Om1hcChsbWUucmVzLnNpbXBsZSwgfiBzdW1tYXJ5KGNvbnRyYXN0KGVtbWVhbnMoLiwgfiBUaW1lKSwgbWV0aG9kID0gInBhaXJ3aXNlIikpICU+JSB0aWJibGUoKSksCiAgICAgICAgIHBvc3Rob2MudGltZV9leHBvc3VyZSA9IHB1cnJyOjptYXAobG1lLnJlcy5jb21wbGV4LCB+IHN1bW1hcnkoY29udHJhc3QoZW1tZWFucyguLCB+IFRpbWUgKiBleHBvc3VyZSksIG1ldGhvZCA9ICJwYWlyd2lzZSIpKSAlPiUgdGliYmxlKCkpCiAgICAgICAgICkKYGBgCgoKLSBmaW5kaW5nIGJldHRlciBtb2RlbApgYGB7cn0KIyMgY29tcGFyZSBzaW1wbGUgKHdpdGhvdXQgaW50ZXJhY3Rpb24pIHdpdGggY29tcGxleCBtb2RlbCAoaW50ZXJhY3Rpb24pCmJpY19haWNfcmVzIDwtIGxtZV9yZXMgJT4lIAogIG11dGF0ZShzaW1wbGVfZ2xhbmNlID0gcHVycnI6Om1hcChsbWUucmVzLnNpbXBsZSwgfihicm9vbTo6Z2xhbmNlKC4pKSksCiAgICAgICAgIGNvbXBsZXhfZ2xhbmNlID0gcHVycnI6Om1hcChsbWUucmVzLmNvbXBsZXgsIH4oYnJvb206OmdsYW5jZSguKSkpKSAlPiUgCiAgdW5uZXN0KGNvbHMgPSBjKHNpbXBsZV9nbGFuY2UsY29tcGxleF9nbGFuY2UpLG5hbWVzX3NlcCA9ICIuIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoQXNzYXksIGNvbnRhaW5zKCJBSUMiKSxjb250YWlucygiQklDIikpCgpkZl9iZXR0ZXJfbW9kZWwgPC0gYmljX2FpY19yZXMgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzPWMoLVVuaVByb3QsLUFzc2F5KSkgJT4lIAogIHNlcGFyYXRlKG5hbWUsIGludG89YygibW9kZWwiLCJldmFsIiksc2VwID0gIlxcLiIscmVtb3ZlID0gVCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBtb2RlbCwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgJT4lIAogIG11dGF0ZShzaW1wbGVfYmV0dGVyID0gc2ltcGxlX2dsYW5jZSA8IGNvbXBsZXhfZ2xhbmNlLAogICAgICAgICBzaW1wbGVfZGVsdGEgPSBzaW1wbGVfZ2xhbmNlLWNvbXBsZXhfZ2xhbmNlLAogICAgICAgICBiZXR0ZXJfbW9kZWwgPSBjYXNlX3doZW4oYWJzKHNpbXBsZV9kZWx0YSk+NiB+ICJjb21wbGV4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gInNpbXBsZSIpKQpgYGAKCmBgYHtyfQpkZl9iZXR0ZXJfbW9kZWwgJT4lIAogIGdyb3VwX2J5KGV2YWwpICU+JSAKICBjb3VudChiZXR0ZXJfbW9kZWwpICU+JSAKICBnZ3Bsb3QoYWVzKHg9YmV0dGVyX21vZGVsLCB5PW4pKSArCiAgZ2VvbV9jb2woKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9biksc2l6ZT0yLG51ZGdlX3kgPSA1MCkgKyAKICBmYWNldF93cmFwKH5ldmFsKQpgYGAKCgpgYGB7cn0KZGZfYmV0dGVyX21vZGVsICU+JSBmaWx0ZXIoZXZhbD09IkJJQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHRlcl9tb2RlbD09ImNvbXBsZXgiKSAKYGBgCgoKCgoKYGBge3J9CmxtZV9yZXNfcGFkaiA8LSBsbWVfcmVzICU+JSAKICB1bm5lc3QoY29scz0icG9zdGhvYy50aW1lIikgJT4lIAogIGZpbHRlcihjb250cmFzdD09IkFjdXRlIC0gTTEyIikgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKHAuYWRqID0gcC5hZGp1c3QocC52YWx1ZSwgbWV0aG9kPSJmZHIiKSwKICAgICAgICAgICAgICAgICAgRkRSID0gaWZlbHNlKHAuYWRqIDw9IDAuMDEsIFRSVUUsRkFMU0UpKSAlPiUgCiAgYXJyYW5nZShwLmFkaikKYGBgCgoKYGBge3J9CmFzc2F5X2JldHRlcl9jb21wbGV4X21vZGVsIDwtIGRmX2JldHRlcl9tb2RlbCAlPiUgZmlsdGVyKGV2YWw9PSJCSUMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZXR0ZXJfbW9kZWw9PSJjb21wbGV4IikgJT4lIHB1bGwoQXNzYXkpCgpwbG90KGV1bGVyKAogIGxpc3QoImFjdXRlX20xMiIgPSBsbWVfcmVzX3BhZGogJT4lIGZpbHRlcihGRFI9PVQpICU+JSBwdWxsKEFzc2F5KSwKICAgICAgICJiaWNfY29tcGxleF9iZXR0ZXIiID0gYXNzYXlfYmV0dGVyX2NvbXBsZXhfbW9kZWwpKSwKICAKICAgICAgICBmaWxscyA9IGMoIiNDNTFCN0QiLAogICAgICAgICAgICAgICAgICAid2hpdGUiKSwKICAgICAgIHF1YW50aXRpZXMgPSBUUlVFLAogICAgICAgbHR5ID0gMSwjMTozLAogICAgICAgZm9udHNpemU9MiwKICAgICAgIGxhYmVscyA9IGxpc3QoZm9udHNpemU9NyksCiAgICAgICBzaGFwZSA9ICJlbGxpcHNlIixhZGp1c3RfbGFiZWxzID0gVCkKYGBgCgpgYGB7cn0KbG1lX3Jlc19wYWRqICU+JSAKICB0cmFuc211dGUoQXNzYXksIGVzdGltYXRlLHAuYWRqKSAlPiUgCiAgZmlsdGVyKEFzc2F5ICVpbiUgYXNzYXlfYmV0dGVyX2NvbXBsZXhfbW9kZWwpICU+JSAKICBhcnJhbmdlKC1hYnMoZXN0aW1hdGUpKQpgYGAKCmBgYHtyfQpkYXAucmVzIDwtIGxtZV9yZXNfcGFkaiAlPiUgCiAgZHBseXI6OnJlbmFtZShsb2dGQyA9IGVzdGltYXRlKSAlPiUgCiAgbXV0YXRlKGRpcmVjdGlvbiA9IGlmZWxzZShsb2dGQzwwLCJkb3duIiwidXAiKSkgICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jKGxtZS5yZXMuc2ltcGxlLGxtZS5yZXMuY29tcGxleCxsbWUuY29tcGxleC50aWR5KSkKYGBgCgoKYGBge3J9CihkYXAuYWN1dGUudm9sY2FubyA8LSBkYXAucmVzICU+JSAKICAgZ2dwbG90KGFlcyh4PWxvZ0ZDLCB5PS1sb2cxMChwLmFkaiksIGNvbG9yPUZEUikpICsKICAgZ2VvbV9wb2ludChhbHBoYT0wLjcsc2l6ZT0uNSwgc2hhcGU9MTYpICsKICAgdGhlbWVfbWluaW1hbCgpICsKICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGEgPSAuICU+JSBmaWx0ZXIoRkRSID09VFJVRSwgYWJzKGxvZ0ZDKSA+MS41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IEFzc2F5KSwgY29sb3I9ImJsYWNrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlICAgICAgICA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJib3RoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuYWxwaGE9LjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gdW5pdCgwLjIsICJsaW5lcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9pbnQucGFkZGluZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnZ3JleTUwJykgKwogICAKICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMSwgMSksIGxpbmV0eXBlID0gImRvdHRlZCIsIGxpbmV3aWR0aCA9IC41KSArCiAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjAxKSwgbGluZXR5cGUgPSAiZG90dGVkIiwgbGluZXdpZHRoID0gLjUpICsgCiAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygtNC4wLC0zLjAsLTIuMCwtMS4wLDAuMCwxLjAsMi4wLDMuMCw0LjAsNS4wLDYuMCksbGltaXRzID0gYygtNCw2KSkgKwogICAKICAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMS4xLCB5ID0gMjEsIHhlbmQgPSA0LCB5ZW5kID0gMjEpLCBjb2xvcj10aW1lM19jb2xbWzFdXSwgI3k9MTYuNQogICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpKSArCiAgIGFubm90YXRlKCJ0ZXh0Iix4PTIuNiwgeT0yMi41LCBzaXplPTIsIGxhYmVsPSJIaWdoIGFidW5kYW50XG5pbiBhY3V0ZSBtYWxhcmlhIikgKyAjeT0xNy42CiAgIAogICBnZW9tX3NlZ21lbnQoYWVzKHggPSAtMS4xLCB5ID0gMjEsIHhlbmQgPSAtNCwgeWVuZCA9IDIxKSxjb2xvcj10aW1lM19jb2xbWzFdXSwKICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSkgKwogICBhbm5vdGF0ZSgidGV4dCIseD0tMi42LCB5PTIyLjUsIHNpemU9MiwgbGFiZWw9IkxvdyBhYnVuZGFudFxuaW4gYWN1dGUgbWFsYXJpYSIpICsgI3k9MTcuMQogICAKICAgbGFicyh4PSJFc3RpbWF0ZWQgZGlmZmVyZW5jZSAoTlBYKSBhdCBhY3V0ZSBjb21wYXJlZCB0byBjb252YWxlc2NlbmNlIiwKICAgICAgICB5PSItbG9nMTAoYWRqLiBwLXZhbHVlKSIpICsKICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NikpICsKICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYyh0aW1lM19jb2xbWzNdXSx0aW1lM19jb2xbWzFdXSkpKQpgYGAKCgoKIyMgRmlndXJlIDFHCmBgYHtyfQpobS5pbnB1dCA8LSBkYXRhLndpZGUgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlICU+JSBkcGx5cjo6c2VsZWN0KERBaWQsc3R1ZHlfaWQsIHNhbXBsZV9pZCwgVGltZSksYnk9InNhbXBsZV9pZCIpICU+JSAKICBkcGx5cjo6ZmlsdGVyKFRpbWU9PSJBY3V0ZSIpCgp0b3AyNSA8LSBkYXAucmVzICU+JSAKICBkcGx5cjo6ZmlsdGVyKEZEUj09VFJVRSkgJT4lCiAgYXJyYW5nZShkZXNjKGFicyhsb2dGQykpLGRlc2MocC5hZGopKSAlPiUKICBtdXRhdGUodXBfZG93biA9IGlmZWxzZShsb2dGQz4wLCJ1cCIsImRvd24iKSkgJT4lIAogIGRwbHlyOjpncm91cF9ieSh1cF9kb3duKSAlPiUgCiAgc2xpY2VfaGVhZChuPTI1KQoKdG9wMjUuc3BsaXQgPC0gdG9wMjUgJT4lIGNvbHVtbl90b19yb3duYW1lcygiQXNzYXkiKSAlPiUgCiAgdHJhbnNtdXRlKGRpcmVjdGlvbiA9IGZhY3RvcihkaXJlY3Rpb24sIGxldmVscyA9IGMoInVwIiwiZG93biIpLCBsYWJlbHMgPSBjKCJoaWdoIiwibG93IikpKQoKbm9ybS5kZiA8LSBobS5pbnB1dCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtYyhEQWlkLFRpbWUsc3R1ZHlfaWQpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjKHRvcDI1JEFzc2F5KSkgJT4lIAogIHQoKSAlPiUgc2NhbGUoKQoKIyMgPT0gQ29tcGxleEhlYXRtYXAgPT0gIyMKKGFjdXRlLm5weC50b3AyNS5obSA8LSBub3JtLmRmICU+JSAKICAgIHNjYWxlKCkgJT4lIAogICAgSGVhdG1hcChuYW1lPSJzY2FsZWRcbk5QWCIsCiAgICAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29sdW1ucyA9ICJzcGVhcm1hbiIsCiAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kX2NvbHVtbnM9IndhcmQuRDIiLAogICAgICAgICAgICAKICAgICAgICAgICAgdG9wX2Fubm90YXRpb24gPSBIZWF0bWFwQW5ub3RhdGlvbihkZiA9IGRhdGEuZnJhbWUoc2FtcGxlX2lkID0gY29sbmFtZXMoLikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwYXJhdGUoc2FtcGxlX2lkLCBpbnRvID0gYygic3R1ZHlfaWQiLCJUaW1lIiksc2VwPSJcXHwiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oc3ViamVjdFRhYmxlICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zbXV0ZShzdHVkeV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRlbWljID0gZmFjdG9yKGNhc2Vfd2hlbihlbmRlbWljPT0icHJpbWFyeV9pbmZlY3RlZCJ+InByaW1hcnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZGVtaWM9PSJwcmV2aW91c2x5X2V4cG9zZWQifiJwcmV2aW91c2x5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdD1OQSksbGV2ZWxzPWMoInByaW1hcnkiLCJwcmV2aW91c2x5IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldmVyZV81ID0gaWZlbHNlKHNldmVyZV81PT0xLCJ5ZXMiLCJubyIpKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KC1zdHVkeV9pZCwtVGltZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoMiwgIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19hbm5vdGF0aW9uX25hbWUgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCgzLCAibW0iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KDMsICJtbSIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2xlZ2VuZCA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sYWJlbCA9IGxpc3Qoc2V2ZXJlXzUgPSAiU2V2ZXJlIG1hbGFyaWFcbihXSE8pIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRlbWljID0gImV4cG9zdXJlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBsaXN0KGVuZGVtaWMgPSAgYygicHJldmlvdXNseSI9ICIjRjFBMzQwIiwicHJpbWFyeSI9ICIjOTk4RUMzIiksI2VuZGVtaWMyX2NvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V2ZXJlXzUgPSBjKCJ5ZXMiPSJ0b21hdG8iLCJubyI9ImdyZXk4MCIpKSwjc2V2ZXJlXzVfY29sKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoPSJjb2x1bW4iKSwKICAgICAgICAgICAgCiAgICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRiwKICAgICAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDgpLAogICAgICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gVFJVRSwKICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gVFJVRSwKICAgICAgICAgICAgY29sdW1uX2RlbmRfcmVvcmRlciA9IFRSVUUsCiAgICAgICAgICAgIHJvd19kZW5kX3Jlb3JkZXI9MS1yb3dTdW1zKGFicyhub3JtLmRmKSksCiAgICAgICAgICAgIGNsdXN0ZXJfcm93X3NsaWNlcyA9IEZBTFNFLAogICAgICAgICAgICByb3dfZGVuZF93aWR0aCA9IHVuaXQoMC41LCAiY20iKSwgCiAgICAgICAgICAgIGNvbHVtbl9kZW5kX2hlaWdodCA9IHVuaXQoMC41LCAiY20iKSwgCiAgICAgICAgICAgIHJhc3Rlcl9yZXNpemVfbWF0ID0gbWVhbiwKICAgICAgICAgICAgcm93X3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT02KSwKICAgICAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBUUlVFLAogICAgICAgICAgICByb3dfc3BsaXQgPSB0b3AyNS5zcGxpdCwKICAgICAgICAgICAgcm93X2dhcCA9IHVuaXQoMC4wNSwiY20iKSwKICAgICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCgzLCAibW0iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCgzLCAibW0iKSksCiAgICAgICAgICAgIGhlaWdodCA9IG5jb2woLikqdW5pdCgxLjQsICJtbSIpLAogICAgICAgICAgICB3aWR0aCA9IG5jb2woLikqdW5pdCguMTQsIm1tIikKICAgICkpCmBgYAoKIyMgRmlndXJlIDFICmBgYHtyfQp0b3AxMHVwIDwtIGRhcC5yZXMgJT4lIGRwbHlyOjpmaWx0ZXIoRkRSPT1UUlVFKSAlPiUKICBhcnJhbmdlKGRlc2MoYWJzKGxvZ0ZDKSksZGVzYyhwLmFkaikpICU+JQogIG11dGF0ZSh1cF9kb3duID0gaWZlbHNlKGxvZ0ZDPjAsInVwIiwiZG93biIpKSAlPiUgCiAgZmlsdGVyKHVwX2Rvd249PSJ1cCIpICU+JSAKICBoZWFkKG49MTApICU+JQogIHB1bGwoQXNzYXkpCgoodmlvbGluX21hbGFyaWFfdG9wMTAgPC0gZGF0YS5sb25nICU+JSAKICAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIGRwbHlyOjpzZWxlY3QoREFpZCxUaW1lLHNhbXBsZV9pZCxzdHVkeV9pZCksCiAgICAgICAgICAgICAgYnk9InNhbXBsZV9pZCIpICU+JSAKICAgZHBseXI6OmZpbHRlcihBc3NheSAlaW4lIGModG9wMTB1cCkpICU+JSAKICAgbXV0YXRlKEFzc2F5ID0gZmFjdG9yKEFzc2F5LCBsZXZlbHMgPSB0b3AxMHVwKSkgJT4lIAogICAKICAgZ2dwbG90KGFlcyh4PVRpbWUsIHk9TlBYLCBjb2xvcj1UaW1lLGZpbGw9VGltZSkpICsgCiAgIGdlb21fbGluZShhZXMoZ3JvdXA9c3R1ZHlfaWQpLCBjb2xvcj0iZ3JleSIsYWxwaGE9LjYsc2l6ZT0uMikrCiAgIGdlb21fdmlvbGluKHRyaW0gPSBGLGFscGhhPS4yLGx3ZD0uMjUpICsKICAgZ2VvbV9ib3hwbG90KGFscGhhPTEsd2lkdGg9MC4yNSxjb2xvcj0iYmxhY2siLG91dGxpZXIuc2l6ZSA9IDAuNSwgZmF0dGVuID0gMSxsd2Q9LjI1LHNob3cubGVnZW5kID0gRikgKwogICBmYWNldF93cmFwKH5Bc3NheSxuY29sID0gNSxzY2FsZXMgPSAiZnJlZV95IikgKwogICB0aGVtZV9taW5pbWFsKCkgKwogICBsYWJzKHg9IiIpICsKICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dGltZTNfY29sKSArCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz10aW1lM19jb2wpKQpgYGAKCiMjIEZpZ3VyZSAxSQpgYGB7cn0KdG9wMTBkb3duIDwtIGRhcC5yZXMgJT4lIGRwbHlyOjpmaWx0ZXIoRkRSPT1UUlVFKSAlPiUKICBhcnJhbmdlKGRlc2MoYWJzKGxvZ0ZDKSksZGVzYyhwLmFkaikpICU+JQogIG11dGF0ZSh1cF9kb3duID0gaWZlbHNlKGxvZ0ZDPjAsInVwIiwiZG93biIpKSAlPiUgCiAgZmlsdGVyKHVwX2Rvd249PSJkb3duIikgJT4lIAogIGhlYWQobj0xMCkgJT4lCiAgcHVsbChBc3NheSkKCih2aW9saW5fbWFsYXJpYV90b3AxMF9kb3duIDwtIGRhdGEubG9uZyAlPiUgCiAgIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlICU+JSBkcGx5cjo6c2VsZWN0KERBaWQsVGltZSxzYW1wbGVfaWQsc3R1ZHlfaWQpLAogICAgICAgICAgICAgIGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgIGRwbHlyOjpmaWx0ZXIoQXNzYXkgJWluJSBjKHRvcDEwZG93bikpICU+JSAKICAgbXV0YXRlKEFzc2F5ID0gZmFjdG9yKEFzc2F5LCBsZXZlbHMgPSB0b3AxMGRvd24pKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9VGltZSwgeT1OUFgsIGNvbG9yPVRpbWUsZmlsbD1UaW1lKSkgKyAKICAgIGdlb21fbGluZShhZXMoZ3JvdXA9c3R1ZHlfaWQpLCBjb2xvcj0iZ3JleSIsYWxwaGE9LjYsc2l6ZT0uMikrCiAgICBnZW9tX3Zpb2xpbih0cmltID0gRixhbHBoYT0uMixsd2Q9LjI1KSArCiAgICBnZW9tX2JveHBsb3QoYWxwaGE9MSx3aWR0aD0wLjI1LGNvbG9yPSJibGFjayIsb3V0bGllci5zaXplID0gMC41LCBmYXR0ZW4gPSAxLGx3ZD0uMjUsc2hvdy5sZWdlbmQgPSBGKSArCiAgICBmYWNldF93cmFwKH5Bc3NheSxuY29sID0gNSxzY2FsZXMgPSAiZnJlZV95IikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoeD0iIikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz10aW1lM19jb2wpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz10aW1lM19jb2wpKQpgYGAKCiMjIFN1cHBsZW1lbnRhcnkgVGFibGUgUzEgCmBgYHtyfQojI2d0c3VtbWFyeQpsaWJyYXJ5KGd0c3VtbWFyeSkKc3ViamVjdFRhYmxlICU+JSAKICBtdXRhdGUoeWVhcnNfc2luY2VfZW5kZW1pYyA9IGNhc2Vfd2hlbihlbmRlbWljPT0icHJpbWFyeSJ+TkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSB5ZWFyc19zaW5jZV9lbmRlbWljKSwKICAgICAgICAgCiAgICAgICAgIFNPRkFfdG90YWwgPSBhcy5udW1lcmljKFNPRkFfdG90YWwpLAogICAgICAgICBlbmRlbWljID0gc3RyX3JlcGxhY2UoZW5kZW1pYywiXyIsIiAiKSwKICAgICAgICAgc2V2ZXJlXzUgPSBjYXNlX3doZW4oc2V2ZXJlXzU9PTEgfiAic2V2ZXJlIiwuZGVmYXVsdCA9ICJub24tc2V2ZXJlIikpICU+JSAKICB0Ymxfc3VtbWFyeShpbmNsdWRlID0gYyhzZXgsIGFnZSwgZW5kZW1pYywgeWVhcnNfc2luY2VfZW5kZW1pYywgZGlmZl9hY3V0ZVNhbXBsZV9zcHRfY3VycmVudC5hYnMsIGluZl9yYmNfbWF4LCBzZXZlcmVfNSxTT0ZBX3RvdGFsKSwKICAgICAgICAgICAgICAKICAgICAgICAgICAgICBzdGF0aXN0aWMgPSBsaXN0KGFsbF9jb250aW51b3VzKCkgfiAie21lZGlhbn0gKHttaW59LXttYXh9KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gLyB7Tn0gKHtwfSUpIgogICAgICAgICAgICAgICksCiAgICAgICAgICAgICAjIGRpZ2l0cyA9IGFsbF9jb250aW51b3VzKCkgfiAyLAogICAgICAgICAgICAgZGlnaXRzID0gYyhhZ2UgfiAwLAogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19zaW5jZV9lbmRlbWljIH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgZGlmZl9hY3V0ZVNhbXBsZV9zcHRfY3VycmVudC5hYnMgfiAwLAogICAgICAgICAgICAgICAgICAgICAgICBpbmZfcmJjX21heCB+IDIpLAogICAgICAgICAgICAgIGxhYmVsID0gYyhlbmRlbWljIH4gIlByZXZpb3VzIG1hbGFyaWEgZXhwb3N1cmUiLAogICAgICAgICAgICAgICAgICAgICAgICBhZ2UgfiAiQWdlIiwKICAgICAgICAgICAgICAgICAgICAgICAgc2V4IH4iU2V4IiwKICAgICAgICAgICAgICAgICAgICAgICAgeWVhcnNfc2luY2VfZW5kZW1pYyB+ICJZZWFycyBzaW5jZSBsaXZpbmcgaW4gZW5kZW1pYyBhcmVhIiwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mX3JiY19tYXggfiAiUGFyYXNpdGVtaWEgWyVdIiwKICAgICAgICAgICAgICAgICAgICAgICAgU09GQV90b3RhbCB+ICJTT0ZBIHNjYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgZGlmZl9hY3V0ZVNhbXBsZV9zcHRfY3VycmVudC5hYnMgfiAiRGF5cyBzaW5jZSBzeW1wdG9tIG9uc2V0IiwKICAgICAgICAgICAgICAgICAgICAgICAgc2V2ZXJlXzUgPSAiU2V2ZXJlIG1hbGFyaWEgYWNjb3JkaW5nIHRvIFdITyBjcml0ZXJpYVxuKHJlZiBXSE8gR3VpZGVsaW5lcyBmb3IgdGhlIHRyZWF0bWVudCBvZiBNYWxhcmlhICwgM3JkIGVkaXRpb24sIDIwMTUpIiksCiAgICAgICAgICAgICAgbWlzc2luZyA9ICJubyIKICApICU+JSAKICBhZGRfbigpICU+JSAjIGFkZCBjb2x1bW4gd2l0aCB0b3RhbCBudW1iZXIgb2Ygbm9uLW1pc3Npbmcgb2JzZXJ2YXRpb25zCiAgbW9kaWZ5X2hlYWRlcihsYWJlbCA9ICIqKlZhcmlhYmxlKioiKSAlPiUgIyB1cGRhdGUgdGhlIGNvbHVtbiBoZWFkZXIKICBib2xkX2xhYmVscygpIApgYGAKCiMjIFN1cHBsZW1lbnRhcnkgVGFibGUgUzIKCmBgYHtyfQpkYXBzLm91dCA8LSBsbWVfcmVzX3BhZGogJT4lIAogIHRyYW5zbXV0ZShVbmlQcm90LCAKICAgICAgICAgICAgQXNzYXksCiAgICAgICAgICAgIGVzdGltYXRlLAogICAgICAgICAgICBjb250cmFzdCwgCiAgICAgICAgICAgIFNFLAogICAgICAgICAgICBDSSA9IDEuOTYqU0UsCiAgICAgICAgICAgIGRmLAogICAgICAgICAgICB0LnJhdGlvLAogICAgICAgICAgICBwLnZhbHVlLCAKICAgICAgICAgICAgcC5hZGosCiAgICAgICAgICAgIHByZWZlcnJlZF9tb2RlbCA9IGNhc2Vfd2hlbihBc3NheSAlaW4lIGFzc2F5X2JldHRlcl9jb21wbGV4X21vZGVsIH4gImNvbXBsZXgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSAic2ltcGxlIikpCiNkYXBzLm91dCU+JSAgd3JpdGVfdHN2KHBhc3RlMChyZXN1bHQuZGlyLCJTdXBwbGVtZW50YXJ5X1RhYmxlUzJfRGlmZmVyZW50aWFsbHlBYnVuZGFudFByb3RlaW5zLnRzdiIpKQpkYXBzLm91dCAjJT4lIGhlYWQoKQpgYGAKYGBge3J9CmRhcHMub3V0ICU+JSBmaWx0ZXIocC5hZGogPD0wLjAxLCBwcmVmZXJyZWRfbW9kZWw9PSJzaW1wbGUiLCBlc3RpbWF0ZTw9LTEpCmBgYAoKCmNvbXAjIyBTdXBwbGVtZW50YXJ5IEZpZ3VyZSAxCiMjIyBGaWd1cmUgUzFBCgpgYGB7cn0KdG1wIDwtIGRhdGEubG9uZyAlPiUgCiAgZGlzdGluY3Qoc2FtcGxlX2lkKSAKaG1fbWF0IDwtIHRtcCAlPiUgCiAgc2VwYXJhdGUoc2FtcGxlX2lkLCBpbnRvID0gYygic3R1ZHlfaWQiLCJUaW1lIiksc2VwID0gIlxcfCIscmVtb3ZlID0gVCkgJT4lIAogICBtdXRhdGUoVGltZSA9IGZhY3RvcihUaW1lLCBsZXZlbHM9YygiQWN1dGUiLCJEMTAiLCJNMTIiKSksCiAgICAgICAgICBkdW1teSA9IFRpbWUpICU+JSAKICAKICBncm91cF9ieShzdHVkeV9pZCkgJT4lIAogIG11dGF0ZShuID0gbigpKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFRpbWUsIHZhbHVlc19mcm9tID0gZHVtbXkpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1uKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpICU+JSAKICByZWxvY2F0ZShBY3V0ZSxEMTAsTTEyKSAlPiUgCiAgdCgpIAoKKHNhbXBsZV9vdmVybGFwX2htIDwtIGhtX21hdCAlPiUgCiAgSGVhdG1hcChyb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGLAogICAgICAgICAgbmFfY29sID0gIndoaXRlIiwKICAgICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICByb3dfbmFtZXNfc2lkZSA9ICJsZWZ0IiwKICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICBjb2x1bW5fbmFtZXNfcm90ID0gNDUsCiAgICAgICAgICBzaG93X2hlYXRtYXBfbGVnZW5kID0gRiwKICAgICAgICAgIGNvbHVtbl9zcGxpdCA9IGRhdGEuZnJhbWUoc3R1ZHlfaWQgPSBjb2xuYW1lcyhobV9tYXQpKSAlPiUgCiAgICAgICAgICAgIGxlZnRfam9pbihzdWJqZWN0VGFibGUgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICB0cmFuc211dGUoc3R1ZHlfaWQsIGVuZGVtaWMpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKAogICAgICAgICAgICAgICAgICAgICAgICAgIHRpYmJsZShzdHVkeV9pZCA9IGMoIjIwMTQwMDMiLCIyMDEyUFQxMiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRlbWljID0gYygicHJpbWFyeV9pbmZlY3RlZCIsInByaW1hcnlfaW5mZWN0ZWQiKSkpKSAlPiUgIAogICAgICAgICAgICB0cmFuc211dGUoZW5kZW1pYz0gZmFjdG9yKGVuZGVtaWMsIGxldmVscz1jKCJwcmltYXJ5X2luZmVjdGVkIiwicHJldmlvdXNseV9leHBvc2VkIiksIGxhYmVscz0gYygicHJpbWFyeSBpbmZlY3RlZCIsInByZXZpb3VzbHkgZXhwb3NlZCIpKSksCiAgICAgICAgICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgCiAgICAgICAgICByZWN0X2dwID0gZ3Bhcihjb2wgPSAid2hpdGUiLCBsd2QgPSAuNSksCiAgICAgICAgICB3aWR0aCA9IG5jb2woLikqdW5pdCgxLCAibW0iKSwgCiAgICAgICAgICBoZWlnaHQgPSBucm93KC4pKnVuaXQoMiwgIm1tIiksCiAgICAgICAgICAjaGVpZ2h0ID0gbmNvbCguKSp1bml0KDEuNCwgIm1tIiksCiAgICAgICAgICAjICB3aWR0aCA9IG5jb2woLikqdW5pdCguNSwibW0iKSwKICAgICAgICAgIGJvcmRlcl9ncCA9IGdwYXIoY29sID0gImJsYWNrIiwgbHR5ID0gLjkpLAogICAgICAgICAgY29sID0gIHRpbWUzX2NvbCwKICAgICAgICAgIHRvcF9hbm5vdGF0aW9uID0gSGVhdG1hcEFubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKHN0dWR5X2lkID0gY29sbmFtZXMoLikpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oc3ViamVjdFRhYmxlICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc211dGUoc3R1ZHlfaWQsIGVuZGVtaWMpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWJibGUoc3R1ZHlfaWQgPSBjKCIyMDE0MDAzIiwiMjAxMlBUMTIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRlbWljID0gYygicHJpbWFyeV9pbmZlY3RlZCIsInByaW1hcnlfaW5mZWN0ZWQiKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KC1zdHVkeV9pZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDMsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2Fubm90YXRpb25fbmFtZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChlbmRlbWljID0gIGVuZGVtaWMyX2NvbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoPSJjb2x1bW4iKSkKKQoKYGBgCgojIyMgRmlndXJlIFMxQgoKYGBge3J9CihhY3V0ZV9leHBvc3VyZV92b2xjYW5vIDwtIGxtZV9yZXMgJT4lIAogIHVubmVzdChjb2xzPXBvc3Rob2MudGltZV9leHBvc3VyZSkgJT4lIAogIGZpbHRlcihjb250cmFzdCAlaW4lYygiQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIE0xMiBwcmltYXJ5X2luZmVjdGVkIiwKICAgICAgICAgICAgICAgICAgICAiQWN1dGUgcHJldmlvdXNseV9leHBvc2VkIC0gTTEyIHByZXZpb3VzbHlfZXhwb3NlZCIpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShjb250cmFzdCkgJT4lIAogIG11dGF0ZShwLmFkaiA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIiksCiAgICAgICAgIEZEUiA9IGlmZWxzZShwLmFkaiA8PSAwLjAxLCBUUlVFLEZBTFNFKSkgJT4lIAogIGFycmFuZ2UocC5hZGopICU+JSAKICB0cmFuc211dGUoQXNzYXksY29udHJhc3QsIGVzdGltYXRlLFNFLGRmLHQucmF0aW8sIHAudmFsdWUsIHAuYWRqLCBGRFIsCiAgICAgICAgICAgIGNvbG9yID0gY2FzZV93aGVuKEZEUj09VCAmIGNvbnRyYXN0PT0iQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIE0xMiBwcmltYXJ5X2luZmVjdGVkIiB+ICJwcmltYXJ5X2luZmVjdGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRkRSPT1UICYgY29udHJhc3Q9PSJBY3V0ZSBwcmV2aW91c2x5X2V4cG9zZWQgLSBNMTIgcHJldmlvdXNseV9leHBvc2VkIiB+ICJwcmV2aW91c2x5X2V4cG9zZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIGNvbnRyYXN0ID0gZmFjdG9yKGNvbnRyYXN0LCBsZXZlbHM9YygiQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIE0xMiBwcmltYXJ5X2luZmVjdGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY3V0ZSBwcmV2aW91c2x5X2V4cG9zZWQgLSBNMTIgcHJldmlvdXNseV9leHBvc2VkIikpLAogICAgICAgICAgICBsYWJlbF80X2NvbXBsZXhfYmV0dGVyID0gY2FzZV93aGVuKEFzc2F5ICVpbiUgYXNzYXlfYmV0dGVyX2NvbXBsZXhfbW9kZWwgJiBjb250cmFzdD09IkFjdXRlIHByaW1hcnlfaW5mZWN0ZWQgLSBNMTIgcHJpbWFyeV9pbmZlY3RlZCIgfiBBc3NheSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKSkgJT4lIAogIAogIGdncGxvdChhZXMoeT1mY3RfcmVvcmRlcihBc3NheSwgZXN0aW1hdGUpLCB4PWVzdGltYXRlLCBjb2xvcj1jb2xvcikpICsKIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9ZW5kZW1pYzJfY29sLCBuYS52YWx1ZSA9ICJncmV5IixicmVha3MgPSBjKCJwcmltYXJ5X2luZmVjdGVkIiwicHJldmlvdXNseV9leHBvc2VkIikpICsKICBsYWJzKGNvbG9yPU5VTEwsCiAgICAgICB4PSJFc3RpbWF0ZWQgZGlmZmVyZW5jZSArLSA5NSUgQ0kgYXQgYWN1dGUgZm9yXG5wcmltYXJ5IGluZmVjdGVkIGFuZCBwcmV2aW91c2x5IGV4cG9zZWQgaW5kaXZpZHVhbHNcbmNvbXBhcmVkIHRvIE0xMiIsIyJFc3RpbWF0ZWQgZGlmZmVyZW5jZSAoTlBYKSBhdCBhY3V0ZSBjb21wYXJlZCB0byBoZWFsdGh5LXN0YXRlIGF0IE0xMiIsCiAgICAgICB5PSJyYW5rZWQgcHJvdGVpbnMiKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj1lc3RpbWF0ZSAtIDEuOTYqU0UsIAogICAgICAgICAgICAgICAgICAgIHhtYXg9ZXN0aW1hdGUgKyAxLjk2KlNFKSwKICAgICAgICAgICAgICAgIGxpbmV3aWR0aD0uMiwgICAgIyBUaGlubmVyIGxpbmVzCiAgICAgICAgICAgICAgICB3aWR0aD0uMiwKICAgICAgICAgICAgICAgIGFscGhhPS4xKSArCiAgICBnZW9tX3BvaW50KGFscGhhPTAuNyxzaXplPS41LCBzaGFwZT0xNikgKwogICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWxhYmVsXzRfY29tcGxleF9iZXR0ZXIpLAogICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRiwKICAgICAgICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsCiAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAuNSwKICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEsCiAgICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IC43NSwKICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAieSIsCiAgICAgICAgICAgICAgICAgICAgc2l6ZT0xLAogICAgICAgICAgICAgICAgICAgI2xhYmVsLnNpemUgPSAuMSwKICAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LmFscGhhPS4xLAogICAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IDE2KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5PTIsIGFscGhhPS42KSArCiAgdGhlbWVfbWluaW1hbCgpKQpgYGAKCgpgYGB7cn0KbG1lX3Jlc19leHBvIDwtIGxtZV9yZXMgJT4lIAogIHVubmVzdChjb2xzPSJwb3N0aG9jLnRpbWVfZXhwb3N1cmUiKSAlPiUgCiAgZmlsdGVyKGNvbnRyYXN0PT0iQWN1dGUgcHJpbWFyeV9pbmZlY3RlZCAtIEFjdXRlIHByZXZpb3VzbHlfZXhwb3NlZCIpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShwLmFkaiA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIiksCiAgICAgICAgICAgICAgICAgIEZEUiA9IGlmZWxzZShwLmFkaiA8PSAwLjAxLCBUUlVFLEZBTFNFKSkgJT4lIAogIGZpbHRlcihGRFI9PVQpICU+JSAKICBhcnJhbmdlKC1lc3RpbWF0ZSkgCgphc3NheXNfc2lnbmlmaWNhbnRfZGlmZmVyZW50X2F0X2FjdXRlX2V4cCA8LSBsbWVfcmVzX2V4cG8gJT4lIAogIHB1bGwoQXNzYXkpCmBgYAoKIyMjIEZpZ3VyZSBTMUMKCmBgYHtyfQpsaWJyYXJ5KGV1bGVycikKCnBsb3QoZXVsZXIobGlzdCgiYWN1dGUiID0gbG1lX3Jlc19wYWRqICU+JSBmaWx0ZXIoRkRSPT1UKSAlPiUgcHVsbChBc3NheSksCiAgICAgICAgICAgICAgICAgICJleHBvc3VyZSI9IGxtZV9yZXNfZXhwbyAlPiUgZmlsdGVyKEZEUj09VCkgJT4lIHB1bGwoQXNzYXkpKSksIyBhc3NheXNfc2lnbmlmaWNhbnRfZGlmZmVyZW50X2F0X2FjdXRlX2V4cCkpLCNsbWVfcmVzX2V4cG8gJT4lIGZpbHRlcihGRFI9PVQpICU+JSBwdWxsKEFzc2F5KSkpLAogICAgICAgIGZpbGxzID0gYygiI0M1MUI3RCIsCiAgICAgICAgICAgICAgICAgICJ3aGl0ZSIpLAogICAgICAgcXVhbnRpdGllcyA9IFRSVUUsCiAgICAgICBsdHkgPSAxLCMxOjMsCiAgICAgICBmb250c2l6ZT0xLAogICAgICAgbGFiZWxzID0gbGlzdChmb250c2l6ZT01KSwKICAgICAgIHNoYXBlID0gImVsbGlwc2UiLGFkanVzdF9sYWJlbHMgPSBUKQoKYWN1dF9leHBvc3VyZV9pbnRlcnNlY3QgPC0gaW50ZXJzZWN0KGFzc2F5c19zaWduaWZpY2FudF9kaWZmZXJlbnRfYXRfYWN1dGVfZXhwLCNsbWVfcmVzX2V4cG8gJT4lIGZpbHRlcihGRFI9PVQpICU+JSBwdWxsKEFzc2F5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxtZV9yZXNfcGFkaiAlPiUgZmlsdGVyKEZEUj09VCkgJT4lIHB1bGwoQXNzYXkpKQpgYGAKCiMjIyBGaWd1cmUgUzFECgpgYGB7cn0KZGYgPC0gbG1lX3JlcyAlPiUgCiAgZmlsdGVyKEFzc2F5ICVpbiUgYXNzYXlzX3NpZ25pZmljYW50X2RpZmZlcmVudF9hdF9hY3V0ZV9leHApICU+JSAKICBtdXRhdGUoQXNzYXkgPSBmYWN0b3IoQXNzYXksIGxldmVscz1hc3NheXNfc2lnbmlmaWNhbnRfZGlmZmVyZW50X2F0X2FjdXRlX2V4cCkpICU+JSAKICB1bm5lc3QoY29scz1wb3N0aG9jLnRpbWVfZXhwb3N1cmUpICU+JSAKICBmaWx0ZXIoY29udHJhc3QgJWluJWMoIkFjdXRlIHByaW1hcnlfaW5mZWN0ZWQgLSBNMTIgcHJpbWFyeV9pbmZlY3RlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICJBY3V0ZSBwcmV2aW91c2x5X2V4cG9zZWQgLSBNMTIgcHJldmlvdXNseV9leHBvc2VkIikpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShjb2xvciA9IGNhc2Vfd2hlbihjb250cmFzdD09IkFjdXRlIHByaW1hcnlfaW5mZWN0ZWQgLSBNMTIgcHJpbWFyeV9pbmZlY3RlZCIgfiAicHJpbWFyeV9pbmZlY3RlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0PT0iQWN1dGUgcHJldmlvdXNseV9leHBvc2VkIC0gTTEyIHByZXZpb3VzbHlfZXhwb3NlZCIgfiAicHJldmlvdXNseV9leHBvc2VkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUKICMgcm93bmFtZXNfdG9fY29sdW1uKCJyb3dudW1iZXJzIikgJT4lIAogICNmaWx0ZXIoQXNzYXklaW4lYygiQ1hDTDEwIiwiSUZORyIsIkNYQ0w5IiwiVE5GU0YxM0IiKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLShsbWUucmVzLnNpbXBsZTpwb3N0aG9jLnRpbWUpKSAKcmVxdWlyZShnZ3RleHQpCihhY3V0ZV9leHBvc3VyZV9zaWduaWZpY2FudCA8LSBkZiAlPiUgCiAgICBtdXRhdGUoeC5sYWJlbCA9IHBhc3RlKCI8c3BhbiBzdHlsZSA9ICdjb2xvcjogIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShBc3NheSAlaW4lIGFjdXRfZXhwb3N1cmVfaW50ZXJzZWN0ICwgInBpbmsiLCAiYmxhY2siKSwKICAgICAgICAgICAgICAgICAgICAgICAgICI7Jz4iLAogICAgICAgICAgICAgICAgICAgICAgICAgQXNzYXksCiAgICAgICAgICAgICAgICAgICAgICAgICAiPC9zcGFuPiIsIHNlcCA9ICIiKSwKICAgICAgICAgeC5sYWJlbCA9IGZjdF9yZW9yZGVyKHgubGFiZWwsIGFzLmNoYXJhY3RlcihBc3NheSkpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eC5sYWJlbCwgeT1lc3RpbWF0ZSwgY29sb3I9Y29sb3IpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xNixzaXplPS41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVuZGVtaWMyX2NvbCwgYnJlYWtzID0gYygicHJpbWFyeV9pbmZlY3RlZCIsInByZXZpb3VzbHlfZXhwb3NlZCIpKSArCgogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGx0eT0yLCBhbHBoYT0uMykgKwogIyAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKHNob3cubGVnZW5kID0gRiwgY29sb3I9ImJsYWNrIikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49ZXN0aW1hdGUgLSAxLjk2KlNFLCAKICAgICAgICAgICAgICAgICAgICB5bWF4PWVzdGltYXRlICsgMS45NipTRSksCiAgICAgICAgICAgICAgICBsaW5ld2lkdGg9LjIsICAgICMgVGhpbm5lciBsaW5lcwogICAgICAgICAgICAgICAgd2lkdGg9LjIsCiAgICAgICAgICAgICAgICBhbHBoYT0uNSkgKwogIGxhYnMoeD1OVUxMLAogICAgICAgY29sb3IgPSBOVUxMLAogICAgICAgeT0iRXN0aW1hdGVkIGRpZmZlcmVuY2UgKy0gOTUlIENJIGF0IGFjdXRlIGZvclxucHJpbWFyeSBpbmZlY3RlZCBhbmQgcHJldmlvdXNseSBleHBvc2VkIGluZGl2aWR1YWxzXG5jb21wYXJlZCB0byBNMTJcbiIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKGFuZ2xlID0gOTAsIGhqdXN0ID0gMSx2anVzdD0wLjUsIHNpemU9NiksCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQopCmBgYAoKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXJlIDIKCioqcmVsYXRlZCB0byBtYWluIEZpZ3VyZSAyKioKCiMjIyBGaWd1cmUgUzJBCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKc3VwcGxlbWVudGFyeV9jb3ZhcmlhdGVzLnJlcyA8LSBkYXRhLmxvbmcgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIGlubmVyX2pvaW4oc3ViamVjdFRhYmxlLCBieT0ic3R1ZHlfaWQiKSAlPiUgCiAgZmlsdGVyKFRpbWUgIT0gIkQxMCIpICU+JSAKICBtdXRhdGUoVGltZSA9IGZhY3RvcihUaW1lLCBsZXZlbHM9YygiQWN1dGUiLCJNMTIiKSkpICU+JSAKICBncm91cF9ieShBc3NheSkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKGxtZS5yZXMgPSBwdXJycjo6bWFwKGRhdGEsIH4gbG1lclRlc3Q6OmxtZXIoTlBYIH4gVGltZSArIHllYXJfaW5jbHVzaW9uICsgc2V4ICsgYWdlICsgZW5kZW1pYyArIGluZl9yYmNfbWF4ICsgKDF8c3R1ZHlfaWQpLCBSRU1MID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAuKSksCiAgICAgICAgIGxtZS50aWR5ID0gcHVycnI6Om1hcChsbWUucmVzLCB+IGJyb29tLm1peGVkOjp0aWR5KC4pKSkKCnN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXNfIDwtIHN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXMgJT4lIAogIHVubmVzdChjb2xzID0gbG1lLnRpZHkpICU+JSAKICBmaWx0ZXIoZWZmZWN0ID09ImZpeGVkIiwgCiAgICAgICAgIHRlcm0hPSIoSW50ZXJjZXB0KSIpICU+JSAKICAjZmlsdGVyKHRlcm0gIT0gIlJlc2lkdWFscyIpICU+JSAKICBtdXRhdGUodGVybSA9IGNhc2Vfd2hlbih0ZXJtPT0ic2V4bWFsZSJ+InNleCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybT09ImVuZGVtaWNwcmltYXJ5X2luZmVjdGVkIn4iZW5kZW1pYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybT09IlRpbWVNMTIifiJUaW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHRlcm0pKSAlPiUgCiAgZ3JvdXBfYnkodGVybSkgJT4lIAogIG11dGF0ZShwLmFkaiA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIikKICApICU+JQogIG11dGF0ZSh0ZXJtLmNvbCA9IGNhc2Vfd2hlbihwLmFkaiA+IDAuMDEgfiBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcC5hZGogPD0gMC4wMSB+IHRlcm0pKQoKY292LmNvbG9ycyA8LSBjKCJUaW1lIiA9IHRpbWUzX2NvbFtbMV1dLHNldE5hbWVzKGJyZXdlci5wYWwoNywiRGFyazIiKVtjKDE6Myw1OjgpXSwgYygic2V4IiwiZW5kZW1pYyIsImFnZSIsInllYXJfaW5jbHVzaW9uIiwiaW5mX3JiY19tYXgiKSkpCgpjb3VudHMuZmRyIDwtIHN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXNfICU+JSAKICBmaWx0ZXIocC5hZGogPD0gMC4wMSkgJT4lIAogIGdyb3VwX2J5KHRlcm0pICU+JSAKICBjb3VudChzb3J0ID0gVCkKCihkYXRhLmFvdi5wbG90IDwtIHN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXNfICU+JSAKICAgIG11dGF0ZSh0ZXJtID0gZmFjdG9yKHRlcm0sIGxldmVscz1jb3VudHMuZmRyJHRlcm0pKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9dGVybSwgeT0gLWxvZzEwKHAuYWRqKSkpICsgCiAgICBnZW9tX2ppdHRlcihhZXMoY29sb3I9dGVybS5jb2wpLCBzaG93LmxlZ2VuZCA9IEYsc2l6ZT0uMjUsYWxwaGE9Ljcsc2hhcGU9MTYpICsKICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhPSAuICU+JSBncm91cF9ieSh0ZXJtKSAlPiUgc2xpY2VfbWF4KG49NSxvcmRlcl9ieSA9IC1sb2cxMChwLmFkaikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMobGFiZWw9QXNzYXkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYsZm9yY2UgPSAuNSwgbnVkZ2VfeSA9IC4yNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemU9MC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5hbHBoYT0uMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gMTUsIGNvbG9yPSJncmF5NDUiKSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9LWxvZzEwKDAuMDEpLCAKICAgICAgICAgICAgICAgbGluZXR5cGUgPSAzKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY292LmNvbG9ycykgKwogICAgCiAgICBnZW9tX3RleHQoZGF0YT1jb3VudHMuZmRyLGFlcyh4PXRlcm0sIHk9LTEuMiwgbGFiZWw9biwgY29sb3I9dGVybSksIHNob3cubGVnZW5kID0gRikgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygiYWdlIiA9ICJBZ2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAieWVhcl9pbmNsdXNpb24iID0gIlllYXJcbm9mXG5zYW1wbGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzZXgiID0gIlNleCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJlbmRlbWljIiA9ICJQcmV2aW91c1xuZXhwb3N1cmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW5mX3JiY19tYXgiID0gIlBhcmFzaXRlbWlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRpbWUiID0gIkluZmVjdGlvblxuKEFjdXRlIHZzIGNvbnZhbGVzY2VuY2UpIikpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHg9TlVMTCwgCiAgICAgICAgIGNvbG9yPU5VTEwpICsKICAgIHRoZW1lKCkpCmBgYAoKCgojIyMgRmlndXJlIFMyQgpgYGB7cn0KbjJzaG93IDwtIDMKKGFub3ZhLnNleC5wbG90IDwtIHN1cHBsZW1lbnRhcnlfY292YXJpYXRlcy5yZXNfICU+JQogICAgZmlsdGVyKHRlcm09PSJzZXgiKSAlPiUKICAgIGFycmFuZ2UocC5hZGopICU+JSAKICAgIGhlYWQobj1uMnNob3cpICU+JSAKICAgIHVubmVzdChjb2xzID0gZGF0YSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PVRpbWUsIHk9TlBYLCBmaWxsPWFzLmNoYXJhY3RlcihzZXgpKSkgKwogICAgZ2VvbV9ib3hwbG90KCBmYXR0ZW4gPSAxLGx3ZD0uMjUsb3V0bGllci5zaXplID0gMC41KSArCiAgICBmYWNldF93cmFwKH5Bc3NheSwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHg9TlVMTCwKICAgICAgICAgZmlsbD0iU2V4IikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gc2V4Ml9jb2wpKQoKKGFub3ZhLmVuZGVtaWMucGxvdCA8LSBzdXBwbGVtZW50YXJ5X2NvdmFyaWF0ZXMucmVzXyAlPiUKICAgIGZpbHRlcih0ZXJtPT0iZW5kZW1pYyIpICU+JQogICAgYXJyYW5nZShwLmFkaikgJT4lIAogICAgaGVhZChuPW4yc2hvdykgJT4lIAogICAgdW5uZXN0KGNvbHMgPSBkYXRhKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9VGltZSwgeT1OUFgsIGZpbGw9YXMuY2hhcmFjdGVyKGVuZGVtaWMpKSkgKwogICAgZ2VvbV9ib3hwbG90KGZhdHRlbiA9IDEsbHdkPS4yNSxvdXRsaWVyLnNpemUgPSAwLjUpICsKICAgIGZhY2V0X3dyYXAofkFzc2F5LCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoeD1OVUxMLAogICAgICAgICBmaWxsPSJQcmV2aW91cyBleHBvc3VyZSIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGVuZGVtaWMyX2NvbCkpCgooYW5vdmEueWVhcl9pbmNsdXNpb24ucGxvdCA8LSBzdXBwbGVtZW50YXJ5X2NvdmFyaWF0ZXMucmVzXyAlPiUKICAgIGZpbHRlcih0ZXJtPT0ieWVhcl9pbmNsdXNpb24iKSAlPiUgYXJyYW5nZShwLmFkaikgJT4lIAogICAgaGVhZChuPW4yc2hvdykgJT4lIAogICAgdW5uZXN0KGNvbHMgPSBkYXRhKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9YXMubnVtZXJpYyh5ZWFyX2luY2x1c2lvbikseT1OUFgsY29sb3I9VGltZSkpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0uNSkgKwogICAgZ2VvbV9zbW9vdGgobGluZXdpZHRoPTAuNCwKICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMjAxMSwyMDIxKSxicmVha3MgPSBjKDIwMTEsMjAxNiwyMDIxKSkgKyAKICAgIGZhY2V0X3dyYXAofkFzc2F5LCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoeD0iWWVhciBvZiBpbmNsdXNpb24iLAogICAgICBjb2xvcj0iU2FtcGxlIHRpbWUgcG9pbnQiKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdGltZTNfY29sKSkKCihhbm92YS5hZ2UucGxvdCA8LSBzdXBwbGVtZW50YXJ5X2NvdmFyaWF0ZXMucmVzXyAlPiUKICAgIGZpbHRlcih0ZXJtPT0iYWdlIikgJT4lIGFycmFuZ2UocC5hZGopICU+JSAKICAgIGhlYWQobj1uMnNob3cpICU+JSAKICAgIHVubmVzdChjb2xzID0gZGF0YSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PWFzLm51bWVyaWMoYWdlKSx5PU5QWCxjb2xvcj1UaW1lKSkgKwogICAgZ2VvbV9wb2ludChzaXplPS41KSArCiAgICBnZW9tX3Ntb290aChsaW5ld2lkdGg9MC40LAogICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgICBmYWNldF93cmFwKH5Bc3NheSwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHRpdGxlPSIiLAogICAgICAgICB4PSJBZ2UgKHllYXJzKSIsCiAgICAgICAgIGNvbG9yPSJTYW1wbGUgdGltZSBwb2ludCIpICsgCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdGltZTNfY29sKQopCgooYW5vdmEuaW5mX3JiY19tYXgucGxvdCA8LSBzdXBwbGVtZW50YXJ5X2NvdmFyaWF0ZXMucmVzXyAlPiUKICAgIGZpbHRlcih0ZXJtPT0iaW5mX3JiY19tYXgiKSAlPiUgYXJyYW5nZShwLmFkaikgJT4lIAogICAgaGVhZChuPW4yc2hvdykgJT4lIAogICAgdW5uZXN0KGNvbHMgPSBkYXRhKSAlPiUgCiAgICBmaWx0ZXIoVGltZT09IkFjdXRlIikgJT4lIAogICAgZ2dwbG90KGFlcyh4PWFzLm51bWVyaWMoaW5mX3JiY19tYXgpLHk9TlBYLGNvbG9yPWFzLm51bWVyaWMoaW5mX3JiY19tYXgpKSkgKwogICAgZ2VvbV9wb2ludChzaXplPS41KSArCiAgICBnZW9tX3Ntb290aChhZXMoY29sb3I9Li54Li4pLAogICAgICAgICAgICAgICAgbGluZXdpZHRoPTAuNCwKICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKwogICAgZmFjZXRfd3JhcCh+QXNzYXksIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh0aXRsZT0iIiwKICAgICAgICAgeD0iUGFyYXNpdGVtaWEsIGluZmVjdGVkIGVyeXRocm9jeXRlcyBbJV0iLAogICAgICAgICBjb2xvcj0iUGFyYXNpdGVtaWEgWyVdIikgKyAKICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iZ3JleSIsaGlnaD0iZGFya3JlZCIpCiAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0aW1lM19jb2wpCikKCihhbm92YS5wYW5lbCA8LSAoYW5vdmEuaW5mX3JiY19tYXgucGxvdCAvIAogICAgICAgICAgICAgICAgICAgYW5vdmEuZW5kZW1pYy5wbG90IC8KICAgICAgICAgICAgICAgICAgIGFub3ZhLnllYXJfaW5jbHVzaW9uLnBsb3QgLyAKICAgICAgICAgICAgICAgICAgIGFub3ZhLnNleC5wbG90LwogICAgICAgICAgICAgICAgICAgYW5vdmEuYWdlLnBsb3QpKQpgYGAKCiMjIyBGaWd1cmUgUzJDCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsbWVfcmVzLmQxMCA8LSBkYXRhX25lc3RlZCAlPiUgCiAgbXV0YXRlKGxtZS5yZXMgPSBwdXJycjo6bWFwKGRhdGEsIH4gbG1lclRlc3Q6OmxtZXIoTlBYIH4gVGltZSArIGV4cG9zdXJlICsgKDF8c3R1ZHlfaWQpLCBSRU1MID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsbWU0OjpsbWVyQ29udHJvbChjaGVjay5jb252LnNpbmd1bGFyID0gImlnbm9yZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IC54ICU+JSBkcGx5cjo6ZmlsdGVyKFRpbWUhPSJBY3V0ZSIpKSksCiAgICAgICAgIHBvc3Rob2MudGltZSA9IHB1cnJyOjptYXAobG1lLnJlcywgfiBzdW1tYXJ5KGNvbnRyYXN0KGVtbWVhbnMoLiwgfiBUaW1lKSwgbWV0aG9kID0gInBhaXJ3aXNlIikpICU+JSB0aWJibGUoKSkKICAgICAgICApCgpsbWVfcmVzLmQxMF9wYWRqIDwtIGxtZV9yZXMuZDEwICU+JSAKICB1bm5lc3QoY29scz0icG9zdGhvYy50aW1lIikgJT4lIAogIGZpbHRlcihjb250cmFzdD09IkQxMCAtIE0xMiIpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShwLmFkaiA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZD0iZmRyIiksCiAgICAgICAgIEZEUiA9IGlmZWxzZShwLmFkaiA8PSAwLjAxLCBUUlVFLEZBTFNFKSkgJT4lIAogIGFycmFuZ2UocC5hZGopCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRX0KCmFjdXRfZDEwX2xpc3QgPC0gbGlzdCgiQWN1dGUiPWMobG1lX3Jlc19wYWRqICU+JSBmaWx0ZXIoRkRSPT1UUlVFLCBlc3RpbWF0ZT4xKSAlPiUgcHVsbChBc3NheSkpLAogICAgICAgICAgICAgICAgICAgICAgIkQxMCIgPSBjKGxtZV9yZXMuZDEwX3BhZGogJT4lIGZpbHRlcihGRFI9PVRSVUUsIGVzdGltYXRlPjEpICU+JSBwdWxsKEFzc2F5KSkpCgojIyB2ZW5uIHBsb3Qgd2l0aCBvdmVybGFwcCBudW1iZXJzCih2ZW5uLkRBUC5hY3V0ZS5kMTAgPC0gZ2d2ZW5uOjpnZ3Zlbm4oYWN1dF9kMTBfbGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3BlcmNlbnRhZ2UgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxfY29sb3IgPSBhcy5jaGFyYWN0ZXIodGltZTNfY29sW2MoMSwyKV0pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJva2Vfc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXRfbmFtZV9zaXplID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0X3NpemUgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9fc2NhbGUgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfZWxlbWVudHMgPSBGKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgcGxvdC50YWcgPSBlbGVtZW50X3RleHQoc2l6ZT02KSkpCgoKYGBgCgojIyMgRmlndXJlIFMyRApgYGB7cn0KKGQxMF9tYWxhcmlhX3ZvbGNhbm8gPC0gIGxtZV9yZXMuZDEwX3BhZGogJT4lIAogICBhcnJhbmdlKHAuYWRqLCBhYnMoZXN0aW1hdGUpKSAlPiUgCiAgIGdncGxvdChhZXMoeD1lc3RpbWF0ZSwgeT0tbG9nMTAocC5hZGopLCBjb2xvcj1GRFIpKSArCiAgIGdlb21fcG9pbnQoYWxwaGE9MC43LHNpemU9LjUsIHNoYXBlPTE2KSArCiAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhID0gLiAlPiUgZmlsdGVyKEZEUiA9PVRSVUUsIGFicyhlc3RpbWF0ZSkgPjEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gQXNzYXkpLCBjb2xvcj0iYmxhY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yY2UgICAgICAgID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uICAgID0gImJvdGgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5hbHBoYT0uMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9MS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3gucGFkZGluZyA9IHVuaXQoMC4yLCAibGluZXMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2dyZXk1MCcKICAgKSArCiAgIHRoZW1lX21pbmltYWwoKSArCiAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTEsIDEpLCBsaW5ldHlwZSA9ICJkb3R0ZWQiLCBzaXplID0gLjUpICsKICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDEpLCBsaW5ldHlwZSA9ICJkb3R0ZWQiLCBzaXplID0gLjUpICsgCiAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygtMi41LC0xLjAsMC4wLDEuMCwyLjUsNS4wKSxsaW1pdHMgPSBjKC0yLjUsNSkpICsKICAgbGFicyh4PSJFc3RpbWF0ZWQgZGlmZmVyZW5jZSAoTlBYKSIsCiAgICAgICAgeT0iLWxvZzEwKGFkai4gcC12YWx1ZSkiLAogICAgICAgIHN1YnRpdGxlPSAiRDEwIGFmdGVyIGRpc2Vhc2UgdnMuIGNvbnZhbGVzY2VuY2UiLAogICAgICAgIGNhcHRpb249cGFzdGUwKCJEQVA6ICIsbG1lX3Jlcy5kMTBfcGFkaiAlPiUgZmlsdGVyKEZEUj09VFJVRSkgJT4lIG5yb3coKSwiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICJEQVAgdXA6ICIsbG1lX3Jlcy5kMTBfcGFkaiAlPiUgZmlsdGVyKEZEUj09VFJVRSxlc3RpbWF0ZT4wKSAlPiUgbnJvdygpLCJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgIkRBUCBGQz4xOiAiLGxtZV9yZXMuZDEwX3BhZGogJT4lIGZpbHRlcihGRFI9PVRSVUUsZXN0aW1hdGU+MSkgJT4lIG5yb3coKSwiXG4iKSkgKwogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSkgKwogICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKHRpbWUzX2NvbFtbM11dLHRpbWUzX2NvbFtbMl1dKSkpCmBgYAoKIyMjIEZpZ3VyZSBTMkUKYGBge3J9CihhY3V0ZV9kMTBfY29tcCA8LSBkYXAucmVzICU+JSAKICAgdW5ncm91cCgpICU+JSAKICAgYXJyYW5nZSgtbG9nRkMpICU+JSAKICAgbXV0YXRlKHJvd19pZD1yb3dfbnVtYmVyKCkpICU+JSAKICAgbXV0YXRlKEFzc2F5X29yZGVycyA9IGZhY3Rvcihhcy5mYWN0b3Iocm93X2lkKSwgbGV2ZWxzID0gcm93X2lkLCBsYWJlbHMgPSBBc3NheSksCiAgICAgICAgICBBc3NheV9vcmRlcnMgPSByb3dfaWQpICU+JSAKICAgbGVmdF9qb2luKGxtZV9yZXMuZDEwX3BhZGosIGJ5PWMoIkFzc2F5IiwiVW5pUHJvdCIpLHN1ZmZpeCA9IGMoIi5hY3V0ZSIsIi5kMTAiKSkgJT4lIAogICBtdXRhdGUoZCA9IGlmZWxzZShlc3RpbWF0ZT5sb2dGQyxULEYpLAogICAgICAgICAgZF9kYmwgPSBhYnMobG9nRkMtZXN0aW1hdGUpKSAlPiUKICAgCiAgIGdncGxvdChhZXMoeD1Bc3NheV9vcmRlcnMpKSArCiAgIGdlb21fc2VnbWVudChkYXRhID0gLiAlPiUgZmlsdGVyKHAuYWRqLmQxMDw9MC4wMSwgZXN0aW1hdGUgPjEpLCAKICAgICAgICAgICAgICAgIGFlcyhncm91cD1Bc3NheSwgeCA9IEFzc2F5X29yZGVycywgeGVuZCA9IEFzc2F5X29yZGVycyx5ZW5kID0gbG9nRkMsIHk9ZXN0aW1hdGUsIGNvbG9yPWQpLCBsd2Q9MC4xKSArCiAgIGdlb21fcG9pbnQoYWVzKHk9bG9nRkMpLCBzaXplPS4wNSwgYWxwaGE9MSwgY29sb3I9dGltZTNfY29sW1sxXV0pICsKICAgZ2VvbV9wb2ludChkYXRhID0gLiAlPiUgZmlsdGVyKHAuYWRqLmQxMCA8PTAuMDUpLCBhZXMoeT1lc3RpbWF0ZSksY29sb3I9dGltZTNfY29sW1syXV0sIHNpemU9LjA1LGFscGhhPTEpICsKICAgCiAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhID0gLiAlPiUgZmlsdGVyKHAuYWRqLmQxMDw9MC4wNSwgZXN0aW1hdGUgPjEpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoZD09VFJVRSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZV9tYXgob3JkZXJfYnkgPSBkX2RibCxuPTEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IEFzc2F5LHk9ZXN0aW1hdGUsIGNvbG9yPWQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlICAgICAgICA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJib3RoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBudWRnZV94ID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9MiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IDE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSB1bml0KDAuMSwgImxpbmVzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdibGFjaycpICsgCiAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiRkFMU0UiID0gIm5hdnkiLCJUUlVFIj0icmVkIiksIGxhYmVscz1jKCJsb3dlciBhdCBEMTAiLCJoaWdoZXIgYXQgRDEwIikpICsKICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxsaW5ldHlwZT0zLCBjb2xvcj10aW1lM19jb2xbWzNdXSkgKwogICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kPWMoLjEsMCksCiAgICAgICAgICAgICAgICAgICAgICB0cmFucyA9ICJzcXJ0IikgKyAKICAgbGFicyhjb2xvciA9IE5VTEwsCiAgICAgICAgeD0iUHJvdGVpbnMgcmFua2VkIGJ5IGVzdGltYXRlZCBkaWZmZXJlbmNlIChOUFgpXG5hdCBhY3V0ZSBtYWxhcmlhIiwKICAgICAgICB5PSJFc3RpbWF0ZWQgZGlmZmVyZW5jZSAoTlBYKSIpICsKICAgdGhlbWVfbWluaW1hbCgpICsKICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYpKSAKKQpgYGAKCgojIyBTdXBwbGVtZW50YXJ5IEZpZ3VyZSAzIAoqKnJlbGF0ZWQgdG8gbWFpbiBGaWd1cmUgMSoqCgojIyMgRmlndXJlIFMzQQpgYGB7cn0KcmVxdWlyZShjbHVzdGVyUHJvZmlsZXIpCgpsZW5ndGgodW5pcXVlKGRhdGEkVW5pUHJvdCkpICMjIDE0NjMKCmVudHJlel91bmlwcm90X25hbWVfbWFwcGluZyA8LSBjbHVzdGVyUHJvZmlsZXI6OmJpdHIodW5pcXVlKGRhdGEubG9uZyRVbmlQcm90KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbVR5cGU9IlVOSVBST1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvVHlwZT1jKCJTWU1CT0wiLCJFTlRSRVpJRCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9yZ0RiPSJvcmcuSHMuZWcuZGIiKSAlPiUgCiAgZHBseXI6OnJlbmFtZShVbmlQcm90ID0gVU5JUFJPVCwKICAgICAgICAgICAgICAgIFN5bWJvbCA9IFNZTUJPTCwKICAgICAgICAgICAgICAgIEVudHJleiA9IEVOVFJFWklEKSAKCnJhbmtzX2VudHJleiA8LSBlbnRyZXpfdW5pcHJvdF9uYW1lX21hcHBpbmcgJT4lIAogIGlubmVyX2pvaW4oZGFwLnJlcyAlPiUgdW5ncm91cCgpICU+JSBmaWx0ZXIocC5hZGo8PTAuMDEpLCBieT0iVW5pUHJvdCIpICU+JQogIGFycmFuZ2UoLWxvZ0ZDKSAlPiUKICBkcGx5cjo6c2VsZWN0KEVudHJleiwgbG9nRkMpICU+JSBkZWZyYW1lKCkKCiMjIyBLRUdHCiMjIGFsbCBleHBsb3JlIHByb3RlaW5zCnVuaXZlcnNlLnByb3RlaW5zIDwtIGRhdGEubG9uZyAlPiUgZGlzdGluY3QoQXNzYXksVW5pUHJvdCkgJT4lIGlubmVyX2pvaW4oZW50cmV6X3VuaXByb3RfbmFtZV9tYXBwaW5nLGJ5PSJVbmlQcm90IikKIyMgcHJlcCBlbnJpY2ggaW5wdXQKc2lnX3Byb3RlaW5zX2RmIDwtIGVudHJlel91bmlwcm90X25hbWVfbWFwcGluZyAlPiUgCiAgaW5uZXJfam9pbihkYXAucmVzICU+JSB1bmdyb3VwKCksIGJ5PSJVbmlQcm90IikgJT4lIGZpbHRlcihwLmFkaiA8PSAwLjAxKSAKCiMgRnJvbSBzaWduaWZpY2FudCByZXN1bHRzLCB3ZSB3YW50IHRvIGZpbHRlciBvbiBsb2cyZm9sZCBjaGFuZ2UKc2lnX3Byb3RlaW5zIDwtIHNpZ19wcm90ZWluc19kZiRsb2dGQwojIE5hbWUgdGhlIHZlY3RvcgpuYW1lcyhzaWdfcHJvdGVpbnMpIDwtIHNpZ19wcm90ZWluc19kZiRFbnRyZXoKIyBvbWl0IE5BIHZhbHVlcwpzaWdfcHJvdGVpbnMgPC0gbmEub21pdChzaWdfcHJvdGVpbnMpCiMgZmlsdGVyIG9uIG1pbiBsb2cyZm9sZCBjaGFuZ2UgKGxvZzJGb2xkQ2hhbmdlID4gMSkKc2lnX3Byb3RlaW5zIDwtIG5hbWVzKHNpZ19wcm90ZWlucylbYWJzKHNpZ19wcm90ZWlucykgPiAxXQoKCmNwX0tFR0cucmVzIDwtIGVucmljaEtFR0coCiAgc2lnX3Byb3RlaW5zLAogIG9yZ2FuaXNtID0gImhzYSIsCiAgI2tleVR5cGUgPSAiVU5JUFJPVCIsCiAgcHZhbHVlQ3V0b2ZmID0gMSwKICBwQWRqdXN0TWV0aG9kID0gIkJIIiwKICB1bml2ZXJzZSA9IHVuaXZlcnNlLnByb3RlaW5zJEVudHJleiwKICBtaW5HU1NpemUgPSAxMCwgCiAgbWF4R1NTaXplID0gNTAwLAogIHF2YWx1ZUN1dG9mZiA9IDEsCiAgdXNlX2ludGVybmFsX2RhdGEgPSBGCikKCiNkYXRhLmZyYW1lKGNwX0tFR0cucmVzKQoKCihjcC5rZWdnLmFjdXRlZmMxIDwtIGRhdGEuZnJhbWUoY3BfS0VHRy5yZXMpICU+JQogICAgc2VwYXJhdGUoR2VuZVJhdGlvLCBpbnRvPWMoImhpdCIsInRvdGFsIiksc2VwPSIvIixyZW1vdmUgPSBGLGNvbnZlcnQ9VFJVRSkgJT4lIAogICAgaGVhZCgxMCkgJT4lIAogICAgbXV0YXRlKHJhdGlvID0gaGl0L3RvdGFsKSAlPiUgCiAgICAKICAgIGdncGxvdChhZXMoeD1mY3RfcmVvcmRlcihEZXNjcmlwdGlvbiwgLXJhdGlvLC5kZXNjID0gVFJVRSksIHk9cmF0aW8pKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjA1KSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0tbG9nMTAocC5hZGp1c3QpKSkgKyNzaXplID0gMykgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1oaXQpLHNpemU9MiwgbnVkZ2VfeSA9IC4wMSkrCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjAyLDApLCB0cmFucyA9ICJwc2V1ZG9fbG9nIikgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKC0wLjAxLCAxKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02ICksCiAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBndWlkZXMoc2l6ZSA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlPVRSVUUpKSArCiAgICBsYWJzKHRpdGxlID0gIktFR0dfMjAyMV9IdW1hbiIsCiAgICAgICAgIHg9IE5VTEwsCiAgICAgICAgIHkgPSAicmF0aW8gW3Byb3RlaW4vdG90YWxdIiwKICAgICAgICAgc2l6ZT0iUHJvdGVpblxub3ZlcmxhcHAiLAogICAgICAgICBjb2xvcj1leHByZXNzaW9uKCItTG9nIlsxMF0qIihwLmFkaikiKSkKICApCmBgYAoKIyMjIEZpZ3VyZSBTM0IKYGBge3IgS0VHRy1wYXRod2F5LXdpbGNveCwgZmlnLmNhcD0iS0VHRyIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnJlcXVpcmUocGF0aHZpZXcpCgpzaWdfcHJvdGVpbnNfZGYgPC0gZW50cmV6X3VuaXByb3RfbmFtZV9tYXBwaW5nICU+JSAKICBpbm5lcl9qb2luKGRhcC5yZXMgJT4lIHVuZ3JvdXAoKSwgYnk9IlVuaVByb3QiKSAlPiUgZmlsdGVyKHAuYWRqIDw9IDAuMDEsIGFicyhsb2dGQyk+MSkgCgoKbG9nRkMgPC0gc2lnX3Byb3RlaW5zX2RmJGxvZ0ZDCm5hbWVzKGxvZ0ZDKSA8LSBzaWdfcHJvdGVpbnNfZGYkRW50cmV6CnB2Lm91dCA8LSBwYXRodmlldyhnZW5lLmRhdGEgPSBsb2dGQywgCiAgICAgICAgICAgICAgICAgICBwYXRod2F5LmlkID0gImhzYTA0MDYwIiwgCiAgICAgICAgICAgICAgICAgICBzcGVjaWVzID0gImhzYSIsIAogICAgICAgICAgICAgICAgICAgbGltaXQgPSBsaXN0KGdlbmU9NSwgY3BkPTEpLAopCgprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHNhMDQwNjAucGF0aHZpZXcucG5nIikKCmBgYAoKCiMgRmlndXJlIDIKKipQb3RlbnRpYWwgc291cmNlcyBhbmQgZnVuY3Rpb25hbGl0aWVzIG9mIHBsYXNtYSBwcm90ZWlucyBkdXJpbmcgYWN1dGUgbWFsYXJpYSoqCgojIyBGaWd1cmUgMkEKCmBgYHtyfQpzZWNyZXRvbWVfbG9jYXRpb25fZGFwIDwtIGRhcC5yZXMgJT4lIAogIGRwbHlyOjpmaWx0ZXIoRkRSPT1UUlVFKSAlPiUKICBhcnJhbmdlKGRlc2MoYWJzKGxvZ0ZDKSksZGVzYyhwLmFkaikpICU+JSAKICBpbm5lcl9qb2luKGhwYV8yNC4wLCBieT1jKCJBc3NheSI9ImdlbmUiLCJVbmlQcm90Ij0idW5pcHJvdCIpKSAlPiUgCiAgbXV0YXRlKHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyA9IGNhc2Vfd2hlbihzZWNyZXRvbWVfbG9jYXRpb249PSJOb3Qgc2VjcmV0ZWQifiBwYXN0ZTAoc2VjcmV0b21lX2xvY2F0aW9uLCIgLSAiLHJuYV90aXNzdWVfc3BlY2lmaWNpdHkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHNlY3JldG9tZV9sb2NhdGlvbikpICU+JSAKICBncm91cF9ieShzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpICU+JSAKICBjb3VudChzb3J0ID0gVFJVRSkgCgojIyBjaGFuZ2Ugb3JkZXIKc2VjcmV0b21lX2xvY2F0aW9uX2RhcC5vcmRlciA8LSBzZWNyZXRvbWVfbG9jYXRpb25fZGFwICU+JSBwdWxsKHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykKc2VjcmV0b21lX2xvY2F0aW9uX2RhcC5vcmRlciA8LSBjKCJTZWNyZXRlZCB0byBibG9vZCIsIkludHJhY2VsbHVsYXIgYW5kIG1lbWJyYW5lIiwiU2VjcmV0ZWQgaW4gb3RoZXIgdGlzc3VlcyIsIlNlY3JldGVkIHRvIGV4dHJhY2VsbHVsYXIgbWF0cml4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCB0byBkaWdlc3RpdmUgc3lzdGVtIiwgIlNlY3JldGVkIGluIGJyYWluIiwgIlNlY3JldGVkIC0gdW5rbm93biBsb2NhdGlvbiIsICJTZWNyZXRlZCBpbiBmZW1hbGUgcmVwcm9kdWN0aXZlIHN5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gbWFsZSByZXByb2R1Y3RpdmUgc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBUaXNzdWUgZW5yaWNoZWQiLCAiTm90IHNlY3JldGVkIC0gVGlzc3VlIGVuaGFuY2VkIiwiTm90IHNlY3JldGVkIC0gR3JvdXAgZW5yaWNoZWQiLCAiTm90IHNlY3JldGVkIC0gTG93IHRpc3N1ZSBzcGVjaWZpY2l0eSIpCgojIyBwbG90IGV2ZXJ5dGhpbmcKKGhwYS5wcm90ZWluLm9yaWdpbi5vdmVydmlldyA8LSBzZWNyZXRvbWVfbG9jYXRpb25fZGFwICU+JSAKICAgIHVuZ3JvdXAoKSAlPiUgCiAgICBtdXRhdGUoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjID0gZmFjdG9yKGFzLmZhY3RvcihzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpLCBsZXZlbHM9cmV2KHNlY3JldG9tZV9sb2NhdGlvbl9kYXAub3JkZXIpKSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PXNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyx5PW4sZmlsbD1zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpKSArCiAgICBnZW9tX2NvbCh3aWR0aCA9IDAuNSkgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1uKSxzaXplPTIsIG51ZGdlX3kgPSAtLjIpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9InBzZXVkb19sb2ciLG5hbWUgPSBOVUxMLCBzZWMuYXhpcyA9IHNlY19heGlzKH4uLGxhYmVscyA9IE5VTEwsYnJlYWtzID0gTlVMTCwgbmFtZSA9ICJOdW1iZXIgb2YgREFQcyIpLAogICAgICAgICAgICAgICAgICAgICAgICNleHBhbmQ9YygwLC4xNSkKICAgICAgICAgICAgICAgICAgICAgICBleHBhbmQ9YygwLDApCgogICAgICAgICAgICAgICAgICAgICAgICkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9c2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjX2NvbHMsCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBzZWNyZXRvbWVfbG9jYXRpb25fZGFwLm9yZGVyKSArCiAgICBsYWJzKGZpbGw9IlByb3RlaW5cbm9yaWdpblxuYnkgSFBBIiwKICAgICAgICAgeD1OVUxMKSkKYGBgCgpgYGB7cn0KdGVtcC5kZiA8LSBkYXAucmVzICU+JSAKICBkcGx5cjo6ZmlsdGVyKEZEUj09VFJVRSkgJT4lCiAgYXJyYW5nZShkZXNjKGFicyhsb2dGQykpLGRlc2MocC5hZGopKSAlPiUgCiAgaW5uZXJfam9pbihocGFfMjQuMCwgYnk9YygiQXNzYXkiPSJnZW5lIiwiVW5pUHJvdCI9InVuaXByb3QiKSkgJT4lIAogIG11dGF0ZShzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMgPSBjYXNlX3doZW4oc2VjcmV0b21lX2xvY2F0aW9uPT0iTm90IHNlY3JldGVkIn4gcGFzdGUwKHNlY3JldG9tZV9sb2NhdGlvbiwiIC0gIixybmFfdGlzc3VlX3NwZWNpZmljaXR5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBzZWNyZXRvbWVfbG9jYXRpb24pKQpgYGAKCiMjIEZpZ3VyZSAyQgpgYGB7ciB9CmRmMSA8LSB0ZW1wLmRmICU+JSAKICB0cmFuc211dGUoQXNzYXksIGxvZ0ZDLCBwLmFkaiwgZGlyZWN0aW9uLHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYywgc2VjcmV0b21lX2Z1bmN0aW9uKSAKCmRmMiA8LSBkZjEgJT4lIAogIGdyb3VwX2J5KHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykgJT4lIAogIHN1bW1hcmlzZShhdGxhc19uYW1lX2NvdW50ID0gbigpKSAlPiUgCiAgbGVmdF9qb2luKAogICAgZGYxICU+JSAKICAgICAgZ3JvdXBfYnkoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjLCBzZWNyZXRvbWVfZnVuY3Rpb24sIGRpcmVjdGlvbikgJT4lIAogICAgICBzdW1tYXJpc2UoZnVuY3Rpb25fbmFtZV9jb3VudCA9IG4oKSksCiAgICBieT0ic2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjIikgJT4lIAogIGxlZnRfam9pbigKICAgIGRmMSAlPiUgZ3JvdXBfYnkoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjLCBzZWNyZXRvbWVfZnVuY3Rpb24sIGRpcmVjdGlvbikgJT4lIAogICAgICBzdW1tYXJpc2UobWVkaWFuX2xvZ0ZDID0gbWVkaWFuKGxvZ0ZDKSksCiAgICBieT1jKCJzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMiLCAic2VjcmV0b21lX2Z1bmN0aW9uIiwiZGlyZWN0aW9uIikpCgooaHBhLmZ1bmN0aW9uLmJ1YmJsZXBsb3QgPC0gZGYyICU+JSAKICAgIGZpbHRlcighc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjICVpbiUgYygiTlVMTCIsICJOQSIsIm5vIG1hcHBpbmciKSwKICAgICAgICAgICAhc2VjcmV0b21lX2Z1bmN0aW9uICVpbiUgYygiTlVMTCIpKSAlPiUgCiAgICBtdXRhdGUoc2VjcmV0b21lX2Z1bmN0aW9uID0gY2FzZV93aGVuKGlzLm5hKHNlY3JldG9tZV9mdW5jdGlvbikgfiAiTm8gc2VjcmV0b21lIGZ1bmN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBzZWNyZXRvbWVfZnVuY3Rpb24pKSAlPiUgCiAgICBtdXRhdGUoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjID0gZmFjdG9yKGFzLmZhY3RvcihzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1yZXYoc2VjcmV0b21lX2xvY2F0aW9uX2RhcC5vcmRlcikpKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9bWVkaWFuX2xvZ0ZDLAogICAgICAgICAgICAgICB5PSBmY3RfcmVvcmRlcjIoc2VjcmV0b21lX2Z1bmN0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF0bGFzX25hbWVfY291bnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbl9uYW1lX2NvdW50LC5kZXNjID0gRikpKSArCiAgICBnZW9tX3BvaW50KGFlcyhzaXplPWZ1bmN0aW9uX25hbWVfY291bnQsIGNvbG9yPXNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyksIHNob3cubGVnZW5kID0gVCkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCxsaW5ldHlwZT0xKSArCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZnVuY3Rpb25fbmFtZV9jb3VudCksCiAgICAgICAgICAgICAgc2l6ZT0yLCBjb2xvcj0iZ3JleTIwIixzaG93LmxlZ2VuZCA9IEYsIHBhcnNlID0gRikgKwogICAgbGFicyh4PSJtZWRpYW4gZXN0aW1hdGVkIGRpZmZlcmVuY2UgKE5QWCkiLAogICAgICAgICB5PU5VTEwsCiAgICAgICAgIHRpdGxlID0gIk51bWJlciBEQVBzIHBlciBIUEEgZnVuY3Rpb24iLAogICAgICAgICBzaXplPSJOdW1iZXIgb2YgcHJvdGVpbnMiLAogICAgICAgICBjYXB0aW9uPSJTaXplOiBudW1iZXIgb2YgcHJvdGVpbnMiLAogICAgICAgICBjb2xvciA9ICJIUEEgc291cmNlIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWNfY29scywgbGltaXRzID0gc2VjcmV0b21lX2xvY2F0aW9uX2RhcC5vcmRlcikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gInBzZXVkb19sb2ciKSArCiAgICBzY2FsZV95X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwxKSkrCiAgICBndWlkZXMoc2l6ZSA9ICJub25lIikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHNjYWxlX3NpemUocmFuZ2U9YygzLDYpKSArCiAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NikpCikKYGBgCgoKIyMgRmlndXJlIDJDCmBgYHtyIERBUC1ocGEtZnVuY3Rpb259CihhY3V0ZV9tYWxhcmlhX2hwYV9zb3VyY2UgPC0gdGVtcC5kZiAlPiUgCiAgICByaWdodF9qb2luKHRvcDI1ICU+JSB0cmFuc211dGUoQXNzYXksbG9nRkMpKSAlPiUgCiAgICAKICAgIGdncGxvdChhZXMoeD1mY3RfcmVvcmRlcihBc3NheSxsb2dGQyksIHk9bG9nRkMsIGNvbG9yPXNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykpICsKICAgIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBUUlVFLHNpemU9MSkgKwogICAgZ2VvbV9jb2wod2lkdGggPSAuMDUsc2hvdy5sZWdlbmQgPSBGKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoc2VjLmF4aXMgPSBzZWNfYXhpcyh+LixsYWJlbHMgPSBOVUxMLGJyZWFrcyA9IE5VTEwsIG5hbWUgPSAiVG9wMjUgREFQIikpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA0KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKGNvbG9yPSJIUEEgc291cmNlIiwKICAgICAgICAgeD0iIiwKICAgICAgICAgeT0iRXN0aW1hdGVkIGRpZmZlcmVuY2UgKE5QWCkiLAogICAgICAgICB0aXRsZSA9ICJQcm90ZWluIHNvdXJjZSBhY2NvcmRpbmcgdG8gSHVtYW4gUHJvdGVpbiBBdGxhcyIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjX2NvbHMsCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzPXNlY3JldG9tZV9sb2NhdGlvbl9kYXAub3JkZXIpKQpgYGAKCgojIyBTdXBwbGVtZW50YXJ5IEZpZ3VyZSA0IAoqKnJlbGF0ZWQgdG8gbWFpbiBGaWd1cmUgMioqCgojIyMgRmlndXJlIFM0QQpgYGB7cn0KbWFsYXJpYS5kYXBzLmhwYTIzIDwtIGRhcC5yZXMgJT4lIAogIGFycmFuZ2UoZGVzYyhhYnMobG9nRkMpKSxkZXNjKHAuYWRqKSkgJT4lIAogIGZpbHRlcihwLmFkajw9MC4wMSkgJT4lIAogIGFycmFuZ2UoLWxvZ0ZDKSAlPiUgCiAgbGVmdF9qb2luKGhwYV8yNC4wLGJ5PWMoIlVuaVByb3QiID0gInVuaXByb3QiKSkgJT4lIAogIHVuZ3JvdXAoKQoKIyMgYWJ1bmRhbnQgcHJvdGVpbnMgaW4gYWN1dGUgbWFsYXJpYSBwbGFzbWEsIG5vdCBpbW11bmUgY2VsbCBzcGVjaWZpYyBub3IgcHJlZGljdGVkIHRvIGJlIHNlY3JldGVkCiMjID0+IHRpc3N1ZSBsZWFrYWdlPz8KbWFsYXJpYS50aXNzdWUubGVha2FnZSA8LSBtYWxhcmlhLmRhcHMuaHBhMjMgJT4lIAogIGZpbHRlcihpcy5uYShybmFfYmxvb2RfY2VsbF9zcGVjaWZpY2l0eSkgfCAKICAgICAgICAgICBybmFfYmxvb2RfY2VsbF9zcGVjaWZpY2l0eT09Ik5vdCBkZXRlY3RlZCBpbiBpbW11bmUgY2VsbHMiLCAKICAgICAgICAgcm5hX3Rpc3N1ZV9zcGVjaWZpY2l0eSAlaW4lIGMoIlRpc3N1ZSBlbnJpY2hlZCIpLCMsIkdyb3VwIGVucmljaGVkIiwiVGlzc3VlIGVuaGFuY2VkIiksCiAgICAgICAgIHNlY3JldG9tZV9sb2NhdGlvbiA9PSJOb3Qgc2VjcmV0ZWQiLAogICAgICAgICBsb2dGQyA+MCkjLjUpCgpzZWNyZXRvbWUubG9jYXRpb24ub3JkZXIgPC0gYygiU2VjcmV0ZWQgdG8gYmxvb2QiLCJJbnRyYWNlbGx1bGFyIGFuZCBtZW1icmFuZSIsIlNlY3JldGVkIGluIG90aGVyIHRpc3N1ZXMiLCJTZWNyZXRlZCB0byBleHRyYWNlbGx1bGFyIG1hdHJpeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgdG8gZGlnZXN0aXZlIHN5c3RlbSIsICJTZWNyZXRlZCBpbiBicmFpbiIsICJTZWNyZXRlZCAtIHVua25vd24gbG9jYXRpb24iLCAiU2VjcmV0ZWQgaW4gZmVtYWxlIHJlcHJvZHVjdGl2ZSBzeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIG1hbGUgcmVwcm9kdWN0aXZlIHN5c3RlbSIsIk5vdCBzZWNyZXRlZCIpCnNlY3JldG9tZS5mdW4uY291bnQgPC0gbWFsYXJpYS5kYXBzLmhwYTIzICU+JSBncm91cF9ieShzZWNyZXRvbWVfZnVuY3Rpb24pICU+JSBjb3VudCgpICU+JSBhcnJhbmdlKC1uKSAlPiUgcHVsbChzZWNyZXRvbWVfZnVuY3Rpb24pCgpkZiA8LSBtYWxhcmlhLmRhcHMuaHBhMjMgJT4lIAogIGZpbHRlcihsb2dGQz49MCkgJT4lIAogIHRyYW5zbXV0ZShBc3NheSwKICAgICAgICAgICAgZGlyZWN0aW9uLAogICAgICAgICAgICBzZWNyZXRvbWVfbG9jYXRpb24gPSBmYWN0b3Ioc2VjcmV0b21lX2xvY2F0aW9uLCBsZXZlbHM9IHNlY3JldG9tZS5sb2NhdGlvbi5vcmRlciksCiAgICAgICAgICAgIHNlY3JldG9tZV9mdW5jdGlvbiA9IGZhY3RvcihzZWNyZXRvbWVfZnVuY3Rpb24sIGxldmVscyA9IHNlY3JldG9tZS5mdW4uY291bnQpLAogICAgICAgICAgICBybmFfYmxvb2RfY2VsbF9zcGVjaWZpY2l0eSwKICAgICAgICAgICAgcm5hX3Rpc3N1ZV9zcGVjaWZpY2l0eSA9IGZhY3RvcihybmFfdGlzc3VlX3NwZWNpZmljaXR5LCBsZXZlbHMgPSBjKCJUaXNzdWUgZW5yaWNoZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwIGVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUaXNzdWUgZW5oYW5jZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxvdyB0aXNzdWUgc3BlY2lmaWNpdHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBkZXRlY3RlZCIpKSwKICAgICAgICAgICAgdGlzc3VlX2VucmljaGVkID0gZmFjdG9yKGNhc2Vfd2hlbihybmFfYmxvb2RfY2VsbF9zcGVjaWZpY2l0eT09Ik5vdCBkZXRlY3RlZCBpbiBpbW11bmUgY2VsbHMiICYgcm5hX3Rpc3N1ZV9zcGVjaWZpY2l0eSA9PSAiVGlzc3VlIGVucmljaGVkIiAmIHNlY3JldG9tZV9sb2NhdGlvbiA9PSJOb3Qgc2VjcmV0ZWQiICYgZGlyZWN0aW9uID09ICJ1cCIgfiIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9ICIwIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWMoIjEiLCIwIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIjEiPSJUaXNzdWUgc3BlY2lmaWMgYW5kIG5vdCBzZWNyZXRlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMCI9Ikxlc3MgdGlzc3VlIHNwZWNpZmljIikKICAgICAgICAgICAgKSkKYGBgCgoKYGBge3J9CihkYXAub3JpZ2luLncudGwgPC0gZGYgJT4lCiAgICBnZ3Bsb3QoYWVzKGF4aXMxID0gc2VjcmV0b21lX2xvY2F0aW9uLAogICAgICAgICAgICAgICBheGlzMiA9IHNlY3JldG9tZV9mdW5jdGlvbiwKICAgICAgICAgICAgICAgYXhpczMgPSBybmFfdGlzc3VlX3NwZWNpZmljaXR5LAogICAgICAgICAgICAgICBheGlzNCA9IHRpc3N1ZV9lbnJpY2hlZAogICAgKSkgKwogICAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IHNlY3JldG9tZV9sb2NhdGlvbiksd2lkdGggPSAxLzEyLGdlb20gPSAiZmxvdyIsIGxvZGUuZ3VpZGFuY2UgPSAiZm9yd2FyZCIsKSArCiAgICBnZW9tX3N0cmF0dW0oYWVzKGZpbGw9c2VjcmV0b21lX2xvY2F0aW9uKSx3aWR0aCA9IDEvMTIpICsKICAgIGdnZml0dGV4dDo6Z2VvbV9maXRfdGV4dChzdGF0ID0gInN0cmF0dW0iLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KHN0cmF0dW0pKSxtaW4uc2l6ZSA9IDEsIHNob3cubGVnZW5kID0gRikgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJTZWNyZXRvbWVcbmxvY2F0aW9uIiwiU2VjcmV0b21lXG5mdW5jdGlvbiIsICJUaXNzdWUgc3BlY2lmaWNpdHlcbihiYXNlZCBvbiBnZW5lIGV4cHJlc3Npb24pIiwiVGlzc3VlIHNwZWNpZmljaXR5XG4ob3ZlcmFsbCkiKSwgZXhwYW5kID0gYyguMiwgLjA1KSkgKwogICAgdGhlbWVfYncoKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGMoc2VjcmV0b21lX2xvY2F0aW9uX2NvbHMsIk5BIj0icmVkIiwiU1BFQyI9IndoaXRlIikpICsKICAgIGxhYnModGl0bGUgPSAiQWJ1bmRhbnQgcHJvdGVpbnMgaW4gYmxvb2QgZHVyaW5nIGFjdXRlIG1hbGFyaWEiLAogICAgICAgICB5PSAiTnVtYmVyIG9mIHByb3RlaW5zIikgKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIsIHNpemU9MC41LCBmaWxsPU5BKSwKICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChzaXplID0gMC4yLCBjb2xvdXIgPSAiZ3JleSIpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKYGBgCgojIyMgRmlndXJlIFM0QgpgYGB7cn0KKGFsbHV2aWFsX3Byb3RlaW5vcmlnaW4gPC0gZGYgJT4lCiAgIGdncGxvdChhZXMoYXhpczEgPSBzZWNyZXRvbWVfbG9jYXRpb24sCiAgICAgICAgICAgICAgYXhpczMgPSBybmFfdGlzc3VlX3NwZWNpZmljaXR5LAogICAgICAgICAgICAgIGF4aXM0ID0gdGlzc3VlX2VucmljaGVkCiAgICkpICsKICAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IHRpc3N1ZV9lbnJpY2hlZCksd2lkdGggPSAxLzEyLGdlb20gPSAiZmxvdyIsIGxvZGUuZ3VpZGFuY2UgPSAiZm9yd2FyZCIsKSArCiAgIGdlb21fc3RyYXR1bShhZXMoZmlsbD1zZWNyZXRvbWVfbG9jYXRpb24pLHdpZHRoID0gMS8xMikgKwogICBnZ2ZpdHRleHQ6Omdlb21fZml0X3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChzdHJhdHVtKSksbWluLnNpemUgPSAxLCBzaG93LmxlZ2VuZCA9IEYpICsKICAgCiAgIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiU2VjcmV0b21lXG5sb2NhdGlvbiIsIyJTZWNyZXRvbWVcbmZ1bmN0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGlzc3VlIHNwZWNpZmljaXR5XG4oYmFzZWQgb24gZ2VuZSBleHByZXNzaW9uKSIsIlRpc3N1ZSBzcGVjaWZpY2l0eVxuKG92ZXJhbGwpIiksIGV4cGFuZCA9IGMoLjIsIC4wNSkpICsKICAgdGhlbWVfYncoKSArCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gYygiVGlzc3VlIHNwZWNpZmljIGFuZCBub3Qgc2VjcmV0ZWQiPSJyZWQiLCJMZXNzIHRpc3N1ZSBzcGVjaWZpYyI9ImdyZXk5MCIpKSArCiAgIGxhYnModGl0bGUgPSAiUG90ZW50aWFsIHRpc3N1ZSBsZWFrYWdlIHByb3RlaW5zIGluIGJsb29kIGR1cmluZyBhY3V0ZSBtYWxhcmlhIiwKICAgICAgICB5PSAiTnVtYmVyIG9mIHByb3RlaW5zIikgKwogICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgc2l6ZT0wLjUsIGZpbGw9TkEpLAogICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3Qoc2l6ZSA9IDAuMiwgY29sb3VyID0gImdyZXkiKSwKICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKCm1hbGFyaWEudGlzc3VlLmxlYWthZ2UgPC0gZGYgJT4lIGZpbHRlcih0aXNzdWVfZW5yaWNoZWQ9PSJUaXNzdWUgc3BlY2lmaWMgYW5kIG5vdCBzZWNyZXRlZCIpICU+JSBwdWxsKEFzc2F5KQpgYGAKCiMjIyBGaWd1cmUgUzRDCmBgYHtyfQojIyMgdGlzc3VlIGV4cHJlc3Npb27CqAptYXQgPC0gaHBhLnRpc3N1ZSAlPiUgCiAgZmlsdGVyKGdlbmVfbmFtZSAlaW4lIGMobWFsYXJpYS50aXNzdWUubGVha2FnZSkpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdGlzc3VlLCB2YWx1ZXNfZnJvbSA9IG5fdHBtLCB2YWx1ZXNfZm4gPSBtZWRpYW4pICU+JSAKICBkcGx5cjo6c2VsZWN0KC1nZW5lKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJnZW5lX25hbWUiKQoKbWF0MSA8LSBtYXQgJT4lIAogIHQoKSAlPiUgCiAgc2NhbGUoKSAlPiUgCiAgc2NhbGVzOjpyZXNjYWxlKHRvPWMoMCwxKSkgJT4lIAogIHQoKSAKCihobS50aXNzdWUubGVha2FnZSA8LSBtYXQxICU+JSAKICAgIHQoKSAlPiUgCiAgICBIZWF0bWFwKHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9ICBncGFyKGZvbnRzaXplPTQpLAogICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBULAogICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBULAogICAgICAgICAgICBuYW1lPSJzY2FsZWRcbm5UUE0iLAogICAgICAgICAgICBjb2x1bW5fdGl0bGUgPSAiSGlnaCBhYnVuZGFudCBwbGFzbWEgcHJvdGVpbnNcbiAnVGlzc3VlIHNwZWNpZmljIGFuZCBub3Qgc2VjcmV0ZWQnIiwKICAgICAgICAgICAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT02KSwKICAgICAgICAgICAgY29sID0gY2lyY2xpemU6OmNvbG9yUmFtcDIoYyhtaW4obWF0MSksbWF4KG1hdDEpKSwgYygid2hpdGUiLCJyZWQiKSksCiAgICAgICAgICAgIGNvbHVtbl9kZW5kX2hlaWdodCA9IHVuaXQoNSwibW0iKSwKICAgICAgICAgICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDUsIm1tIiksCiAgICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDIwLCAibW0iKSkpCikKYGBgCgojIyMgRmlndXJlIFM0RApgYGB7cn0KKHRpc3N1ZS5sZWFrYWdlLnZpb2xpbmUgPC0gZGF0YS5sb25nICU+JSAKICAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIGRwbHlyOjpzZWxlY3QoREFpZCxUaW1lLHNhbXBsZV9pZCxzdHVkeV9pZCksCiAgICAgICAgICAgICAgYnk9InNhbXBsZV9pZCIpICU+JSAKICAgZHBseXI6OmZpbHRlcihBc3NheSAlaW4lIGMobWFsYXJpYS50aXNzdWUubGVha2FnZSksCiAgICAgICAgICAgICAgICAgVGltZSE9IkQxMCIpICU+JSAKICAgbXV0YXRlKEFzc2F5ID0gZmFjdG9yKEFzc2F5LCBsZXZlbHMgPSBjKG1hbGFyaWEudGlzc3VlLmxlYWthZ2UpKSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PVRpbWUsIHk9TlBYLCBjb2xvcj1UaW1lLGZpbGw9VGltZSkpICsgCiAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPXN0dWR5X2lkKSwgY29sb3I9ImdyZXkiLGFscGhhPS42LHNpemU9LjIpKwogICAgZ2VvbV92aW9saW4odHJpbSA9IEYsYWxwaGE9LjIsbHdkPS4yNSkgKwogICAgZ2VvbV9ib3hwbG90KGFscGhhPTEsd2lkdGg9MC4yNSxjb2xvcj0iYmxhY2siLG91dGxpZXIuc2l6ZSA9IDAuNSwgZmF0dGVuID0gMSxsd2Q9LjI1LHNob3cubGVnZW5kID0gRikgKwogICAgZmFjZXRfd3JhcCh+QXNzYXksbmNvbCA9IDksc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHg9IiIpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dGltZTNfY29sKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9dGltZTNfY29sKSkKYGBgCgojIyMgRmlndXJlIFM0RQoKYGBge3J9CmRmIDwtICBkYXRhLmxvbmcgJT4lIAogICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgZHBseXI6OnNlbGVjdChEQWlkLFRpbWUsc2FtcGxlX2lkLHN0dWR5X2lkKSwKICAgICAgICAgICAgICBieT0ic2FtcGxlX2lkIikgJT4lIAogIGZpbHRlcihBc3NheSVpbiUgYygiQUdYVCIsIkhBTzEiKSwKICAgICAgICAgVGltZT09IkFjdXRlIikgJT4lIAogIGxlZnRfam9pbigKICAgIGNsaW5jaGVtX3N0dWR5X3BhdHNfYWN1dGUud2lkZSAlPiUgdHJhbnNtdXRlKHN0dWR5X2lkLCBwX2FzYXQsIHBfYWxhdCkKICApICU+JSAKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAiY2xpbmNoZW0iLCB2YWx1ZXNfdG8gPSAiY2xpbmNoZW1fdmFsIixjb2xzID0gcF9hc2F0OnBfYWxhdCkKCmRmICU+JSAKICBnZ3Bsb3QoYWVzKHg9TlBYLHk9Y2xpbmNoZW1fdmFsKSkgKwogICNnZW9tX3BvaW50KHNoYXBlPTE2LCBzaXplPS41KSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKwogIGZhY2V0X2dyaWQoQXNzYXl+Y2xpbmNoZW0pCgpsaWJyYXJ5KHNlZSkKKGFneHRfaGFvMV9hbGF0X2FzYXRfY29yIDwtIGRmICU+JSAKICB0cmFuc211dGUoc2FtcGxlX2lkLCBBc3NheSxOUFgsY2xpbmNoZW0sY2xpbmNoZW1fdmFsKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEFzc2F5LCB2YWx1ZXNfZnJvbSA9IE5QWCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGNsaW5jaGVtLCB2YWx1ZXNfZnJvbSA9IGNsaW5jaGVtX3ZhbCkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlX2lkIikgJT4lIAogIGNvcnJlbGF0aW9uKG1ldGhvZCA9ICJzcGVhcm1hbiIpICU+JSAKICBzdW1tYXJ5KCkgJT4lIAogIHBsb3QoKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkpCmBgYAoKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXJlIDUKKipyZWxhdGVkIHRvIG1haW4gRmlndXJlIDIqKgojIyMgRmlndXJlIFM1QS1ECmBgYHtyfQppPSJTZWNyZXRlZCB0byBibG9vZCIKYWN1dGVfbWFsYXJpYV9ocGFfZnVuY3Rpb25fZmFjZXQubGlzdCA8LSBsaXN0KCkKZm9yKGkgaW4gYygiU2VjcmV0ZWQgdG8gYmxvb2QiLCJJbnRyYWNlbGx1bGFyIGFuZCBtZW1icmFuZSIsIlNlY3JldGVkIGluIG90aGVyIHRpc3N1ZXMiLCJTZWNyZXRlZCB0byBleHRyYWNlbGx1bGFyIG1hdHJpeCIsIlNlY3JldGVkIHRvIGRpZ2VzdGl2ZSBzeXN0ZW0iLCJTZWNyZXRlZCBpbiBicmFpbiIsIlNlY3JldGVkIC0gdW5rbm93biBsb2NhdGlvbiIpKXsKICAKICAoYWN1dGVfbWFsYXJpYV9ocGFfZnVuY3Rpb25fZmFjZXQubGlzdFtbaV1dIDwtIAogICAgIGRhcC5yZXMgJT4lIAogICAgIGRwbHlyOjpmaWx0ZXIoRkRSPT1UUlVFLAogICAgICAgICAgICAgICAgICAgYWJzKGxvZ0ZDKT4wKSAlPiUKICAgICBpbm5lcl9qb2luKGhwYV8yNC4wLGJ5PWMoIkFzc2F5Ij0iZ2VuZSIpKSAlPiUgCiAgICAgZHBseXI6OmZpbHRlcihzZWNyZXRvbWVfbG9jYXRpb24gPT0gaSwgCiAgICAgICAgICAgICAgICAgICAhc2VjcmV0b21lX2Z1bmN0aW9uICVpbiUgYyhOQSwiTlVMTCIsIk5vdCBzZWNyZXRlZCIpCiAgICAgKSAlPiUgCiAgICAgICB1bmdyb3VwKCkgJT4lIAogICAgICAgbXV0YXRlKHNlY3JldG9tZV9mdW5jdGlvbiA9IGZhY3RvcihzZWNyZXRvbWVfZnVuY3Rpb24pKSU+JSAKICAgICAgIGdncGxvdChhZXMoeCA9IGZjdF9yZW9yZGVyMihBc3NheSwgc2VjcmV0b21lX2Z1bmN0aW9uLCAtbG9nRkMpLAogICAgICAgICAgICAgICAgICB5PWxvZ0ZDLCBjb2xvciA9IHNlY3JldG9tZV9sb2NhdGlvbikpICsKICAgICAgIGdlb21fcG9pbnQoc2l6ZT0xLCBzaG93LmxlZ2VuZCA9IEYpICsgCiAgICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPSBsb2dGQyAtIDEuOTYqU0UsIyAxLjk2KlNFID1jb25mLmxvdwogICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1sb2dGQyArIDEuOTYqU0UsI2NvbmYuaGlnaCwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPXNlY3JldG9tZV9sb2NhdGlvbiksCiAgICAgICAgICAgICAgICAgICAgIHNpemU9LjI1LCAgICAKICAgICAgICAgICAgICAgICAgICAgd2lkdGg9LjIsCiAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSwKICAgICAgICAgICAgICAgICAgICAgYWxwaGE9LjUpICsKICAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPTIsIGFscGhhPS40KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHNlY3JldG9tZV9sb2NhdGlvbl9jb2xzKSArCiAgICAgICBjb29yZF9mbGlwKCkgKwogICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoc2VjcmV0b21lX2xvY2F0aW9uKSwgCiAgICAgICAgICAgICAgICAgIHJvd3MgPSB2YXJzKHNlY3JldG9tZV9mdW5jdGlvbiksIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZV95Iixkcm9wID0gRikgKwogICAgICAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCxzaXplPTMuNSksCiAgICAgICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAiaW5zaWRlIiwKICAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMyksCiAgICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSksCiAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT01KSwKICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NSksCiAgICAgICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZT01KSwKICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAuNSksCiAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gLjUpLAogICAgICAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgICAgbGFicyh4PSIiLAogICAgICAgICAgICB5PSJFc3RpbWF0ZWQgZGlmZmVyZW5jZSAoTlBYKSB3aXRoIDk1JSBDSSIpICsKICAgICAgIGV4cGFuZF9saW1pdHMoeSA9IGMoLTEsMSkpCiAgKQp9CmBgYAoKCiMjIyBkZWx0YSBOUFggCi0gbmVlZGVkIGZvciBoZWF0bWFwIGFubm90YXRpb24gYW5kICBsYXRlciBvbiBjbHVzdGVyaW5nCmBgYHtyfQpkZl80X2ZjIDwtIGRhdGEud2lkZSAlPiUgCiAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIGRwbHlyOjpzZWxlY3QoREFpZCxzdHVkeV9pZCwgc2FtcGxlX2lkLCBUaW1lKSxieT0ic2FtcGxlX2lkIikgJT4lIAogIGRwbHlyOjpmaWx0ZXIoVGltZSE9IkQxMCIpICU+JSAKICBkcGx5cjo6c2VsZWN0KERBaWQsc3R1ZHlfaWQsIHNhbXBsZV9pZCwgVGltZSwgZXZlcnl0aGluZygpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSA1Om5jb2woLiksIG5hbWVzX3RvID0gIkFzc2F5IiwgdmFsdWVzX3RvID0gIk5QWCIpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1EQWlkLC1zYW1wbGVfaWQpICU+JSAKICBwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9ICJOUFgiLCBuYW1lc19mcm9tID0gIlRpbWUiKQoKCk0xMl9tZWRpYW5fTTEyIDwtIGRmXzRfZmMgJT4lIAogIGdyb3VwX2J5KEFzc2F5KSAlPiUgCiAgc3VtbWFyaXNlKG0xMl9tZWRpYW4gPSBtZWRpYW4oTTEyLG5hLnJtID0gVFJVRSkpIAoKZmNfb3Zlcl9tZWRpYW5fTTEyIDwtIGRmXzRfZmMgJT4lIAogIGlubmVyX2pvaW4oTTEyX21lZGlhbl9NMTIsIGJ5PSJBc3NheSIpICU+JSAKICBncm91cF9ieShBc3NheSkgJT4lIAogIG11dGF0ZShsb2cyRkNfbWVkaWFuTTEyID0gQWN1dGUtbTEyX21lZGlhbikgJT4lIAogIGRwbHlyOjpzZWxlY3QoLU0xMikgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZHBseXI6OnJlbmFtZShkTlBYID0gbG9nMkZDX21lZGlhbk0xMikgCgojZmNfb3Zlcl9tZWRpYW5fTTEyICU+JSBzYXZlUkRTKCIuLi9kYXRhL2RhdGFfY2xlYW4vMjAyMzA0MjZfRXhwbG9yZTE1MzZfZmNfb3Zlcl9tZWRpYW5fbTEyX3RpZHlfbG9uZy5yZHMiKQpmY19vdmVyX21lZGlhbl9NMTIgJT4lIGhlYWQoKQpgYGAKCgoKIyBGaWd1cmUgMyAKKipTaW5nbGUtY2VsbCB0cmFuc2NyaXB0b21pY3Mgb2YgUEJNQ3MgZHVyaW5nIGFjdXRlIG1hbGFyaWEqKgoKYGBge3IgcGNhLWRhdGEtcmhhcHNvZHloaWdobGlnaHR9CmRmIDwtIGRhdGEud2lkZSAlPiUgCiAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIAogICAgICAgICAgICAgICB0cmFuc211dGUoc2FtcGxlX2lkKSwKICAgICAgICAgICAgIGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGVfaWQiKQoKIyMgUEMgY2FsY3VsYXRpb24KcGNhUmVzIDwtIHN0YXRzOjpwcmNvbXAoZGYsY2VudGVyID0gVFJVRSwgc2NhbGUuID0gVFJVRSkKdmFyRXhwIDwtIHJvdW5kKHBjYVJlcyRzZGV2XjIgLyBzdW0ocGNhUmVzJHNkZXZeMikgKiAxMDApCnBjYURGIDwtIGRhdGEuZnJhbWUoUEMxID0gcGNhUmVzJHhbLCAxXSwKICAgICAgICAgICAgICAgICAgICBQQzIgPSBwY2FSZXMkeFssIDJdKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAKCiMjIFByZXAgZm9yIHBsb3R0aW5nCmRhdGE0cGxvdCA8LSBwY2FERiAlPiUgCiAgZHBseXI6OmlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIG11dGF0ZShyaGFwc29keV9saWIgPSBpZmVsc2Uoc3R1ZHlfaWQgPT0gIjIwMTMwMDQiLCJMaWJyYXJ5IDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN0dWR5X2lkID09ICIyMDEzMDA3IiwiTGlicmFyeSAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3R1ZHlfaWQgPT0gIjIwMTMwMDgiLCJMaWJyYXJ5IDMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3R1ZHlfaWQgPT0gIjIwMTgwMDIiLCJMaWJyYXJ5IDQiLE5BKSkpKSkKCgoocGxvdC5wY2EucmhhcHNvZHkgPC0gZGF0YTRwbG90ICU+JSAKICAgIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gVGltZSxmaWxsPU5VTEwsIGxhYmVsID0gTlVMTCkpICsKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjksIHNpemUgPSAxKSArCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YT0gLiAlPiUgZmlsdGVyKHN0dWR5X2lkICVpbiUgcmhhcHNvZHlfc3R1ZHlfaWRzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9UEMxLHk9UEMyLCBsYWJlbD1yaGFwc29keV9saWIpLGNvbG9yPSJncmV5MTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJib3RoIixib3gucGFkZGluZyA9IDEsIG1heC5vdmVybGFwcyA9IEluZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPTMsIGFscGhhPS45LHNob3cubGVnZW5kID0gRikgKwogICAgZ2VvbV9wb2ludChkYXRhPSAuICU+JSBmaWx0ZXIoc3R1ZHlfaWQgJWluJSByaGFwc29keV9zdHVkeV9pZHMpLAogICAgICAgICAgICAgICBhZXMoY29sb3I9VGltZSksCiAgICAgICAgICAgICAgIHNpemU9MC41LCBhbHBoYT0uOCkgKwogICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MSxhbHBoYT0xKSkpKwogICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gdGltZTNfY29sKSArCiAgICBsYWJzKHggPSBwYXN0ZTAoIlBDMSAoIiwgIHZhckV4cFsxXSwgIiAlKSIpLAogICAgICAgICB5ID0gcGFzdGUwKCJQQzIgKCIsICB2YXJFeHBbMl0sICIgJSkiKSwKICAgICAgICAgc2hhcGU9IlJoYXBzb2R5IGxpYnJhcnkiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgICsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksIAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSkgCmBgYAoKbG9hZCBzZXVyYXQgb2JqZWN0ICYgc2V0IGNvbG9ycwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KFNldXJhdCkKI3BibWMgPC0gcmVhZFJEUygiLi4vZGF0YS9kYXRhL3JoYXBzb2R5LzIwMjEtMTItMTdBYlNlcV9DZWxsX0NhbGxpbmdfcWNfY2NhX3dubl9jbHVzdGVyaW5nX2Fubm90YXRlZC5yZHMiKQpwYm1jIDwtIHJlYWRSRFMoIi4uL2RhdGEvZGF0YS9yaGFwc29keS9NYWxhcmlhVHJhdmVsZXJfUmhhcHNvZHlBYlNlcV9DZWxsX0NhbGxpbmdfcWNfY2NhX3dubl9jbHVzdGVyaW5nX2Fubm90YXRlZC5yZHMiKQoKcGJtYyRHcm91cF9yZXYgPC0gZmFjdG9yKGFzLmZhY3RvcihwYm1jJEdyb3VwKSwgbGV2ZWxzID0gYygicHJpbWFyeSIsICJwcmV2aW91c2x5IikpCgojLSBSTkEgTm9ybWFsaXphdGlvbgpwYm1jIDwtIE5vcm1hbGl6ZURhdGEob2JqZWN0ID0gcGJtYywgYXNzYXkgPSAnUk5BJywgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAnTG9nTm9ybWFsaXplJywgc2NhbGUuZmFjdG9yID0gMTAwMDApCgojLSBBYiBOb3JtYWxpemF0aW9uCnBibWMgPC0gTm9ybWFsaXplRGF0YShvYmplY3QgPSBwYm1jLCBhc3NheSA9ICdBRFQnLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICdDTFInKSAjbWFyZ2luCUlmIHBlcmZvcm1pbmcgQ0xSIG5vcm1hbGl6YXRpb24sIG5vcm1hbGl6ZSBhY3Jvc3MgZmVhdHVyZXMgKDEpIG9yIGNlbGxzICgyKQoKIyMgbGlzdCBvZiBwcm90ZWlucy9tcm5hIHRhcmdldHMgY292ZXJlZAphYi5tYXJrZXJzIDwtIHJvd25hbWVzKHBibWNAYXNzYXlzJEFEVCkKcm5hLm1hcmtlcnMgPC0gcm93bmFtZXMocGJtY0Bhc3NheXMkUk5BKQoKIyNjaGFuZ2UgZ3JvdXAgY29sb3IKRU5ERU1JQ19jb2xvcnMgPC0gc2V0TmFtZXMoYygiI0YxQTM0MCIsIiM5OThFQzMiKSwgYygicHJldmlvdXNseV9leHBvc2VkIiwicHJpbWFyeV9pbmZlY3RlZCIpKQojcHJldmlvdXNseV9leHBvc2VkICAgcHJpbWFyeV9pbmZlY3RlZCAKIyAgICAgICAgICIjRjFBMzQwIiAgICAgICAgICAiIzk5OEVDMyIgCkVOREVNSUNfY29sb3JzIDwtIHNldE5hbWVzKGJyZXdlci5wYWwoMywiUHVPciIpW2MoMSwzKV0sIGMoInByZXZpb3VzbHlfZXhwb3NlZCIsInByaW1hcnlfaW5mZWN0ZWQiKSkKbmFtZXMoRU5ERU1JQ19jb2xvcnMpIDwtIGMoInByZXZpb3VzbHkiLCJwcmltYXJ5IikKVElNRV9jb2xvcnMgPC0gc2V0TmFtZXMoYnJld2VyLnBhbCg2LCJQaVlHIiksIGMoIkFjdXRlIiwiRDEwIiwiTTEiLCJNMyIsIk02IiwiWTEiKSkKCnNjYWxlZF8wMV9jb2wgPC0gY2lyY2xpemU6OmNvbG9yUmFtcDIoYygwLDEpLCBjKCJ3aGl0ZSIsInJlZCIpKQoKTDFfY29sb3JzIDwtIGxlbmd0aCh1bmlxdWUocGJtY0BtZXRhLmRhdGEkQ2VsbFR5cGVfTDEpKQpMMV9jb2xvcnMgPC0gYygiIzY4YTc0OCIsCiAgICAgICAgICAgICAgICIjODc2MWNjIiwKICAgICAgICAgICAgICAgIiNhZTk1M2UiLAogICAgICAgICAgICAgICAiIzY4OGJjYyIsCiAgICAgICAgICAgICAgICIjY2M2OTNkIiwKICAgICAgICAgICAgICAgIiM0YWFjOGQiLAogICAgICAgICAgICAgICAiI2MzNjFhYSIsCiAgICAgICAgICAgICAgICIjY2E1MzY5IikKbmFtZXMoTDFfY29sb3JzKSA8LSB1bmlxdWUocGJtY0BtZXRhLmRhdGEkQ2VsbFR5cGVfTDEpCgoKSWRlbnRzKHBibWMpIDwtICJDZWxsVHlwZV9MMiIKCkwyX2NvbG9ycyA8LSBsZW5ndGgodW5pcXVlKHBibWNAbWV0YS5kYXRhJENlbGxUeXBlX0wyKSkKTDJfY29sb3JzIDwtIGMoIm1EQyI9IiM3OTY1OEMiLAogICAgICAgICAgICAgICAicERDIiA9ICIjQUVBMTRFIiwKICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICJDRDE0IG1vbm9jeXRlcyI9ICIjRDFFQUI3IiwKICAgICAgICAgICAgICAgIkNEMTYgbW9ub2N5dGVzIj0iI0RCN0Q0NyIsCiAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAiVmQyKyBnZFQiPSIjNzk2Q0Q3IiwKICAgICAgICAgICAgICAgIlZkMi0gZ2RUIiA9ICAiIzY2QUM1NSIsCiAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAiTksgQ0Q1NmRpbSBDRDE2KyIgPSAiI0VCQjY5RSIsIAogICAgICAgICAgICAgICAiTksgQ0Q1NmRpbSIgPSAgIiNDRUU0ODYiLAogICAgICAgICAgICAgICAiTksgQ0Q1NmJyaWdodCI9ICAiI0UwREFEQiIsCiAgICAgICAgICAgICAgICJOSyBwcm9saWYuIiA9IiNCNUU3REYiLAogICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIkIgbmFpdmUiID0gIiM4ODlBRTUiLAogICAgICAgICAgICAgICAiQiBtZW1vcnkiID0gIiM2NkVENTgiLAogICAgICAgICAgICAgICAiUGxhc21hIGNlbGxzIiA9ICIjODkzQ0VBIiwKICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICJDRDQgbmFpdmUiPSAiI0UxNTA4MSIsCiAgICAgICAgICAgICAgICJDRDQgVHJlZyBDRDgwKyI9ICIjNTc5MTg5IiwKICAgICAgICAgICAgICAgIkNENCBUcmVnIENEODAtIj0gICIjNjZERUUyIiwKICAgICAgICAgICAgICAgIkNENCBUZmgiPSAiI0Q2NEVEQiIsCiAgICAgICAgICAgICAgICJDRDQgZWZmZWN0LiBhY3RpdmF0ZWQiID0gIiNEMzhEOTYiLAogICAgICAgICAgICAgICAiQ0Q0IGVmZmVjdC4gbWVtb3J5IiA9ICIjRURENTkxIiwKICAgICAgICAgICAgICAgIkNENCB0cmFucy4gbWVtb3J5IiA9ICAiI0RBQjhFMyIsCiAgICAgICAgICAgICAgICJDRDQgY2VudHJhbCBtZW1vcnkiICA9ICIjNkZFOEJFIiwKICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICJDRDggbmFpdmUiPSAiI0NBRUI0OCIsCiAgICAgICAgICAgICAgICJDRDggdHJhbnMuIG1lbW9yeSI9ICIjODVFQjhGIiwKICAgICAgICAgICAgICAgIkNEOCBUZmgiPSIjRTZEMjUzIiwKICAgICAgICAgICAgICAgIk5LVCI9IiM3QkJDREYiLAogICAgICAgICAgICAgICAiQ0Q4IGVmZmVjdC4gbWVtb3J5IiAgPSAgIiNBN0FFOTAiLCAKICAgICAgICAgICAgICAgInVuZGVmaW5lZCI9ICIjRDk4NEQxIikKCm5hbWVzKEwyX2NvbG9ycykgPC0gdW5pcXVlKHBibWNAbWV0YS5kYXRhJENlbGxUeXBlX0wyKQoKYGBgCgojIyBGaWd1cmUgM0EsIEMKYGBge3IgcmhhcHNvZHktdW1hcH0KYXJyIDwtIGxpc3QoeCA9IC0xMywgeSA9IC0xMywgeF9sZW4gPSA1LCB5X2xlbiA9IDUpCgp1bWFwX2F4aXMgPC0gYW5ub3RhdGUoInNlZ21lbnQiLCBsaW5ld2lkdGg9MC4xLAogICAgICAgICAgICAgICAgICAgICAgeCA9IGFyciR4LCB4ZW5kID0gYXJyJHggKyBjKGFyciR4X2xlbiwgMCksIAogICAgICAgICAgICAgICAgICAgICAgeSA9IGFyciR5LCB5ZW5kID0gYXJyJHkgKyBjKDAsIGFyciR5X2xlbiksIAogICAgICAgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGxlbmd0aCA9IHVuaXQoMywgJ3B0JykpKQp1bWFwX2F4aXNfeGxhYiA8LSBhbm5vdGF0ZSgidGV4dCIsIHggPSBhcnIkeCsyLjUsIHkgPSBhcnIkeC0xLCBsYWJlbCA9ICJ3bm5VTUFQIDEiLHNpemU9MSkgCnVtYXBfYXhpc195bGFiIDwtIGFubm90YXRlKCJ0ZXh0IiwgeSA9IGFyciR5KzIuNSwgeCA9IGFyciR5LTEsIGxhYmVsID0gIndublVNQVAgMiIsc2l6ZT0xLGFuZ2xlPTkwKQoKCnJoYXBzb2R5X3VtYXBfY29vcmRzIDwtIGRhdGEudGFibGU6OmRhdGEudGFibGUocGJtY0BtZXRhLmRhdGEsIEVtYmVkZGluZ3Mob2JqZWN0ID0gcGJtYywgcmVkdWN0aW9uID0gJ3dubi51bWFwJykpICU+JSByb3duYW1lc190b19jb2x1bW4oIkNlbGxJRCIpIAoKbGFibGVfZGYgPC0gcmhhcHNvZHlfdW1hcF9jb29yZHMgJT4lCiAgZHBseXI6Omdyb3VwX2J5KENlbGxUeXBlX0wxKSAlPiUKICBkcGx5cjo6c2VsZWN0KENlbGxUeXBlX0wxLCBjb250YWlucygiVU1BUCIpKSAlPiUKICBzdW1tYXJpc2VfYWxsKG1lYW4pCgoocmhhcHNvZHlfdW1hcF9nZ3Bsb3RfbDEgPC0gcmhhcHNvZHlfdW1hcF9jb29yZHMgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gd25uVU1BUF8xLCB5ID0gd25uVU1BUF8yKSkgKyAKICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gYXMuY2hhcmFjdGVyKENlbGxUeXBlX0wxKSksIHNpemUgPSAwLjEsIGFscGhhPS41LCBzaG93LmxlZ2VuZCA9IEYsc2hhcGUgPSAxNikgKwogICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9bGFibGVfZGYsYWVzKHg9d25uVU1BUF8xLHk9d25uVU1BUF8yLCBsYWJlbD1DZWxsVHlwZV9MMSksc2l6ZT0xLjUpICsKICAgICAgICBjb29yZF9maXhlZCgpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1MMV9jb2xvcnMpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICAgICAgICAgICAgICB1bWFwX2F4aXMgKwogICAgICAgICAgICAgICAgdW1hcF9heGlzX3hsYWIgKwogICAgICAgICAgICAgICAgdW1hcF9heGlzX3lsYWIpCgpsYWJsZV9kZiA8LSByaGFwc29keV91bWFwX2Nvb3JkcyAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoQ2VsbFR5cGVfTDIpICU+JQogIGRwbHlyOjpzZWxlY3QoQ2VsbFR5cGVfTDIsIGNvbnRhaW5zKCJVTUFQIikpICU+JQogIHN1bW1hcmlzZV9hbGwobWVhbikKCihyaGFwc29keV91bWFwX2dncGxvdF9sMiA8LSByaGFwc29keV91bWFwX2Nvb3JkcyAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSB3bm5VTUFQXzEsIHkgPSB3bm5VTUFQXzIpKSArIAogICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBhcy5jaGFyYWN0ZXIoQ2VsbFR5cGVfTDIpKSwgc2l6ZSA9IDAuMSwgYWxwaGE9LjUsIHNob3cubGVnZW5kID0gRiwgc2hhcGUgPSAxNikgKyAKICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhPWxhYmxlX2RmLGFlcyh4PXdublVNQVBfMSx5PXdublVNQVBfMiwgbGFiZWw9Q2VsbFR5cGVfTDIpLHNpemU9MS41KSArCiAgICBsYWJzKHggPSAnd25uVU1BUCAxJywgeSA9ICd3bm5VTUFQIDInLCBjb2xvcj1OVUxMKSAgKyAKICAgIGNvb3JkX2ZpeGVkKCkrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPUwyX2NvbG9ycykgKwogICAgdGhlbWVfdm9pZCgpICsKICAgICAgICAgICAgICAgIHVtYXBfYXhpcyArCiAgICAgICAgICAgICAgICB1bWFwX2F4aXNfeGxhYiArCiAgICAgICAgICAgICAgICB1bWFwX2F4aXNfeWxhYikKYGBgCgojIyBGaWd1cmUgM0IKYGBge3J9CnJlcXVpcmUoc2NhbGVzKQoocGVyX3NhbXBsZV9wZXJjX2wxIDwtIHRpYmJsZShwYm1jQG1ldGEuZGF0YSkgJT4lIAogICAgbXV0YXRlKG9yaWcuaWRlbnQgPSBwYXN0ZTAoIlBhdGllbnQiLCIgMCIsTGlicmFyeSkpICU+JSAKICAgIGdyb3VwX2J5KFRpbWUsb3JpZy5pZGVudCkgJT4lIAogICAgY291bnQoQ2VsbFR5cGVfTDEpICU+JSAKICAgICMgU3RhY2tlZCArIHBlcmNlbnQKICAgIGdncGxvdChhZXMoZmlsbCA9IENlbGxUeXBlX0wxLCB5PW4sIHg9b3JpZy5pZGVudCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQ9ImlkZW50aXR5Iix3aWR0aCA9IDAuOSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gTDFfY29sb3JzKSArCiAgICBmYWNldF9ncmlkKH5UaW1lLHNjYWxlcyA9ICJmcmVlX3giKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LGV4cGFuZCA9IGMoMCwwKSkgKyAKICAgIGxhYnMoeCA9ICIiLAogICAgICAgICB5ID0gIkZyZXF1ZW5jeSIsCiAgICAgICAgIGZpbGw9IiIpICsKICAgIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gNikgKwogICAgI3RoZW1lX2Nvd3Bsb3QoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksCiAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpKSkKYGBgCgojIyBGaWd1cmUgM0QKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBibWNfYWN1dGUgPC0gc3Vic2V0KHBibWMsIHN1YnNldD1UaW1lPT0iQWN1dGUiKQoKIy0gUk5BIE5vcm1hbGl6YXRpb24KcGJtY19hY3V0ZSA8LSBOb3JtYWxpemVEYXRhKG9iamVjdCA9IHBibWNfYWN1dGUsIGFzc2F5ID0gJ1JOQScsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gJ0xvZ05vcm1hbGl6ZScsIHNjYWxlLmZhY3RvciA9IDEwMDAwKSAlPiUgU2NhbGVEYXRhKCkKCiMtIEFiIE5vcm1hbGl6YXRpb24KcGJtY19hY3V0ZSA8LSBOb3JtYWxpemVEYXRhKG9iamVjdCA9IHBibWNfYWN1dGUsIGFzc2F5ID0gJ0FEVCcsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gJ0NMUicpICNtYXJnaW4JSWYgcGVyZm9ybWluZyBDTFIgbm9ybWFsaXphdGlvbiwgbm9ybWFsaXplIGFjcm9zcyBmZWF0dXJlcyAoMSkgb3IgY2VsbHMgKDIpCgpgYGAKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyBQc2V1ZG9idWxrIChDZWxsdHlwZSkKCiNodHRwczovL2dpdGh1Yi5jb20vc2F0aWphbGFiL3NldXJhdC9kaXNjdXNzaW9ucy80MjEwCiMjIEF2ZXJhZ2VFeHByZXNzaW9uCklkZW50cyhwYm1jX2FjdXRlKSA8LSAiQ2VsbFR5cGVfTDIiCgojIyBjYWxjdWxhdGlvbiBvZiBwc2V1ZG9idWxrLCBmb3IgZWFjaCBpZGVudGl0eSBiYXNlZCBvbiBjb3VudCBkYXRhCnBibWNfYWN1dGUuYXZnLndpZGUgPC0gbG9nMXAoU2V1cmF0OjpBdmVyYWdlRXhwcmVzc2lvbihwYm1jX2FjdXRlLCBncm91cC5ieSA9ICJDZWxsVHlwZV9MMiIsIHNsb3QgPSAiY291bnRzIiwgdmVyYm9zZSA9IEZBTFNFKSRSTkEpICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiZ2VuZSIpIAoKY29sbmFtZXMocGJtY19hY3V0ZS5hdmcud2lkZSkgPC0gYygiZ2VuZSIsY29sbmFtZXMoU2V1cmF0OjpBdmVyYWdlRXhwcmVzc2lvbihwYm1jX2FjdXRlLCBncm91cC5ieSA9ICJDZWxsVHlwZV9MMiIsIHNsb3QgPSAiY291bnRzIiwgdmVyYm9zZSA9IEZBTFNFKSRSTkEpKQoKcGJtY19hY3V0ZS5hdmcubG9uZyA8LSBwYm1jX2FjdXRlLmF2Zy53aWRlICU+JSBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAiY2VsbHR5cGUiLCB2YWx1ZXNfdG8gPSAiYXZnRXhwIixjb2xzID0gLWdlbmUpCmBgYAoKCk1hcHBpbmcgKGdlbmUgLSBwcm90ZWluKQoKYGBge3J9CiMjIG1hcHBpbmcgCmZ1bGxfbWFwcGluZyA8LSBtYXBwaW5nX3VuaXByb3RfZW5zZW1ibCAlPiUgbGVmdF9qb2luKGhwYV8yNC4wLCBieT1jKCJFbnNlbWJsIj0iZW5zZW1ibCIpKQoKd2lsY294VXAgPC0gZGFwLnJlcyAlPiUgZmlsdGVyKEZEUj09VFJVRSxsb2dGQz4xKSAlPiUgcHVsbChVbmlQcm90KQoKZ2VuZS5zZWxlY3Rpb24gPC0gZnVsbF9tYXBwaW5nICU+JSAKICBmaWx0ZXIoVW5pUHJvdCAlaW4lIHdpbGNveFVwKSAlPiUgCiAgZmlsdGVyKFN5bWJvbCAlaW4lIHJuYS5tYXJrZXJzKSAlPiUgZGlzdGluY3QoQXNzYXkpICU+JSBwdWxsKEFzc2F5KQpgYGAKCiMjIEZpZ3VyZSAzRApIZWF0bWFwIGdlbmVzIGV4cHJlc3Npb24KCmBgYHtyIGhtLWFjdXRlLWdleC13aWRlfQpyaGFwc29keS5nZW5lLm1hdGNoIDwtIGZ1bGxfbWFwcGluZyAlPiUgCiAgZmlsdGVyKFVuaVByb3QgJWluJSB3aWxjb3hVcCkgJT4lIAogIGZpbHRlcihTeW1ib2wgJWluJSB1bmlxdWUocGJtY19hY3V0ZS5hdmcud2lkZSRnZW5lKSkKCiMjIG1ha2UgbWF0cml4IGZvciBoZWF0bWFwCm1hdF9wYm1jX2FjdXRlIDwtIHBibWNfYWN1dGUuYXZnLndpZGUgJT4lIAogIGZpbHRlcihnZW5lICVpbiUgcmhhcHNvZHkuZ2VuZS5tYXRjaCRTeW1ib2wpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoImdlbmUiKSAlPiUgCiAgYXMubWF0cml4KCkgCgojIyBtYWtlIHJvdyhnZW5lL3Byb3RlaW4pIGFubm90YXRpb24gZGYKcm93QW5uby5kZiA8LSBkYXRhLmZyYW1lKEFzc2F5ID0gcm93bmFtZXMobWF0X3BibWNfYWN1dGUpKSAlPiUgCiAgbGVmdF9qb2luKGRhcC5yZXMsYnk9YygiQXNzYXkiKSkgJT4lIAogICNsZWZ0X2pvaW4oaHBhXzI0LjAsYnk9YygiQXNzYXkiPSJnZW5lIikpICU+JSAKICAgIGxlZnRfam9pbihocGFfMjQuMCxieT1jKCJVbmlQcm90Ij0idW5pcHJvdCIpKSAlPiUgCgogIG11dGF0ZShzZWNyZXRvbWVfZnVuY3Rpb24gPSBpZmVsc2UoaXMubmEoc2VjcmV0b21lX2Z1bmN0aW9uKSwiTm8gYW5ub3RhdGVkIGZ1bmN0aW9uIiwgc2VjcmV0b21lX2Z1bmN0aW9uKSkKICAKCmNvbC5hbm5vLmRmIDwtIGRhdGEuZnJhbWUoY29sbmFtZXMgPSBjb2xuYW1lcyhtYXRfcGJtY19hY3V0ZSkpICU+JSAKICB0cmFuc211dGUoY29sbmFtZXMsCiAgICAgICAgICAgIGNvbGFubm8gPSBjYXNlX3doZW4oZ3JlcGwoIkRDIixjb2xuYW1lcykgfiAiREMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJtb25vY3l0ZXMiLGNvbG5hbWVzKSB+ICJNb25vY3l0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJDRDQiLGNvbG5hbWVzKSB+ICJDRDQrIFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJDRDgiLGNvbG5hbWVzKSB+ICJDRDgrIFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJCfFBsYXNtYSIsY29sbmFtZXMpIH4gIkIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJOSyIsY29sbmFtZXMpIH4gIk5LIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiZ2RUIixjb2xuYW1lcykgfiAiZ2RUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9ICJ1bmRlZmluZWQiKSwKICAgICAgICAgICAgY29sYW5ubyA9IGZhY3Rvcihjb2xhbm5vLCBsZXZlbHM9IGMoIkRDIiwiTW9ub2N5dGVzIiwiTksiLCJnZFQiLCJCIiwiQ0Q0KyBUIiwiQ0Q4KyBUIiwidW5kZWZpbmVkIikpKQoKCnJpZ2h0LmFubm8gPC0gSGVhdG1hcEFubm90YXRpb24oZGYgPSBjb2wuYW5uby5kZiAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJjb2xuYW1lcyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaCA9ICJyb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3QoY29sYW5ubyA9IEwxX2NvbG9ycyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBuYW1lID0gIlNORiBjbHVzdGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2Fubm90YXRpb25fbmFtZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19sZWdlbmQgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sZWdlbmRfcGFyYW0gPSBsaXN0KGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2hlaWdodCA9IHVuaXQoLjEsICJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCguMiwgImNtIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDEsICJtbSIpKQoKdG9wLmFubm8gPC0gIEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gcm93QW5uby5kZiAlPiUgdHJhbnNtdXRlKEFzc2F5LCBzZWNyZXRvbWVfbG9jYXRpb24pICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoIkFzc2F5IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaCA9ICJjb2x1bW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19sZWdlbmQgPSBjKFRSVUUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfYW5ub3RhdGlvbl9uYW1lID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGUgPSAiSFBBXG5jbGFzc2lmaWNhdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCgzLCAibW0iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JpZF93aWR0aCA9IHVuaXQoMywgIm1tIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChzZWNyZXRvbWVfbG9jYXRpb24gPSBjKHNlY3JldG9tZV9sb2NhdGlvbl9jb2xzKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaW1wbGVfYW5ub19zaXplID0gdW5pdCgzLCAibW0iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFfY29sID0gImdyZXk5MCIpCgojIyBnZXR0aW5nIGZvbGRjaGFuZ2UgKGROUFggb3ZlciBtZWRpYW4gY29udmFsZXNjZW5jZSkgCm0gPC0gZmNfb3Zlcl9tZWRpYW5fTTEyICU+JQogIGZpbHRlcihBc3NheSAlaW4lIHJvd0Fubm8uZGYkQXNzYXkpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQXNzYXksIHZhbHVlc19mcm9tID0gZE5QWCxpZF9jb2xzID0gc3R1ZHlfaWQpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoInN0dWR5X2lkIikgJT4lIAogIGFzLm1hdHJpeCgpICU+JSB0KCkKCm0gPC0gbVtyb3duYW1lcyhtYXRfcGJtY19hY3V0ZSksXQoKCmJvdHRvbS5hbm5vIDwtIEhlYXRtYXBBbm5vdGF0aW9uKCJQbGFzbWEgcHJvdGVpblxuZE5QWCIgPSBhbm5vX2JveHBsb3QodChtKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSB1bml0KDEuNSwgImNtIiksd2lkdGggPSB1bml0KDEuNSwiY20iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfd2lkdGggPSAwLjgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpc19wYXJhbSA9IGxpc3Qoc2lkZSA9ICJyaWdodCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX3JvdCA9IDQ1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwPWdwYXIoZm9udHNpemUgPSA1KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3AgPSBncGFyKGZpbGw9IiNDNTFCN0QiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRsaW5lID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfcm90ID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9uYW1lX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfc2lkZSA9ICJyaWdodCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDMsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaCA9ICJjb2x1bW4iKQoKCgoocGJtY19sMl9hY3V0ZV9obS53aWRlIDwtIG1hdF9wYm1jX2FjdXRlW3Jvd25hbWVzKG0pLF0gJT4lIAogICAgdCgpICU+JSAKICAgICMjIHNjYWxlIHZhbHVlcyBmcm9tIDAtMQogICAgYXMuZGF0YS5mcmFtZSgpICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHNjYWxlczo6cmVzY2FsZSguLCB0bz1jKDAsMSkpKSkgJT4lIAogICAgYXMubWF0cml4KCkgJT4lIAogICAgQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAoCiAgICAgIG5hbWU9ImF2ZXJhZ2VcbmdlbmVcbmV4cHJlc3Npb24iLAogICAgICBjb2wgPSBzY2FsZWRfMDFfY29sLAogICAgICAKICAgICAgdG9wX2Fubm90YXRpb24gPSB0b3AuYW5ubywKICAgICAgYm90dG9tX2Fubm90YXRpb24gPSBib3R0b20uYW5ubywKICAgICAgcmlnaHRfYW5ub3RhdGlvbiA9ICByaWdodC5hbm5vLAogICAgICBjb2x1bW5fZGVuZF9oZWlnaHQgPSB1bml0KDIsICJtbSIpLAogICAgICBjbHVzdGVyX3Jvd3MgPSBGLAogICAgICByb3dfZGVuZF9yZW9yZGVyID0gVFJVRSwKICAgICAgc2hvd19yb3dfbmFtZXMgPSBUUlVFLAogICAgICBjb2x1bW5fc3BsaXQgPSByb3dBbm5vLmRmJHNlY3JldG9tZV9mdW5jdGlvbiwKICAgICAgY29sdW1uX2RlbmRfcmVvcmRlciA9IEYsCiAgICAgIHJvd190aXRsZV9zaWRlID0gInJpZ2h0IiwKICAgICAgcm93X3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICBjbHVzdGVyX2NvbHVtbnMgPSBULAogICAgICByb3dfc3BsaXQgPSBjb2wuYW5uby5kZiRjb2xhbm5vLAogICAgICByb3dfdGl0bGUgPSBOVUxMLAogICAgICAKICAgICAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT00KSwKICAgICAgY29sdW1uX3RpdGxlX3JvdCA9IDQ1LAogICAgICByb3dfdGl0bGVfcm90ID0gMCwKICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDQpLAogICAgICAjcm93X2RlbmRfd2lkdGggPSB1bml0KDIsICJtbSIpLCAKICAgICAgcm93X2RlbmRfc2lkZSA9ICJsZWZ0IiwKICAgICAgY2x1c3Rlcl9yb3dfc2xpY2VzID0gVCwKICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDQpLCAKICAgICAgY29sdW1uX25hbWVzX3JvdCA9IDkwLAogICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCgzLCAibW0iKSksCiAgICApIAogICkKYGBgCgoKCiMjIEZpZ3VyZSAzRQpDZWxsUGhvbmVEQgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2NwZGIucHJvdGVpbl9pbnB1dCA8LSByZWFkX2RlbGltKCIuLi9kYXRhL2NlbGxwaG9uZURCL3Y0LjEuMF9wcm90ZWluX2lucHV0LmNzdiIpCiNjcGRiLmludGVyYWN0aW9uX2lucHV0IDwtIHJlYWRfZGVsaW0oIi4uL2RhdGEvY2VsbHBob25lREIvdjQuMS4wX2ludGVyYWN0aW9uX2lucHV0LmNzdiIpCgpjcGRiLnByb3RlaW5faW5wdXQgPC0gcmVhZF9kZWxpbSgiLi4vZGF0YS9jZWxscGhvbmVEQi92NV9wcm90ZWluX2lucHV0LmNzdiIsKQpjcGRiLmludGVyYWN0aW9uX2lucHV0IDwtIHJlYWRfZGVsaW0oIi4uL2RhdGEvY2VsbHBob25lREIvdjVfaW50ZXJhY3Rpb25faW5wdXQuY3N2IikKCmtlZ2cuY2NyIDwtIHJlYWRfZXhjZWwoIi4uL2RhdGEvS0VHR19DeXRva2luZUN5dG9raW5lUmVjZXB0b3JJbnRlcmFjdGlvbl9tYWxhcmlhc3BlYy54bHN4IikgJT4lIG11dGF0ZShTb3VyY2UgPSAiS0VHRyIpCmBgYAoKYGBge3J9CnJuYS5tYXJrZXJzLnVuaXByb3QgPC0gZGF0YS5mcmFtZShnZW5lID0gcm5hLm1hcmtlcnMpICU+JSAKICBsZWZ0X2pvaW4oaHBhXzI0LjAgJT4lIHRyYW5zbXV0ZShnZW5lLCB1bmlwcm90KSkgJT4lIG5hLm9taXQoKQpgYGAKCmBgYHtyfQpsaWdhbmQucSA8LSBkYXAucmVzICU+JSBmaWx0ZXIocC5hZGogPD0wLjAxLCBsb2dGQyA+IC4xKSAlPiUgCiAgbGVmdF9qb2luKGNwZGIucHJvdGVpbl9pbnB1dCwKICAgICAgICAgICAgYnk9YygiVW5pUHJvdCI9InVuaXByb3QiKSkgJT4lIAogIHB1bGwoVW5pUHJvdCkKCmxlbmd0aChsaWdhbmQucSkKCm53IDwtIGNwZGIuaW50ZXJhY3Rpb25faW5wdXQgJT4lIAogIGZpbHRlcihwYXJ0bmVyX2EgJWluJSBsaWdhbmQucSwKICAgICAgICAgZGlyZWN0aW9uYWxpdHkgPT0gIkxpZ2FuZC1SZWNlcHRvciIpICU+JSAKICBtdXRhdGUocHJvdGVpbl9uYW1lX2Jfc3RyaXAgPSBnc3ViKCJfSFVNQU4iLCIiLHByb3RlaW5fbmFtZV9iKSwKICAgICAgICAgcHJvdGVpbl9uYW1lX2EgPSBnc3ViKCJfSFVNQU4iLCIiLHByb3RlaW5fbmFtZV9hKSkgJT4lIAogIG11dGF0ZShwcm90ZWluX25hbWVfYl9jb21wbGV4ID0gY2FzZV93aGVuKGlzLm5hKHByb3RlaW5fbmFtZV9iKSB+IHN0cl9yZW1vdmUoaW50ZXJhY3RvcnMscGFzdGUwKHByb3RlaW5fbmFtZV9hLCItIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHByb3RlaW5fbmFtZV9iKSkgJT4lCiAgIHNlcGFyYXRlX2xvbmdlcl9kZWxpbShwcm90ZWluX25hbWVfYl9jb21wbGV4LCBkZWxpbSA9ICIrIikgJT4lIAogICBsZWZ0X2pvaW4oaHBhXzI0LjAgJT4lIHRyYW5zbXV0ZShwcm90ZWluX25hbWVfYl9jb21wbGV4ID0gZ2VuZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlwcm90X2JfY29tcGxleCA9IHVuaXByb3QpLCBieT1jKCJwcm90ZWluX25hbWVfYl9jb21wbGV4IikpICU+JSAKICBtdXRhdGUocHJvdGVpbl9uYW1lX2IgPSBjYXNlX3doZW4oaXMubmEocHJvdGVpbl9uYW1lX2IpIH4gcHJvdGVpbl9uYW1lX2JfY29tcGxleCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gcHJvdGVpbl9uYW1lX2IpLAogICAgICAgICBwYXJ0bmVyX2JfbmV3ID0gY2FzZV93aGVuKGlzLm5hKHVuaXByb3RfYl9jb21wbGV4KSB+IHBhcnRuZXJfYiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHVuaXByb3RfYl9jb21wbGV4KSkgJT4lIAogIHRyYW5zbXV0ZShwYXJ0bmVyX2EsIHBhcnRuZXJfYiwgcGFydG5lcl9iX25ldykgJT4lIAogIGZpbHRlcihwYXJ0bmVyX2JfbmV3ICVpbiUgcm5hLm1hcmtlcnMudW5pcHJvdCR1bmlwcm90KSAlPiUgCiAgbXV0YXRlKHVuaXByb3RfYSA9IHBhcnRuZXJfYSwKICAgICAgICAgdW5pcHJvdF9iID0gcGFydG5lcl9iX25ldykKYGBgCgpgYGB7cn0KbWVhc3VyZWQuaW4ucGxhc21hIDwtIGRhcC5yZXMgJT4lIGZpbHRlcihwLmFkaiA8PTAuMDEsIGxvZ0ZDID4gMC4xKSAlPiUgcHVsbChVbmlQcm90KQptZWFzdXJlZC5pbi5wbGFzbWEubmFtZSA8LSBkYXAucmVzICU+JSBmaWx0ZXIocC5hZGogPD0wLjAxLCBsb2dGQyA+IC4xKSAlPiUgcHVsbChBc3NheSkKCkcgPC0gYXNfdGJsX2dyYXBoKG53ICU+JSB0cmFuc211dGUoZnJvbSA9IHVuaXByb3RfYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0byA9IHVuaXByb3RfYikpCm5vZGVfdGFibGUgPC0gYXNfdGliYmxlKEcpICU+JSAKICBsZWZ0X2pvaW4oZGFwLnJlcyAlPiUgbXV0YXRlKG1lYXN1cmVkLmFzLnNvbHVibGUgPSBUKSwKICAgICAgICAgICAgYnk9YygibmFtZSI9IlVuaVByb3QiKSkgJT4lIAogIGxlZnRfam9pbihocGFfMjQuMCAlPiUgdHJhbnNtdXRlKGdlbmUsIHVuaXByb3QpLCAKICAgICAgICAgICAgYnk9YygibmFtZSI9InVuaXByb3QiKSkgJT4lIAogIG11dGF0ZShwcm90ZWluX25hbWUgPSBnZW5lLAogICAgICAgICBtZWFzdXJlZC5hcy5zb2x1YmxlID0gY2FzZV93aGVuKGlzLm5hKG1lYXN1cmVkLmFzLnNvbHVibGUpIH5GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gVCkpIyAlPiUKYGBgCgpgYGB7cn0KKGxpZ2FuZF9yZWNlcHRvcl9udyA8LSBHICU+JSAKICAgaW5uZXJfam9pbihub2RlX3RhYmxlLGJ5PSJuYW1lIikgJT4lIAogICBjcmVhdGVfbGF5b3V0KGxheW91dCA9ICJmciIpICU+JSAKICAgZ2dyYXBoKCkgKyAKICAgZ2VvbV9lZGdlX2xpbmsoYWxwaGE9LjAyKSArIAogICBnZW9tX2VkZ2VfZmFuKHdpZHRoID0gLjUsIGNvbG9yID0gImdyZXk5MCIpICsKICAgZ2VvbV9ub2RlX3BvaW50KGFlcyhjb2xvcj1pZl9lbHNlKG1lYXN1cmVkLmFzLnNvbHVibGU9PVQsbG9nRkMsTkEpLAogICAgICAgICAgICAgICAgICAgICAgIHNpemU9IGlmX2Vsc2UobWVhc3VyZWQuYXMuc29sdWJsZT09VCxsb2dGQywxKSkpICsKICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMywgYmFyaGVpZ2h0ID0gLjc1KSwKICAgICAgICAgIHNpemU9RikgKwogICBsYWJzKGNvbG9yPSJsb2dGQyBvZiBwcm90ZWluc1xuaW4gcGxhc21hIikgKwogICBzY2FsZV9zaXplKHJhbmdlPWMoMSwzLjUpKSArCiAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IHByb3RlaW5fbmFtZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSBpZl9lbHNlKG1lYXN1cmVkLmFzLnNvbHVibGU9PVQsbG9nRkMsTkEpKSwKICAgICAgICAgICAgICAgICAgc2l6ZT0xLCAKICAgICAgICAgICAgICAgICAgcmVwZWw9VCkgKwogICBzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdz0idGhpc3RsZTIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2g9ImRhcmtyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZT0iY29sb3JiYXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlPSJncmV5MjAiKSArCiAgIHRoZW1lX3ZvaWQoKSArCiAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCggc2l6ZT02KSwKICAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NikpIAopCmBgYAoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnJlY2VwdG9yX2ZhbSA8LSBsaXN0KGN4Y19zdWJmYW0gPSBjKCJDWENSMSIsIkNYQ1IyIiwiQ1hDUjMiLCJDWENSNCIsIkNYQ1I1IiwiQ1hDUjYiLCJDWENSNyIsIlhDUjEiLCJDWDNDUjEiKSwKICAgICAgICAgICAgICAgICAgICAgY2Nfc3ViZmFtID0gcGFzdGUwKCJDQ1IiLDE6MTEpLAogICAgICAgICAgICAgICAgICAgICBjbGFzczFoZWxpY2FsY3l0b19mYW0gPSBjKCJJTDJSQSIsIklMNFIiKSwKICAgICAgICAgICAgICAgICAgICAgY2xhc3MyaGVsaWNhbGN5dG9fZmFtID0gYygiSUwxMFJBIiwiSUwxMFJCIiksCiAgICAgICAgICAgICAgICAgICAgIHByb2xhY3Rpb25fZmFtID0gYygiR0hSIiwiQ1NGM1IiKSwKICAgICAgICAgICAgICAgICAgICAgaWZuX2ZhbSA9YygiSUZOQVIxIiwiSUZOQVIyIiwiSUZOR1IxIiwiSUZOR1IyIiksCiAgICAgICAgICAgICAgICAgICAgIGlsMWxpa2VjeXRvX2ZhbSA9IGMoIklMMVIxIiwiSUwxUkFQIiwiSUwxUjIiLCJJTDE4UjEiLCJJTDE4UkFQIiwiU1QyIiwiSUwxUkFQIiksCiAgICAgICAgICAgICAgICAgICAgIG5vbmNsYXNzaWZpZWQgPSBjKCJDRDQiLCJDU0YxUiIpLAogICAgICAgICAgICAgICAgICAgICB0bmZfZmFtID0gYygiVE5GUjEiLCJUTkZSMiIsIkhWRU0iLCJGQVMiLCJEUjQiLCJEUjUiLCJEQ1IxIiwiRENSMiIsIkVEQVIiLCJSQU5LIiwiQ0QyNyIsIkNEMzAiLCJDRDQwIiwiT3g0MCIsIlRBQ0kiKSwKICAgICAgICAgICAgICAgICAgICAgdGdmYl9mYW0gPSBjKCJUR0ZCUjIiLCJBQ1ZSMkIiLCJBQ1ZSMUIiKSkgJT4lIAogIGVuZnJhbWUoKSAlPiUgdW5uZXN0KGNvbHMgPSBjKHZhbHVlKSkgJT4lIGRwbHlyOjpyZW5hbWUoc3ViZmFtID0gbmFtZSwgcmVjZXB0b3IgPSB2YWx1ZSkKYGBgCgoKYGBge3J9CiNleHRyYWN0IGFsbCB0cmFuc21lbWJyYW5lIHJlY2VwdG9ycyBmcm9tIENlbGxQaG9uZURCIGFzIHVuaXByb3RJRHMKCiMjIGZpbHRlciBDZWxsUGhvbmVEQiBwcm90ZWluX2lucHV0IGZvciB0cmFuc21lbWJyYW5lICYgcmVjZXB0b3JzCmNwZGIucmVjZXB0b3IudHJhbnNtZW0ubmFtZSA8LSBjcGRiLnByb3RlaW5faW5wdXQgJT4lIGZpbHRlcih0cmFuc21lbWJyYW5lPT1UIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZXB0b3I9PVQpICU+JSAKICBtdXRhdGUocHJvdGVpbl9uYW1lID0gZ3N1YigiX0hVTUFOIiwiIixwcm90ZWluX25hbWUpKSAlPiUgCiAgcHVsbCh1bmlwcm90KQpgYGAKCgpgYGB7cn0KZGYgPC0gcGJtY19hY3V0ZS5hdmcud2lkZSAlPiUgCiAgcmlnaHRfam9pbihybmEubWFya2Vycy51bmlwcm90KSAlPiUgCiAgZmlsdGVyKHVuaXByb3QgJWluJSBudyR1bmlwcm90X2IpCgpnZW5lQW5ubyA8LSBkZiAlPiUgdHJhbnNtdXRlKGdlbmUsdW5pcHJvdCkgJT4lIGxlZnRfam9pbihyZWNlcHRvcl9mYW0sYnk9YygiZ2VuZSI9InJlY2VwdG9yIikpICU+JQogIG11dGF0ZShzdWJmYW0gPSBpZmVsc2UoaXMubmEoc3ViZmFtKSwiT3RoZXIiLHN1YmZhbSksCiAgICAgICAgIENQREIgPSBpZmVsc2UodW5pcHJvdCAlaW4lIGNwZGIucmVjZXB0b3IudHJhbnNtZW0ubmFtZSxULEYpLAogICAgICAgICBLRUdHID0gaWZlbHNlKGdlbmUgJWluJSByZWNlcHRvcl9mYW0kcmVjZXB0b3IsVCxGKSwKICAgICAgICAgaW5fcGxhc21hID0gaWZlbHNlKGdlbmUgJWluJSBtZWFzdXJlZC5pbi5wbGFzbWEubmFtZSxULEYpKQoKCm1hdCA8LSBkZiAlPiUgCiAgZHBseXI6OnNlbGVjdCgtdW5pcHJvdCkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygiZ2VuZSIpICU+JSAKICBhcy5tYXRyaXgoKQoKY29sLmFubm8uZGYgPC0gZGF0YS5mcmFtZShjb2xuYW1lcyA9IGNvbG5hbWVzKG1hdCkpICU+JSAKICB0cmFuc211dGUoY29sbmFtZXMsCiAgICAgICAgICAgIGNvbGFubm8gPSBjYXNlX3doZW4oZ3JlcGwoIkRDIixjb2xuYW1lcykgfiAiREMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJtb25vY3l0ZXMiLGNvbG5hbWVzKSB+ICJNb25vY3l0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJDRDQiLGNvbG5hbWVzKSB+ICJDRDQrIFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJDRDgiLGNvbG5hbWVzKSB+ICJDRDgrIFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJCfFBsYXNtYSIsY29sbmFtZXMpIH4gIkIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJOSyIsY29sbmFtZXMpIH4gIk5LIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiZ2RUIixjb2xuYW1lcykgfiAiZ2RUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9ICJ1bmRlZmluZWQiKSwKICAgICAgICAgICAgY29sYW5ubyA9IGZhY3Rvcihjb2xhbm5vLCBsZXZlbHM9IGMoIkRDIiwiTW9ub2N5dGVzIiwiTksiLCJnZFQiLCJCIiwiQ0Q0KyBUIiwiQ0Q4KyBUIiwidW5kZWZpbmVkIikpKQoKY29sQW5uLnRvcCA8LSBIZWF0bWFwQW5ub3RhdGlvbihkZiA9IGNvbC5hbm5vLmRmICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoImNvbG5hbWVzIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gImNvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChjb2xhbm5vID0gTDFfY29sb3JzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2Fubm90YXRpb25fbmFtZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19sZWdlbmQgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sZWdlbmRfcGFyYW0gPSBsaXN0KGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2hlaWdodCA9IHVuaXQoLjEsICJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCguMiwgImNtIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDEsICJtbSIpCikKYGBgCgojIyBGaWd1cmUgM0YKYGBge3IgaG0tYWN1dGUtcmVjZXB0b3ItZ2V4LXdpZGV9Cm0gPC0gIG1hdCAlPiUgCiAgdCgpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gc2NhbGVzOjpyZXNjYWxlKC4sIHRvPWMoMCwxKSkpKSAlPiUgCiAgYXMubWF0cml4KCkgCgoocGJtY19sMl9hY3V0ZV9jZWxscGhvbmVkYl9obS53aWRlIDwtIG0gJT4lIAogICBDb21wbGV4SGVhdG1hcDo6SGVhdG1hcChuYW1lPSJhdmVyYWdlXG5nZW5lXG5leHByZXNzaW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX3NwbGl0ID0gZ2VuZUFubm8kc3ViZmFtLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5fc2xpY2VzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYm90dG9tX2Fubm90YXRpb24gPSBIZWF0bWFwQW5ub3RhdGlvbihkZj1nZW5lQW5ubyAlPiUgdHJhbnNtdXRlKGluX3BsYXNtYSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2g9ImNvbHVtbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sZWdlbmRfcGFyYW0gPSBsaXN0KHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoMS41LCAibW0iKSxuYV9jb2wgPSBjKCJ3aGl0ZSIsIndoaXRlIiwid2hpdGUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2xlZ2VuZCA9IGMoRkFMU0UsRkFMU0UsRkFMU0UpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwID0gZ3Bhcihjb2wgPSAiZ3JleTkwIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sPWxpc3QoQ1BEQiA9IGMoIlRSVUUiID0gImdyZXk2MCIsICJGQUxTRSIgPSAid2hpdGUiLCJOQSIgPSAid2hpdGUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBLRUdHID0gYygiVFJVRSIgPSAiZ3JleTYwIiwgIkZBTFNFIiA9ICJ3aGl0ZSIsIk5BIiA9ICJ3aGl0ZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluX3BsYXNtYSA9IGMoIlRSVUUiID0gImRhcmtyZWQiLCAiRkFMU0UiID0gIndoaXRlIiwiTkEiID0gIndoaXRlIikpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19yb3dfZGVuZCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd190aXRsZV9zaWRlID0gInJpZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3RpdGxlX3JvdCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd190aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3RpdGxlID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gc2NhbGVkXzAxX2NvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX2RlbmRfaGVpZ2h0ID0gdW5pdCgyLCJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfZGVuZF93aWR0aCA9IHVuaXQoMiwgIm1tIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfZGVuZF9zaWRlID0gImxlZnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZF9jb2x1bW5zID0gIm1jcXVpdHR5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHRfYW5ub3RhdGlvbiA9IHJvd0Fubm90YXRpb24oZGYgPSBjb2wuYW5uby5kZiAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJjb2xuYW1lcyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3QoY29sYW5ubyA9IEwxX2NvbG9ycyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfYW5ub3RhdGlvbl9uYW1lID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19sZWdlbmQgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCguMSwgImNtIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCguMiwgImNtIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaW1wbGVfYW5ub19zaXplID0gdW5pdCgxLCAibW0iKQogICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfc3BsaXQgPSBjb2wuYW5uby5kZiRjb2xhbm5vLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fdGl0bGVfcm90ID0gNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA0KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JpZF93aWR0aCA9IHVuaXQoMywgIm1tIikpKQopCgpgYGAKCgoKIyMgU3VwcGxlbWFudGFyeSBGaWd1cmUgUzYgCioqcmVsYXRlZCB0byBtYWluIEZpZ3VyZSAzKioKCiMjIyBGaWd1cmUgUzZBCmBgYHtyfQoocmhhcHNvZHlfY2VsbHNfcGVyX3NhbXBsZSA8LSB0aWJibGUocGJtY0BtZXRhLmRhdGEpICU+JQogICNhcy5kYXRhLnRhYmxlICU+JSAjIHRoZSByZXN1bHRpbmcgbWQgb2JqZWN0IGhhcyBvbmUgInJvdyIgcGVyIGNlbGwKICByb3duYW1lc190b19jb2x1bW4oIkNlbGxJRCIpICAlPiUgCiAgZ3JvdXBfYnkob3JpZy5pZGVudCxUaW1lKSAlPiUgCiAgZHBseXI6OmNvdW50KCkgJT4lIAogIGdncGxvdChhZXMoeD1vcmlnLmlkZW50LHk9biwgZmlsbD1UaW1lKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IFRJTUVfY29sb3JzLGJyZWFrcyA9IGMoIkFjdXRlIiwiRDEwIiwiWTEiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIHRyYW5zID0gInNxcnQiKSArCiAgY29vcmRfZmxpcCgpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImRvZGdlIiwgc2hvdy5sZWdlbmQgPSBUUlVFKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTYwMDAsbHdkPS4yKSArCiAgbGFicyh5PSJOdW1iZXIgb2YgY2VsbHMiLAogICAgICAgeD0iIiwKICAgICAgIGZpbGw9IiIpICsgCiAgdGhlbWVfbWluaW1hbCgpKQpgYGAKCiMjIyBGaWd1cmUgUzZCCmBgYHtyfQojIyBpbnRlZ3JhdGlvbgoocmhhcHNvZHlfdW1hcF9nZ3Bsb3RfaW50X29yaWcuaWRlbnQgPC0gcmhhcHNvZHlfdW1hcF9jb29yZHMgJT4lIAogIGdncGxvdChhZXMoeCA9IHdublVNQVBfMSwgeSA9IHdublVNQVBfMikpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBhcy5jaGFyYWN0ZXIob3JpZy5pZGVudCkpLCBzaXplID0gMC4xLCBhbHBoYT0uMSkgKwogIGxhYnMoeCA9ICd3bm5VTUFQIDEnLCB5ID0gJ3dublVNQVAgMicsIGNvbG9yPU5VTEwpICArIAogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhID0gMSxzaXplPS4yNSkpKSArCiAgbXlfZGltcmVkX3RoZW1lCikKYGBgCgojIyMgRmlndXJlIFM2QwpgYGB7ciB9CiMjIGludGVncmF0aW9uCihyaGFwc29keV91bWFwX2dncGxvdF9pbnRfdGltZSA8LSByaGFwc29keV91bWFwX2Nvb3JkcyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gd25uVU1BUF8xLCB5ID0gd25uVU1BUF8yKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGFzLmNoYXJhY3RlcihUaW1lKSksIHNpemUgPSAwLjI1LCBhbHBoYT0uMSkgKwogIGxhYnMoeCA9ICd3bm5VTUFQIDEnLCB5ID0gJ3dublVNQVAgMicsIGNvbG9yPU5VTEwpICArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBUSU1FX2NvbG9ycyxicmVha3MgPSBjKCJBY3V0ZSIsIkQxMCIsIlkxIikpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYSA9IDEsc2l6ZT0uMjUpKSkgKwogIG15X2RpbXJlZF90aGVtZQopCmBgYAoKIyMjIEZpZ3VyZSBTNkQKYGBge3J9Cih2bG5fYWR0LndlaWdodCA8LSBWbG5QbG90KHBibWMsIGZlYXR1cmVzID0gImFkdC5DQ0Eud2VpZ2h0IiwgZ3JvdXAuYnkgPSAnQ2VsbFR5cGVfTDInLCBjb2xzID0gTDJfY29sb3JzLCBzb3J0ID0gVFJVRSwgcHQuc2l6ZSA9IDApICsKICBOb0xlZ2VuZCgpICsgCiAgbGFicyh0aXRsZSA9ICJhZHQgd2VpZ2h0IiwgeT0iQURUIHdlaWdodCIseD1OVUxMKSkKYGBgCgojIyMgRmlndXJlIFM2RQpgYGB7cn0Kcm5hLm1hcmtlcjRkb3RwbG90IDwtIGMoIlMxMDBBMTIiLCJDRDE0IiwiUzEwMEE5IiwiVk1PMSIsIkMxUUEiLCJGQ0dSM0EiLCAiS0xSRjEiLCJLSVIyREwxIiwKICAgICAgICAgICAgICAgICAgICAgICAgIkdOTFkiLCJJTDEyUkIyIiwiSUwxOFIxIiwiR1pNSyIsIlRZTVMiLCJUT1AyQSIsICJLSUFBMDEwMSIsIkNDUjciLCJMRUYxIiwKICAgICAgICAgICAgICAgICAgICAgICAgIk1ZQyIsICJQQVNLIiwiQ0QyOCIsIklDT1MiLCJSR1MxIiwiQ1RMQTQiLCJDQ1I1IiwiTEFHMyIsIlBPVTJBRjEiLAogICAgICAgICAgICAgICAgICAgICAgICAiRk9YUDMiLCJJTDJSQSIsIkNEOEEiLCJaTkY2ODMiLCJST1JDIiwiSUtaRjIiLCJNUzRBMSIsIkNENzlBIiwiSUdLQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICJUQ0wxQSIsIkZDRVIyIiwiQ0QyMDAiLCJUTkZSU0YxNyIsIkZDRVIxQSIsIkNMRUMxMEEiLCJDRDFDIiwiTlJQMSIsIlRMUjkiLCJUTFI3IikKCihkb3RwbG90LnJuYSA8LSBEb3RQbG90KHBibWMsCiAgICAgICAgZmVhdHVyZXMgPSBybmEubWFya2VyNGRvdHBsb3QsCiAgICAgICAgYXNzYXkgPSAiUk5BIiwKICAgICAgICBjb2xzID0gYygiUmRZbEJ1IiksCiAgICAgICAgY29sLm1pbiA9IC0yLjUsCiAgICAgICAgY29sLm1heCA9IDIuNSwKICAgICAgICBkb3QubWluID0gMCwKICAgICAgICBkb3Quc2NhbGUgPSAxLAogICAgICAgIGlkZW50cyA9IE5VTEwsCiAgICAgICAgZ3JvdXAuYnkgPSBOVUxMLAogICAgICAgIHNwbGl0LmJ5ID0gTlVMTCwKICAgICAgICBjbHVzdGVyLmlkZW50cyA9IEYsCiAgICAgICAgc2NhbGUgPSBUUlVFLAogICAgICAgIHNjYWxlLmJ5ID0gInJhZGl1cyIsCiAgICAgICAgc2NhbGUubWluID0gTkEsCiAgICAgICAgc2NhbGUubWF4ID0gTkEpICsgCiAgUm90YXRlZEF4aXMoKSArIAogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NikpICsgCiAgbGFicyh4PSIiLHk9IiIsIHRpdGxlPSJtUk5BIGV4cHJlc3Npb24iKQopCmBgYAoKCmBgYHtyfQpEb3RQbG90KHBibWMsCiAgICAgICAgZmVhdHVyZXMgPSByb3duYW1lcyhwYm1jQGFzc2F5cyRBRFQpLAogICAgICAgIGFzc2F5ID0gIkFEVCIsCiAgICAgICAgY29scyA9IGMoIlJkWWxCdSIpLAogICAgICAgIGNvbC5taW4gPSAtMi41LAogICAgICAgIGNvbC5tYXggPSAyLjUsCiAgICAgICAgZG90Lm1pbiA9IDAsCiAgICAgICAgZG90LnNjYWxlID0gMSwKICAgICAgICBpZGVudHMgPSBOVUxMLAogICAgICAgIGdyb3VwLmJ5ID0gTlVMTCwKICAgICAgICBzcGxpdC5ieSA9IE5VTEwsCiAgICAgICAgY2x1c3Rlci5pZGVudHMgPSBGLAogICAgICAgIHNjYWxlID0gVFJVRSwKICAgICAgICBzY2FsZS5ieSA9ICJyYWRpdXMiLAogICAgICAgIHNjYWxlLm1pbiA9IE5BLAogICAgICAgIHNjYWxlLm1heCA9IE5BKSArIAogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLCAjIGNlbGwgc3Vic2V0cwogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSkgKyAKICBSb3RhdGVkQXhpcygpICsKICBsYWJzKHg9IiIseT0iIiwgdGl0bGU9IlN1cmZhY2UgcHJvdGVpbiBleHByZXNzaW9uIikKYGBgCgojIyMgRmlndXJlIFM2RgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQooY2VsbG51bWJlcnNfbDIgPC0gdGliYmxlKHBibWNfYWN1dGVAbWV0YS5kYXRhKSAlPiUgCiAgIGdyb3VwX2J5KENlbGxUeXBlX0wyKSAlPiUgCiAgIGNvdW50KCkgJT4lIAogICAKICAgZ2dwbG90KGFlcyhmaWxsID0gQ2VsbFR5cGVfTDIsIHk9biwgeD1mY3RfcmVvcmRlcihDZWxsVHlwZV9MMixuKSkpICsgCiAgIGdlb21fY29sKHNob3cubGVnZW5kID0gRikgKwogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBMMl9jb2xvcnMpICsKICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksdHJhbnMgID0gImxvZzEwIiwgYnJlYWtzPWMoMSwxMCwxMDAsMTAwMCw1MDAwKSkgKyAKICAgY29vcmRfZmxpcCgpICsKICAgbGFicyh4PU5VTEwsCiAgICAgICAgeT0iTnVtYmVyIG9mIGNlbGxzIikgKwogICB0aGVtZV9idygpICsKICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKSkKYGBgCgojIyMgRmlndXJlIFM2RwpgYGB7cn0KZ2VuZXMub2kudGltZXBvaW50cyA9IFZsblBsb3QocGJtYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJDRDE2MyIsICJJTDFCIiwgIklMMVJOIiwgIklDQU0xIiwgIkxJTFJCNCIsICJDWENMMTAiLCAiUzEwMEExMiIsICAiTkFNUFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNDTDIiLCAiQ1hDTDExIiwgIkNYQ0w5IiwgIkFaVTEiLCJWTU8xIiwgIlRORlJTRjgiLCAiQ0hJM0wxIiwiQ0NMNCIsICJHWk1BIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHWk1CIiwiR1pNSCIsIkNTVDciLCJUTkZSU0Y5IiwiSUwyUkEiLCJJTDFSTDEiLCJDRDQ4IiwgIkNEMjciLCAiQ0QzOCIsICJIQVZDUjIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAnQ2VsbFR5cGVfTDInLCBhc3NheSA9ICJSTkEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGxpdC5ieSA9ICJUaW1lIiwgY29scyA9IHRpbWUzX2NvbCwgc29ydCA9IEYsIHB0LnNpemUgPSAwLHN0YWNrID0gVCxmbGlwID0gRikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gNSwgZmFjZT1OVUxMLGhqdXN0ID0gLjUpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAjIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoLjIsICdjbScpLCAjY2hhbmdlIGxlZ2VuZCBrZXkgc2l6ZQogICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCguMiwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSBoZWlnaHQKICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCguMiwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSB3aWR0aAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTUpLCAjY2hhbmdlIGxlZ2VuZCB0aXRsZSBmb250IHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTUpKQoKZ2VuZXMub2kudGltZXBvaW50cyRsYXllcnNbWzFdXSRhZXNfcGFyYW1zJHNpemUgPSAuMQpnZW5lcy5vaS50aW1lcG9pbnRzCmBgYAoKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXJlIDcgCioqcmVsYXRlZCB0byBtYWluIEZpZ3VyZSAzKioKCmBgYHtyIGRvb2xleS1sb2FkLWRhdGF9CmRvb2xleSA8LSByZWFkUkRTKCIuLi9kYXRhL2RhdGEvUmVBbmFseXNpc19Eb29sZXlOTF9ldGFsX2Jpb1J4aXZfMjAyMi9hbm5vdGF0ZWRfU2FiYWhfZGF0YV8yMU9jdDIwMjIucmRzIikKCmRvb2xleV9jb2xvcnMgPC0gc2V0TmFtZXMocmFuZG9tY29sb1I6OmRpc3RpbmN0Q29sb3JQYWxldHRlKGxlbmd0aCh1bmlxdWUoZG9vbGV5QG1ldGEuZGF0YSRjZWxsdHlwZSkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWUoZG9vbGV5QG1ldGEuZGF0YSRjZWxsdHlwZSkpCiMjIFByZWxpbWluYXJ5IFFDIGNoZWNrCgp0aWJibGUoZG9vbGV5QG1ldGEuZGF0YSkgJT4lICMgdGhlIHJlc3VsdGluZyBtZCBvYmplY3QgaGFzIG9uZSAicm93IiBwZXIgY2VsbAogIHJvd25hbWVzX3RvX2NvbHVtbigiQ2VsbElEIikgICU+JSAKICBncm91cF9ieShvcmlnLmlkZW50LHRpbWVwb2ludCxzYW1wbGUuZGF5LElEKSAlPiUgCiAgZHBseXI6OmNvdW50KCkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZ2dwbG90KGFlcyh4PWZjdF9yZW9yZGVyKG9yaWcuaWRlbnQsIHRpbWVwb2ludCkseT1uLCBmaWxsPUlEKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArCiAgY29vcmRfZmxpcCgpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImRvZGdlIiwgc2hvdy5sZWdlbmQgPSBGKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgY2VsbHMgcGVyIHNhbXBsZSIsCiAgICAgICB4PU5VTEwpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyMgRmlndXJlIFM3QQpgYGB7ciBkb29sZXktdW1hcCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZG9vbGV5X3VtYXBfY29vcmRzIDwtIGRhdGEudGFibGU6OmRhdGEudGFibGUoZG9vbGV5QG1ldGEuZGF0YSwgRW1iZWRkaW5ncyhvYmplY3QgPSBkb29sZXksIHJlZHVjdGlvbiA9ICd1bWFwJykpICU+JSByb3duYW1lc190b19jb2x1bW4oIkNlbGxJRCIpIAoKbGFibGVfZGYgPC0gZG9vbGV5X3VtYXBfY29vcmRzICU+JQogIGRwbHlyOjpncm91cF9ieShjZWxsdHlwZSkgJT4lCiAgZHBseXI6OnNlbGVjdChjZWxsdHlwZSwgY29udGFpbnMoIlVNQVAiKSkgJT4lCiAgc3VtbWFyaXNlX2FsbChtZWFuKQoKKGRvb2xleV91bWFwX2dncGxvdCA8LSBkb29sZXlfdW1hcF9jb29yZHMgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yKSkgKyAKICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gYXMuY2hhcmFjdGVyKGNlbGx0eXBlKSksIHNpemUgPSAwLjEsIGFscGhhPS41LHNob3cubGVnZW5kID0gRikgKwogICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9bGFibGVfZGYsYWVzKHg9VU1BUF8xLHk9VU1BUF8yLCBsYWJlbD1jZWxsdHlwZSksc2l6ZT0yKSArCiAgICBsYWJzKHggPSAnVU1BUCAxJywgeSA9ICdVTUFQIDInKSAgKyAKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9ZG9vbGV5X2NvbG9ycykgKwogICAgbXlfZGltcmVkX3RoZW1lKQoKYGBgCgojIyMgRmlndXJlIFM3QgpgYGB7ciBkb29sZXktcmVhbmFseXNpc30KIyMgUGVyY2VudGFnZSBjZWxsdHlwZSBpbiBzYW1wbGUKKGRvb2xleV9wZXJfc2FtcGxlX3BlcmMgPC0gdGliYmxlKGRvb2xleUBtZXRhLmRhdGEpICU+JSAKICAgZ3JvdXBfYnkodGltZXBvaW50LG9yaWcuaWRlbnQpICU+JSAKICAgY291bnQoY2VsbHR5cGUpICU+JSAKICAgIyBTdGFja2VkICsgcGVyY2VudAogICBnZ3Bsb3QoYWVzKGZpbGwgPSBjZWxsdHlwZSwgeT1uLCB4PW9yaWcuaWRlbnQpKSArIAogICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQ9ImlkZW50aXR5Iix3aWR0aCA9IDAuOSkgKwogICBmYWNldF9ncmlkKH50aW1lcG9pbnQsc2NhbGVzID0gImZyZWVfeCIsc3BhY2UgPSAiZnJlZV94IikgKwogICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArIAogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9ZG9vbGV5X2NvbG9ycykgKwogICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LGV4cGFuZCA9IGMoMCwwKSkgKyAKICAgbGFicyh4ID0gIiIsCiAgICAgICAgeSA9ICJGcmVxdWVuY3kiLAogICAgICAgIGZpbGw9IiIpICsKICAgdGhlbWVfbWluaW1hbCgpICsKICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLAogICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSkpCmBgYAoKCmdldCBvbmx5IGFjdXRlIG1hbGFyaWEgY2VsbHMgKERheTApCgpgYGB7ciBkb29sZXktcmVhbmFseXNpcy1kYXkwLWNlbGxudW1iZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRvb2xleV8wIDwtIHN1YnNldChkb29sZXksIHN1YnNldD10aW1lcG9pbnQ9PSJEYXkwIikKIy0gUk5BIE5vcm1hbGl6YXRpb24KZG9vbGV5XzAgPC0gTm9ybWFsaXplRGF0YShvYmplY3QgPSBkb29sZXlfMCwgYXNzYXkgPSAnUk5BJywgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAnTG9nTm9ybWFsaXplJywgc2NhbGUuZmFjdG9yID0gMTAwMDApCmBgYAoKIyMjIEZpZ3VyZSBTN0MKCmBgYHtyIGRvb2xleS1yZWFuYWx5c2lzLWRheTAtY2VsbG51bWJlczEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cihkb29sZXlfMF9jZWxsbnVtYmVycyA8LSAKICAgdGliYmxlKGRvb2xleV8wQG1ldGEuZGF0YSkgJT4lIAogICBncm91cF9ieShjZWxsdHlwZSkgJT4lIAogICBjb3VudCgpICU+JSAKICAgZ2dwbG90KGFlcyhmaWxsID0gY2VsbHR5cGUsIHk9biwgeD1mY3RfcmVvcmRlcihjZWxsdHlwZSxuKSkpICsgCiAgIGdlb21fY29sKHNob3cubGVnZW5kID0gRikgKwogICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSx0cmFucyAgPSAibG9nMTAiKSArCiAgIGNvb3JkX2ZsaXAoKSArCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1kb29sZXlfY29sb3JzKSArCiAgIGxhYnMoeD1OVUxMLAogICAgICAgIHk9Ik51bWJlciBvZiBjZWxscyIpICsKICAgdGhlbWVfYncoKSArCiAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSkpCmBgYAoKYGBge3IgZG9vbGV5LXJlYW5hbHlzaXMtZGF5MCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgY2FsY3VsYXRpb24gb2YgcHNldWRvYnVsaywgZm9yIGVhY2ggaWRlbnRpdHkgYmFzZWQgb24gY291bnQgZGF0YQpkb29sZXlfMC5hdmcud2lkZSA8LSBsb2cxcChBdmVyYWdlRXhwcmVzc2lvbihkb29sZXlfMCwgZ3JvdXAuYnkgPSAiY2VsbHR5cGUiLCBzbG90ID0gImNvdW50cyIsIHZlcmJvc2UgPSBGQUxTRSkkUk5BKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oImdlbmUiKSAKCmRvb2xleV8wLmF2Zy5sb25nIDwtIGRvb2xleV8wLmF2Zy53aWRlICU+JSAKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAiY2VsbHR5cGUiLCB2YWx1ZXNfdG8gPSAiYXZnRXhwIixjb2xzID0gLWdlbmUpICU+JSBmaWx0ZXIoYXZnRXhwID4wKQpgYGAKCmBgYHtyfQpkb29sZXkuZ2VuZS5tYXRjaCA8LSBmdWxsX21hcHBpbmcgJT4lIAogIGZpbHRlcihVbmlQcm90ICVpbiUgd2lsY294VXApICU+JSAKICBmaWx0ZXIoU3ltYm9sICVpbiUgdW5pcXVlKGRvb2xleV8wLmF2Zy5sb25nJGdlbmUpKQoKbWF0X2Rvb2xleV8wIDwtIGRvb2xleV8wLmF2Zy53aWRlICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIGRvb2xleS5nZW5lLm1hdGNoJFN5bWJvbCkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygiZ2VuZSIpICU+JSAKICBhcy5tYXRyaXgoKSAKYGBgCgojIyMgRmlndXJlIFM3RApgYGB7cn0KIyMgUmhhcHNvZHkgdnMuIERvb2xleQojI2Jpbm5pbmcgb2YgY2VsbCBpbW11bmUgY2VsbCBzdWJzZXRzCgojZGltKG1hdF9kb29sZXlfMCkKI2RpbShtYXRfcGJtY19hY3V0ZSkKCiMjIGdlbmUgb3ZlcmxhcCBSaGFwc29keSwgRG9vbGV5IGV0IGFsLCBFeHBsb3JlCnJoYXBzb2R5X2Rvb2xleV9vdmVybGFwcCA8LSBpbnRlcnNlY3Qocm93bmFtZXMobWF0X2Rvb2xleV8wKSxyb3duYW1lcyhtYXRfcGJtY19hY3V0ZSkpCgpjb21wYXJlX2Rvb2xleV9yaGFwc29keSA8LSBkYXRhLmZyYW1lKG1hdF9kb29sZXlfMFtyaGFwc29keV9kb29sZXlfb3ZlcmxhcHAsXSkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiZ2VuZSIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLWdlbmUpICU+JQogIG11dGF0ZShvcmlnaW4gPSAiZG9vbGV5IikgJT4lIAogIGJpbmRfcm93cygKICAgIGRhdGEuZnJhbWUobWF0X3BibWNfYWN1dGVbcmhhcHNvZHlfZG9vbGV5X292ZXJsYXBwLF0pICU+JSAKICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCJnZW5lIikgJT4lIAogICAgICBwaXZvdF9sb25nZXIoY29scyA9IC1nZW5lKSAlPiUKICAgICAgbXV0YXRlKG9yaWdpbiA9ICJyaGFwc29keSIpKSAlPiUKICAKICAKICBtdXRhdGUobmFtZS5jb21tb24gPSBpZmVsc2UoZ3JlcGwoIkNEMTQiLG5hbWUpLCJDRDE0bW9ubyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiQ0QxNi5tb25vY3l0ZXMiLG5hbWUsaWdub3JlLmNhc2UgPSBUKSwiQ0QxNm1vbm8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJwREMiLG5hbWUpLCJwREMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgibURDIixuYW1lKSwibURDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJOS1QiLG5hbWUpLCJOS1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJnZFR8zrPOtC5ULmNlbGxzIixuYW1lKSwiZ2RUY2VsbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJDRDgiLG5hbWUpLCJDRDhUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJDRDQiLG5hbWUpLCJDRDRUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiTksiLG5hbWUpLCJOSyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJCIixuYW1lKSwiQmNlbGwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIlVua25vd258dW5kZWZpbmVkIixuYW1lKSwidW5kZWZpbmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUpKSkpKSkpKSkpKSkgCgpgYGAKCgoKYGBge3J9CmNvbW1vbi5jZWxsdHlwZXMgPC0gaW50ZXJzZWN0KGZpbHRlcihjb21wYXJlX2Rvb2xleV9yaGFwc29keSxvcmlnaW49PSJkb29sZXkiKSAlPiUgcHVsbChuYW1lLmNvbW1vbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihjb21wYXJlX2Rvb2xleV9yaGFwc29keSxvcmlnaW49PSJyaGFwc29keSIpICU+JSBwdWxsKG5hbWUuY29tbW9uKSkKCmRvb2xleV9obSA8LSBjb21wYXJlX2Rvb2xleV9yaGFwc29keSAlPiUgCiAgZmlsdGVyKG9yaWdpbj09ImRvb2xleSIsIG5hbWUuY29tbW9uICVpbiUgY29tbW9uLmNlbGx0eXBlcykgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBnZW5lLCB2YWx1ZXNfZnJvbSA9IHZhbHVlLGlkX2NvbHMgPSBuYW1lLmNvbW1vbikgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygibmFtZS5jb21tb24iKSAlPiUgCiAgIyMgc2NhbGUgdmFsdWVzIGZyb20gMC0xCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gc2NhbGVzOjpyZXNjYWxlKC4sIHRvPWMoMCwxKSkpKSAlPiUgCiAgICBhcy5tYXRyaXgoKSAlPiUgCiAgICB0KCkgJT4lCgogIEhlYXRtYXAobmFtZT0iRG9vbGV5IiwKICAgICAgICAgIGNvbHVtbl90aXRsZSA9ICJEb29sZXkgZXQgYWwuIiwKICAgICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAKICAgICAgICAgIGNvbHVtbl9vcmRlciA9IGNvbW1vbi5jZWxsdHlwZXMsCiAgICAgICAgICBjb2wgPSBzY2FsZWRfMDFfY29sLAogICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgIHJvd19kZW5kX3Jlb3JkZXIgPSBUUlVFLAogICAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBUUlVFLAogICAgICAgICAgc2hvd19oZWF0bWFwX2xlZ2VuZCA9IEYsCiAgICAgICAgICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksCiAgICAgICAgICByb3dfdGl0bGVfcm90ID0gMCwKICAgICAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA0KSwKICAgICAgICAgIHJvd19kZW5kX3dpZHRoID0gdW5pdCg1LCAibW0iKSwgCiAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksIAogICAgICAgICAgY29sdW1uX25hbWVzX3JvdCA9IDkwLAogICAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA1KSksCiAgICAgICAgICB3aWR0aCA9IG5yb3coLikqdW5pdCguMywgIm1tIiksIAogICAgICAgICAgaGVpZ2h0ID0gbmNvbCguKSp1bml0KDYsICJtbSIpLAogICkKCnJoYXBzb2R5X2htIDwtIGZpbHRlcihjb21wYXJlX2Rvb2xleV9yaGFwc29keSwgb3JpZ2luPT0icmhhcHNvZHkiLCBuYW1lLmNvbW1vbiAlaW4lIGNvbW1vbi5jZWxsdHlwZXMpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBnZW5lLCB2YWx1ZXNfZnJvbSA9IHZhbHVlLGlkX2NvbHMgPSBuYW1lLmNvbW1vbix2YWx1ZXNfZm4gPSBtZWRpYW4pICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoIm5hbWUuY29tbW9uIikgJT4lIAogICMjIHNjYWxlIHZhbHVlcyBmcm9tIDAtMQogICAgYXMuZGF0YS5mcmFtZSgpICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHNjYWxlczo6cmVzY2FsZSguLCB0bz1jKDAsMSkpKSkgJT4lICNzY2FsZSguKSkpICU+JSAKICAgIGFzLm1hdHJpeCgpICU+JSAKICAgIHQoKSAlPiUKCiAgSGVhdG1hcChuYW1lPSJhdmVyYWdlXG5nZW5lXG5leHByZXNzaW9uIiwKICAgICAgICAgIGNvbHVtbl90aXRsZSA9ICJUaGlzIHN0dWR5IiwKICAgICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICBjb2x1bW5fb3JkZXIgPSBjb21tb24uY2VsbHR5cGVzLAogICAgICAgICAgY29sID0gc2NhbGVkXzAxX2NvbCwKICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgICByb3dfZGVuZF9yZW9yZGVyID0gVFJVRSwKICAgICAgICAgIHNob3dfcm93X25hbWVzID0gVFJVRSwKICAgICAgICAgIHJvd190aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgICAgIHJvd190aXRsZV9yb3QgPSAwLAogICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDQpLAogICAgICAgICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDUsICJtbSIpLCAKICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwgCiAgICAgICAgICBjb2x1bW5fbmFtZXNfcm90ID0gOTAsCiAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9wb3NpdGlvbiA9ICJ0b3BjZW50ZXIiCiAgICAgICAgICApLAogICAgICAgICAgd2lkdGggPSBucm93KC4pKnVuaXQoLjMsICJtbSIpLCAKICAgICAgICAgIGhlaWdodCA9IG5jb2woLikqdW5pdCg2LCAibW0iKSwKICApCgpjb21wYXJlX2Rvb2xleV9yaGFwc29keV9obV9uZXcgPC0gZG9vbGV5X2htICsgcmhhcHNvZHlfaG0KCmRyYXcoY29tcGFyZV9kb29sZXlfcmhhcHNvZHlfaG1fbmV3LCByb3dfZGVuZF9zaWRlID0gImxlZnQiLCBtYWluX2hlYXRtYXAgPSAiYXZlcmFnZVxuZ2VuZVxuZXhwcmVzc2lvbiIsYXV0b19hZGp1c3QgPSBGKQoKYGBgCgoKIyMjIEZpZ3VyZSBTN0UKYGBge3J9CmRpbShtYXRfZG9vbGV5XzApCgpyb3cuYW5uby5kZiA8LSBkYXRhLmZyYW1lKEFzc2F5ID0gcm93bmFtZXMobWF0X2Rvb2xleV8wKSkgJT4lIAogIGxlZnRfam9pbihkYXAucmVzLGJ5PWMoIkFzc2F5IikpICU+JSAKICBsZWZ0X2pvaW4oaHBhXzI0LjAsYnk9YygiQXNzYXkiPSJnZW5lIikpICU+JSAKICBtdXRhdGUoc2VjcmV0b21lX2Z1bmN0aW9uID0gaWZlbHNlKGlzLm5hKHNlY3JldG9tZV9mdW5jdGlvbiksIk5vdCBzZWNyZXRlZCIsIHNlY3JldG9tZV9mdW5jdGlvbikpICU+JSAKICBmaWx0ZXIoc2VjcmV0b21lX2Z1bmN0aW9uICE9ICJOb3Qgc2VjcmV0ZWQiKQoKcm93QW5ubyA8LSBIZWF0bWFwQW5ub3RhdGlvbihkZiA9IHJvdy5hbm5vLmRmICU+JSB0cmFuc211dGUoQXNzYXksc2VjcmV0b21lX2xvY2F0aW9uKSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJBc3NheSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gInJvdyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kID0gYyhUUlVFKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19hbm5vdGF0aW9uX25hbWUgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbmFtZV9ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGUgPSAiSFBBXG5jbGFzc2lmaWNhdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb249Imhvcml6b250YWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCgxLCAibW0iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KDMsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9wb3NpdGlvbiA9ICJ0b3BsZWZ0IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChzZWNyZXRvbWVfbG9jYXRpb24gPSBzZWNyZXRvbWVfbG9jYXRpb25fY29scyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoMywgIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFfY29sID0gImdyZXk5MCIpCgooZG9vbGV5X2RheTBfaG0uaHBhLm1hcHBpbmcgPC0gbWF0X2Rvb2xleV8wW3Jvdy5hbm5vLmRmJEFzc2F5LF0gJT4lIAogICAgdCgpICU+JSAKICAgICMjIHNjYWxlIHZhbHVlcyBmcm9tIDAtMQogICAgYXMuZGF0YS5mcmFtZSgpICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHNjYWxlczo6cmVzY2FsZSguLCB0bz1jKDAsMSkpKSkgJT4lIAogICAgYXMubWF0cml4KCkgJT4lIAogICAgdCgpICU+JSAKICAgIENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKAogICAgICBuYW1lPSJhdmVyYWdlXG5nZW5lXG5leHByZXNzaW9uXG4iLAogICAgICBjb2wgPSBzY2FsZWRfMDFfY29sLAogICAgICByaWdodF9hbm5vdGF0aW9uID0gcm93QW5ubywKICAgICAgY29sdW1uX2RlbmRfaGVpZ2h0ID0gdW5pdCgyLCAibW0iKSwgCiAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgIHJvd19kZW5kX3Jlb3JkZXIgPSBUUlVFLAogICAgICBzaG93X3Jvd19uYW1lcyA9IFRSVUUsCiAgICAgIHJvd19zcGxpdCA9IHJvdy5hbm5vLmRmJHNlY3JldG9tZV9mdW5jdGlvbiwKICAgICAgcm93X3RpdGxlX3NpZGUgPSAicmlnaHQiLAogICAgICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksCiAgICAgIHJvd190aXRsZV9yb3QgPSAwLAogICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNCksCiAgICAgIHJvd19kZW5kX3dpZHRoID0gdW5pdCg0LCAibW0iKSwgCiAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwgCiAgICAgIGNvbHVtbl9uYW1lc19yb3QgPSA5MCwKICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpKSwKICAgICAgaGVpZ2h0ID0gbmNvbCguKSp1bml0KDgsICJtbSIpLAogICAgICB3aWR0aCA9IG5jb2woLikqdW5pdCgyLCJtbSIpKQopCmBgYAoKIyMjIEZpZ3VyZSBTN0YKCmBgYHtyfQptYXRfZG9vbGV5XzAgPC0gZG9vbGV5XzAuYXZnLndpZGUgJT4lIAogIGZpbHRlcihnZW5lICVpbiUgZG9vbGV5LmdlbmUubWF0Y2gkU3ltYm9sKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJnZW5lIikgJT4lIAogIGFzLm1hdHJpeCgpIAoKZGltKG1hdF9kb29sZXlfMCkKCnJvdy5hbm5vLmRmIDwtIGRhdGEuZnJhbWUoQXNzYXkgPSByb3duYW1lcyhtYXRfZG9vbGV5XzApKSAlPiUgCiAgbGVmdF9qb2luKGRhcC5yZXMsYnk9YygiQXNzYXkiKSkgJT4lIAogIGxlZnRfam9pbihocGFfMjQuMCxieT1jKCJBc3NheSI9ImdlbmUiKSkgJT4lIAogIG11dGF0ZShzZWNyZXRvbWVfZnVuY3Rpb24gPSBpZmVsc2UoaXMubmEoc2VjcmV0b21lX2Z1bmN0aW9uKSwiTm90IHNlY3JldGVkIiwgc2VjcmV0b21lX2Z1bmN0aW9uKSkgJT4lIAogIGZpbHRlcihzZWNyZXRvbWVfZnVuY3Rpb24gPT0gIk5vdCBzZWNyZXRlZCIpCgoKKGRvb2xleV9kYXkwX2htLm5vLmhwYS5tYXBwaW5nIDwtIG1hdF9kb29sZXlfMFtyb3cuYW5uby5kZiRBc3NheSxdICU+JSAKICAgIHQoKSAlPiUgCiAgICAjIyBzY2FsZSB2YWx1ZXMgZnJvbSAwLTEKICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiBzY2FsZXM6OnJlc2NhbGUoLiwgdG89YygwLDEpKSkpICU+JSAjc2NhbGUoLikpKSAlPiUgCiAgICBhcy5tYXRyaXgoKSAlPiUgCiAgICB0KCkgJT4lIAogICAgQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAobmFtZT0iYXZlcmFnZVxuZ2VuZVxuZXhwcmVzc2lvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBzY2FsZWRfMDFfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19oZWF0bWFwX2xlZ2VuZCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fZGVuZF9oZWlnaHQgPSB1bml0KDIsICJtbSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfZGVuZF9yZW9yZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93X25hbWVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd19zcGxpdCA9IHJvdy5hbm5vLmRmJHNlY3JldG9tZV9mdW5jdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd190aXRsZV9zaWRlID0gInJpZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd190aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd190aXRsZV9yb3QgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDQsICJtbSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fbmFtZXNfcm90ID0gOTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IG5jb2woLikqdW5pdCg4LCAibW0iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gbmNvbCguKSp1bml0KDIsIm1tIikpCikKYGBgCgojIEZpZ3VyZSA0CioqUHJvdGVpbiBwcm9maWxlLWJhc2VkIHBhdGllbnQgc3RyYXRpZmljYXRpb24gb2YgZGlzZWFzZSBzZXZlcml0eSoqCgojIyBTdXBwbGVtZW50YXJ5IEZpZ3VyZSA4CioqIHJlbGF0ZWQgdG8gbWFpbiBGaWd1cmUgNCoqCgpGaWd1cmUgUzhBCmBgYHtyfQpjbGluX21hcmtlcl9jb2xzIDwtIGMoIkNSUCIsIkNyZWF0aW5pbmUiLCJQYXJhc2l0ZW1pYSIsIlBsYXRlbGV0cyIsIkJpbGlydWJpbiIsIkFTQVQiLCJBTEFUIiwiSGVtb2dsb2JpbiIpCgpjbGluX21hcmtlcl9jb2xzIDwtIHNldE5hbWVzKGJyZXdlci5wYWwobGVuZ3RoKGNsaW5fbWFya2VyX2NvbHMpLG5hbWU9IlNldDMiKSwgY2xpbl9tYXJrZXJfY29scykKCgoKY2xpbmljYWxfdmFyaWFibGVzXzRjaXJjb3MgPC0gIHN1YmplY3RUYWJsZSAlPiUgCiAgICBsZWZ0X2pvaW4oY2xpbmNoZW1fc3R1ZHlfcGF0c19hY3V0ZS53aWRlLCBieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICAjaW5uZXJfam9pbihwYXRpZW50X2NsdXN0LGJ5PSJzdHVkeV9pZCIpICU+JSAKICAgIHVuZ3JvdXAoKSAlPiUgCiAgICBwaXZvdF9sb25nZXIoY29scyA9IGMocGx0X2NvdW50X21pbixpbmZfcmJjX21heCxjcnBfbWF4LGhiX21pbixiaWxpX21heCxjcmVhX21heCwicF9hbGF0IiwicF9hc2F0IiksCiAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiY2xpbi52YXIiLCB2YWx1ZXNfdG89ImNsaW4udmFsIiwKICAgICkgJT4lIAogICAgZHJvcF9uYShjbGluLnZhbCkgJT4lIAogICAgZ3JvdXBfYnkoY2xpbi52YXIpICU+JSAKIG11dGF0ZShuX2dyb3VwPSBhcy5jaGFyYWN0ZXIobigpKSwKICAgICAgICAgICBsYWJlbF9ncm91cD0gZmFjdG9yKHBhc3RlMCgnXG4gbiA9ICcsIG5fZ3JvdXApKSkgJT4lIAogICAgbXV0YXRlKGNsaW4udmFyID0gY2FzZV93aGVuKGNsaW4udmFyPT0iY3JwX21heCJ+IkNSUCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpbi52YXI9PSJwX2FsYXQifiJBTEFUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjbGluLnZhcj09InBfYXNhdCJ+IkFTQVQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNsaW4udmFyPT0icGx0X2NvdW50X21pbiJ+IlBsYXRlbGV0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpbi52YXI9PSJpbmZfcmJjX21heCIgfiJQYXJhc2l0ZW1pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpbi52YXI9PSJiaWxpX21heCJ+IkJpbGlydWJpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpbi52YXI9PSJoYl9taW4iIH4iSGVtb2dsb2JpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpbi52YXI9PSJjcmVhX21heCJ+IkNyZWF0aW5pbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0PWNsaW4udmFyKSkgJT4lIAogICAgbXV0YXRlKGNsaW4udmFyID0gZmFjdG9yKGNsaW4udmFyLCBsZXZlbHM9bmFtZXMoY2xpbl9tYXJrZXJfY29scykpKSAKIAooY2xpbl9wYXJhX3dob2xlX2NvaG9ydCA8LSBjbGluaWNhbF92YXJpYWJsZXNfNGNpcmNvcyAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9bGFiZWxfZ3JvdXAsIHk9Y2xpbi52YWwsIGZpbGw9Y2xpbi52YXIpKSArCiAgICBnZW9tX3Zpb2xpbih0cmltPUYsIHNob3cubGVnZW5kID0gRiwgd2lkdGg9LjQsbHdkPS4yNSkgKwogICAgZ2VvbV9qaXR0ZXIoc2l6ZT0wLjA1LHdpZHRoID0gLjEsIHNob3cubGVnZW5kID0gRixsd2Q9LjI1KSArCiAgICBnZW9tX2JveHBsb3QoYWxwaGE9LjcsIG91dGxpZXIuc2hhcGUgPSBOQSwgd2lkdGg9LjIsIHNob3cubGVnZW5kID0gRixsd2Q9LjI1KSArCiAgICBmYWNldF93cmFwKH5jbGluLnZhciwgc2NhbGVzID0gImZyZWUiLCBucm93ID0gNCwKICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoY2xpbi52YXIgPSBjKCJCaWxpcnViaW4iPSAiQmlsaXJ1YmluXG4oXFUwMDNCQ21vbC9MKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQUxBVCI9IkFMVFxuKFUvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFTQVQiPSJBU1RcbihVL0wpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDUlAiPSJDUlBcbihtZy9MKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGFyYXNpdGVtaWEiPSJQYXJhc2l0ZW1pYVxuKCUpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3JlYXRpbmluZSI9IkNyZWF0aW5pbmVcbihcVTAwM0JDbW9sL0wpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIZW1vZ2xvYmluIj0iSGVtb2dsb2JpblxuKGcvZEwpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQbGF0ZWxldHMiPSJQbGF0ZWxldFxuKGNvdW50cykiKSkpICsKICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDYpKwogICAgbGFicyh5PSJDbGluaWNhbCBwYXJhbWV0ZXIgdmFsdWUiLAogICAgICAgICB4PU5VTEwpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Y2xpbl9tYXJrZXJfY29scykpCgogCmBgYAoKIyMjIEZpZ3VyZSBTOEMgCmBgYHtyfQpwYXRpZW50X1NPRkEgPC0gc3ViamVjdFRhYmxlICU+JSBkcGx5cjo6c2VsZWN0KHN0dWR5X2lkLCBjb250YWlucygiU09GQSIpKQoKd2hvMjJfc2V2ZXJlbWFsYXJpYSA8LSBzdWJqZWN0VGFibGUgJT4lIAogIHRyYW5zbXV0ZShzdHVkeV9pZCwKICAgICAgICAgICAgcmVzcGlyYXRvcnlfZGlzdHJlc3MgPSBjYXNlX3doZW4ocHVsbV9lZGVtYSA9PSAxIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNwX2Rpc3RyZXNzID09IDEgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZHMgPT0gMSB+IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IDApLAogICAgICAgICAgICBjaXJjXzgwLAogICAgICAgICAgICBoYl83MCA9IGNhc2Vfd2hlbihoYl9taW4gPD0gNzAgfiAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGJfbWluID43MCB+MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSksCiAgICAgICAgICAgIGJpbGlfNTAsCiAgICAgICAgICAgIGNyZWFfMjY1ID0gY2FzZV93aGVuKGNyZWFfbWF4ID49IDI2NSB+IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcmVhX21heCA8MjY1IH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSksCiAgICAgICAgICAgIHBhcmFzaXRhZW1pYV8yID0gY2FzZV93aGVuKGluZl9yYmNfbWF4ID49IDIgfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZfcmJjX21heCA8IDIgfiAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IE5BKSwKICAgICAgICAgICAgcGFyYXNpdGFlbWlhXzUgPSBjYXNlX3doZW4oaW5mX3JiY19tYXggPj0gNSB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZl9yYmNfbWF4IDwgNSB+IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gTkEpCiAgKQoKbWF0IDwtIHdobzIyX3NldmVyZW1hbGFyaWEgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic3R1ZHlfaWQiKSAlPiUgCiAgYXMubWF0cml4KCkgJT4lIAogIHQoKQoKbWF0X3NvZmFfdG90YWwgPC0gZGF0YS5mcmFtZShzdHVkeV9pZCA9IGNvbG5hbWVzKG1hdCkpICU+JSAKICBsZWZ0X2pvaW4ocGF0aWVudF9TT0ZBLCBieT0ic3R1ZHlfaWQiKSAKCnN0dWR5X2lkX1NPRkEuc29ydGVkIDwtIG1hdF9zb2ZhX3RvdGFsICU+JSBhcnJhbmdlKC1TT0ZBX3RvdGFsKSAlPiUgcHVsbChzdHVkeV9pZCkKCm1hdCA8LSBtYXRbLHN0dWR5X2lkX1NPRkEuc29ydGVkXQoKCnNldmVyZXNpZ25fY291bnQgPC0gd2hvMjJfc2V2ZXJlbWFsYXJpYSAlPiUgCiAgdHJhbnNtdXRlKHN0dWR5X2lkLAogICAgICAgICAgICByZXNwaXJhdG9yeV9kaXN0cmVzcywKICAgICAgICAgICAgY2lyY184MCwKICAgICAgICAgICAgaGJfNzAsCiAgICAgICAgICAgIGJpbGlfNTAsCiAgICAgICAgICAgIGNyZWFfMjY1LAogICAgICAgICAgICBwYXJhc2l0YWVtaWFfNSkgJT4lIAogIHJlcGxhY2UoaXMubmEoLiksIDApICU+JSAKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKG5yX29mX3NldmVyZV9zaWducyA9IHN1bShjX2Fjcm9zcyh3aGVyZShpcy5udW1lcmljKSkpKSAlPiUgCiAgdHJhbnNtdXRlKHN0dWR5X2lkLAogICAgICAgICAgICBucl9vZl9zZXZlcmVfc2lnbnMpIAoKKGhtLnNvZmEuY2xpbiA8LSBtYXQgJT4lIAogIEhlYXRtYXAobmFtZSA9ICJTZXZlcmUgbWFsYXJpYSBzeW1wdG9tc1xuZGVmaW5lZCBieSBXSE8gMjAxNSIsCiAgICAgICAgICBjb2wgPSBjKCIwIj0id2hpdGUiLCIxIj0iI0M1MUI3RCIpLAogICAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLCAKICAgICAgICAgIG5hX2NvbCA9ICJncmV5OTAiLAogICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRiwKICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEYsCiAgICAgICAgICBzaG93X3Jvd19kZW5kID0gRiwgCiAgICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRiwKICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRiwKICAgICAgICAgIHRvcF9hbm5vdGF0aW9uID0gSGVhdG1hcEFubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKHN0dWR5X2lkID0gY29sbmFtZXMobWF0KSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKHNldmVyZXNpZ25fY291bnQpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl90b19yb3duYW1lcygic3R1ZHlfaWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9wb3NpdGlvbiA9ICJ0b3BjZW50ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiTnIgb2ZcbnNldmVyZSBtYWxhcmlhXG5zeW1wdG9tcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaW1wbGVfYW5ub19zaXplID0gdW5pdCgyLCAibW0iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9uYW1lX2dwID0gZ3Bhcihmb250c2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChucl9vZl9zZXZlcmVfc2lnbnMgPSBjaXJjbGl6ZTo6Y29sb3JSYW1wMihjKDAsNiksIGMoIndoaXRlIiwib3JhbmdlIikpKSksCiAgICAgICAgICByb3dfdGl0bGVfc2lkZSA9ICJsZWZ0IiwKICAgICAgICAgIHJvd190aXRsZV9yb3QgPSAwLAogICAgICAgICAgcm93X3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgY29sdW1uX3RpdGxlX3NpZGUgPSAidG9wIiwKICAgICAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgIHJvd19kZW5kX3dpZHRoID0gdW5pdCgwLjUsICJjbSIpLCAKICAgICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgIGNvbHVtbl9uYW1lc19yb3QgPSA5MCwKICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3Bvc2l0aW9uID0gInRvcGNlbnRlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXQgPSBjKDAsMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygibm8iLCJ5ZXMiKSksCiAgICAgICAgICBib3R0b21fYW5ub3RhdGlvbiA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gZGF0YS5mcmFtZShzdHVkeV9pZCA9IGNvbG5hbWVzKG1hdCkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4ocGF0aWVudF9TT0ZBLCBieT0ic3R1ZHlfaWQiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdCgtc3R1ZHlfaWQpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gJ2NvbCcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDIsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBsaXN0KFNPRkFfdG90YWwgPSBjb2xvclJhbXAyKGMobWluKHBhdGllbnRfU09GQSRTT0ZBX3RvdGFsLG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWRpYW4ocGF0aWVudF9TT0ZBJFNPRkFfdG90YWwsbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChwYXRpZW50X1NPRkEkU09GQV90b3RhbCxuYS5ybSA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKGJyZXdlci5wYWwoMyxuYW1lPSJQdUJ1IikpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTT0ZBX2xpdmVyID0gU09GQV9zdWJfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNPRkFfY25zID0gU09GQV9zdWJfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNPRkFfY29hZyA9IFNPRkFfc3ViX2NvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTT0ZBX3Jlc3AgPSBTT0ZBX3N1Yl9jb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU09GQV9jYXJkaW8gPSBTT0ZBX3N1Yl9jb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU09GQV9yZW5hbCA9IFNPRkFfc3ViX2NvbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kID0gYyhULEYsRixGLEYsRiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QoU09GQV90b3RhbCA9IGxpc3QodGl0bGUgPSAiU09GQSAodG90YWwpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfcG9zaXRpb24gPSAidG9wY2VudGVyIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNPRkFfY25zID0gbGlzdCh0aXRsZT0iU09GQSAoc3ViY2F0ZWdvcmljYWwpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3Bvc2l0aW9uID0gInRvcGNlbnRlciIpKSksCiAgICAgICAgICB3aWR0aCA9IG5jb2woLikqdW5pdCgxLjMsICJtbSIpLCAKICAgICAgICAgIGhlaWdodCA9IG5yb3coLikqdW5pdCgxLjYsICJtbSIpLAogICAgICAgICAgcmVjdF9ncCA9IGdwYXIoY29sID0gImdyZXk4MCIsIGx3ZCA9IC4yKSwKICAgICAgICAgIGJvcmRlcl9ncCA9IGdwYXIoY29sID0gImJsYWNrIiwgbHR5ID0gLjUpKSkKCmBgYAoKIyMjIEZpZ3VyZSBTOEQtRQoKYGBge3J9CmRhdGE0X3BjYVJlc19GQ21lZGlhbiA8LSBmY19vdmVyX21lZGlhbl9NMTIgJT4lIAogIGZpbHRlcihBc3NheSAlaW4lIGMoZGFwLnJlcyAlPiUgZmlsdGVyKEZEUj09VFJVRSwgYWJzKGxvZ0ZDKT4xKSAlPiUgcHVsbChBc3NheSkpKSAlPiUgCiAgcGl2b3Rfd2lkZXIodmFsdWVzX2Zyb20gPSBkTlBYLCBuYW1lc19mcm9tID0gQXNzYXksIGlkX2NvbHMgPSBzdHVkeV9pZCkgJT4lIGNvbHVtbl90b19yb3duYW1lcygic3R1ZHlfaWQiKSAKCiMjIFBDIGNhbGN1bGF0aW9uCnBjYVJlc19GQ21lZGlhbiA8LSBwcmNvbXAoZGF0YTRfcGNhUmVzX0ZDbWVkaWFuLCBjZW50ZXIgPSBUUlVFLCBzY2FsZS4gPSBUUlVFKQoKdmFyRXhwX0ZDbWVkaWFuIDwtIHJvdW5kKHBjYVJlc19GQ21lZGlhbiRzZGV2XjIgLyBzdW0ocGNhUmVzX0ZDbWVkaWFuJHNkZXZeMikgKiAxMDApCgojc3VtKHZhckV4cF9GQ21lZGlhblsxOjZdKQoKcGNhREZfRkNtZWRpYW4gPC0gZGF0YS5mcmFtZShwY2FSZXNfRkNtZWRpYW4keCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigic3R1ZHlfaWQiKSAlPiUgZHBseXI6OnNlbGVjdCgxOjEwKSAlPiUgCiAgaW5uZXJfam9pbihkYXRhNF9wY2FSZXNfRkNtZWRpYW4gJT4lIHJvd25hbWVzX3RvX2NvbHVtbigic3R1ZHlfaWQiKSwgYnk9InN0dWR5X2lkIikKCihwY2FfRkNtZWRpYW4gPC0gcGNhREZfRkNtZWRpYW4gJT4lIAogICAgZ2dwbG90KGFlcyh4PVBDMSx5PVBDMikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0uNSkgKyAKICAgIG15X2RpbXJlZF90aGVtZSArCiAgICBjb29yZF9maXhlZChyYXRpbyA9IDEuNzUpICsKICAgIGxhYnMoeD1wYXN0ZTAoIlBDMSAoIix2YXJFeHBfRkNtZWRpYW5bMV0sIiUpIiksCiAgICAgICAgIHk9cGFzdGUwKCJQQzIgKCIsdmFyRXhwX0ZDbWVkaWFuWzJdLCIlKSIpLAogICAgICAgICB0aXRsZSA9ICJkTlBYIChkZWx0YSBOUFggb2YgYWN1dGUgb3ZlciBjb252YWxlc2NlbmNlIG1lZGlhbikiLAogICAgICAgICBjYXB0aW9uID0gcGFzdGUwKCIjIHNhbXBsZXM6ICIsZGltKGRhdGE0X3BjYVJlc19GQ21lZGlhbilbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuICMgcHJvdGVpbnM6ICIsZGltKGRhdGE0X3BjYVJlc19GQ21lZGlhbilbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlxubG9nRkM+MSIpCiAgICApKQoKKGFjdXRlLmRucHguZWxsYm93IDwtIGRhdGEuZnJhbWUoUEMgPSAxOjEwLAogICAgICAgICAgIHZhckV4cCA9IHZhckV4cF9GQ21lZGlhblsxOjEwXSkgJT4lIAogIGdncGxvdChhZXMoeD1QQywgeT12YXJFeHApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAzNSwgYnkgPSA1KSkgKwogIGdlb21fcG9pbnQoc2l6ZT0uMikgKwogIGdlb21fbGluZShsd2Q9LjIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygxLDEwKSwgYnJlYWtzID0gYygxOjEwKSkpCgpkZiA8LSBwY2FERl9GQ21lZGlhbiAlPiUgCiAgZHBseXI6OnNlbGVjdChzdHVkeV9pZCxQQzE6UEM2KSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpIAoKc2V0LnNlZWQoMjAyM0wpCmttIDwtIGttZWFucyhkZiwgY2VudGVycyA9IDMsIG5zdGFydCA9IDI1LGl0ZXIubWF4ID0gMTAwKSAKCmttLnJlcyA8LSBkYXRhLmZyYW1lKHN0dWR5X2lkID0gcm93bmFtZXMoZGYpKSAlPiUgaW5uZXJfam9pbihkYXRhLmZyYW1lKGNsdXN0ZXIgPSBrbSRjbHVzdGVyKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJzdHVkeV9pZCIpLCBieT0ic3R1ZHlfaWQiKSAKCmBgYAoKCmBgYHtyfQpwYXRpZW50X2NsdXN0IDwtIGttLnJlcyAlPiUKICBpbm5lcl9qb2luKHN1YmplY3RUYWJsZSAlPiUgdHJhbnNtdXRlKHN0dWR5X2lkLCBTT0ZBX3RvdGFsKSxieT0ic3R1ZHlfaWQiKSAlPiUgCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogIHN1bW1hcmlzZShtZWFuU09GQV90b3RhbCA9IG1lYW4oU09GQV90b3RhbCkpICU+JSAKICBhcnJhbmdlKC1tZWFuU09GQV90b3RhbCkgJT4lIAogIG11dGF0ZShzZXZlcml0eV9sYWIgPSBjKCJzZXZlcmUiLCJtb2RlcmF0ZSIsIm1pbGQiKSkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigicm93bmFtZSIpICU+JSAKICBtdXRhdGUocm93bmFtZSA9IGFzLm51bWVyaWMocm93bmFtZSkpICU+JSAKICBsZWZ0X2pvaW4oa20ucmVzICU+JSB0cmFuc211dGUoc3R1ZHlfaWQsY2x1c3RlcikpICU+JSAKICBtdXRhdGUoY2x1c3Rlci5vcmlnID0gIGZjdF9yZW9yZGVyKGFzLmZhY3RvcihjbHVzdGVyKSxyb3duYW1lKSwKICAgICAgICAgc2V2ZXJpdHlfbGFiID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKHNldmVyaXR5X2xhYikscm93bmFtZSksCiAgICAgICAgIGNsdXN0ZXIgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3Iocm93bmFtZSkscm93bmFtZSkpCgpwYXRpZW50X2NsdXN0ICU+JSB3cml0ZV90c3YoZmlsZSA9IHBhc3RlMChyZXN1bHQuZGlyLCJQYXRpZW50Q2x1c3RlcmluZy50c3YiKSkKcGF0aWVudF9jbHVzdCAlPiUgc2F2ZVJEUyhmaWxlID0gcGFzdGUwKHJlc3VsdC5kaXIsIlBhdGllbnRDbHVzdGVyaW5nLnJkcyIpKQpgYGAKCiMjIyBGaWd1cmUgUzhELUYKCmBgYHtyfQpwY2FfRkNtZWRpYW4KYWN1dGUuZG5weC5lbGxib3cKCihwY2FERl9GQ21lZGlhbl9QQzFfNl9obSA8LSBwY2FERl9GQ21lZGlhbiAlPiUgCiAgZHBseXI6OnNlbGVjdChzdHVkeV9pZCxQQzE6UEM2KSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpICU+JSAKICB0KCkgJT4lIAogIEhlYXRtYXAobmFtZT0iUEMgdmFsdWUiLAogICAgICAgICAgY29sdW1uX2ttID0gMywKICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRiwKICAgICAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemU9NiksCiAgICAgICAgICByb3dfZGVuZF93aWR0aCA9IHVuaXQoNSwgIm1tIiksIAogICAgICAgICAgY29sdW1uX2RlbmRfaGVpZ2h0ID0gdW5pdCg1LCJtbSIpLAogICAgICAgICAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLCAKICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2hlaWdodCA9IHVuaXQoNSwgIm1tIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3Bvc2l0aW9uID0gInRvcGNlbnRlciIpKQopCmBgYAoKCgoKIyMjIEZpZ3VyZSBTOEcKYGBge3J9CmRmX2FjdXRlX3BhdGNsdXN0X2luY2xfY29udiA8LSBkYXRhLmxvbmcgJT4lIAogIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlICU+JSBkcGx5cjo6c2VsZWN0KERBaWQsVGltZSxzYW1wbGVfaWQsc3R1ZHlfaWQpLGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgaW5uZXJfam9pbihwYXRpZW50X2NsdXN0LGJ5PSJzdHVkeV9pZCIpICU+JSAKICAKICBmaWx0ZXIoVGltZT09IkFjdXRlIikgJT4lIAogICMjIGFkZGluZyBkYXRhIGZvciBNMTIgdGltZSBwb2ludAogIGJpbmRfcm93cyhkYXRhLmxvbmcgJT4lIAogICAgICAgICAgICAgIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlICU+JSBkcGx5cjo6c2VsZWN0KERBaWQsVGltZSxzYW1wbGVfaWQsc3R1ZHlfaWQpLGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgICAgICAgICAgICAgaW5uZXJfam9pbihwYXRpZW50X2NsdXN0LGJ5PSJzdHVkeV9pZCIpICU+JSAKICAgICAgICAgICAgICBmaWx0ZXIoVGltZT09Ik0xMiIpICU+JSAKICAgICAgICAgICAgICBtdXRhdGUoc2V2ZXJpdHlfbGFiID0gImNvbnZhbGVzY2VuY2UiKSkgJT4lIAogIG11dGF0ZShzZXZlcml0eV9sYWIgPSBmYWN0b3IoYXMuZmFjdG9yKHNldmVyaXR5X2xhYiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHM9Yygic2V2ZXJlIiwibW9kZXJhdGUiLCJtaWxkIiwiY29udmFsZXNjZW5jZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoInNldmVyZSIsIm1vZGVyYXRlIiwibWlsZCIsImNvbnZhbGVzY2VuY2UiKSkpIApgYGAKCgpgYGB7cn0KbXlfY29tcGFyaXNvbnNfc2V2ZXJlX2NvbnYgPC0gbGlzdChjKCJzZXZlcmUiLCAibW9kZXJhdGUiKSwgYygibW9kZXJhdGUiLCAibWlsZCIpLCBjKCJzZXZlcmUiLCAibWlsZCIpLGMoIm1pbGQiLCJjb252YWxlc2NlbmNlIikpCgoobGl2ZXIudGlzc3VlbGVha2FnZS5zZXZlcml0eS5wbG90IDwtIGRmX2FjdXRlX3BhdGNsdXN0X2luY2xfY29udiAlPiUKICBmaWx0ZXIoQXNzYXkgJWluJSBjKCJBR1hUIiwiSEFPMSIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXNldmVyaXR5X2xhYiwgeT1OUFgsIGNvbG9yPXNldmVyaXR5X2xhYiwgZmlsbD1zZXZlcml0eV9sYWIpKSArIAogIGdlb21fdmlvbGluKHRyaW0gPSBGLGFscGhhPS45KSArCiAgZ2VvbV9qaXR0ZXIoc2l6ZT0wLjI1LHNob3cubGVnZW5kID0gRiwgd2lkdGggPSAwLjA1LCBhbHBoYT0xLCBjb2xvcj0iZ3JleTIwIikgKwogIGdlb21fYm94cGxvdChhbHBoYT0uNyx3aWR0aD0wLjI1LG91dGxpZXIuc2hhcGUgPSBOQSxjb2xvcj0iYmxhY2siLCBmYXR0ZW4gPSAyLGx3ZD0uMjUsc2hvdy5sZWdlbmQgPSBGKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnNlcCA9ICJcbiIsCiAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBULAogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLnNpZ25pZiIgLAogICAgICAgICAgICAgICAgICAgICB2anVzdCA9IC41LAogICAgICAgICAgICAgICAgICAgICBzaXplPTIsCiAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IC4yLAogICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9bXlfY29tcGFyaXNvbnNfc2V2ZXJlX2NvbnYsCiAgICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKwogIGZhY2V0X3dyYXAofkFzc2F5LG5jb2wgPSA4LHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpICsKICBsYWJzKHg9IiIsCiAgICAgICBjb2xvcj1OVUxMLAogICAgICAgZmlsbD1OVUxMKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYyhwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpKSArIAogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjKHBhdGllbnRfa2NsdXN0M19sYWJfY29udikpCikKYGBgCgoKIyMgRmlndXJlIDRBCmBgYHtyfQooYWN1dGUuZG5weC5wY2EuY2x1c3RlcmVkIDwtIHBjYURGX0ZDbWVkaWFuICU+JSAKICBpbm5lcl9qb2luKHBhdGllbnRfY2x1c3QpICU+JSAKICBnZ3Bsb3QoYWVzKHg9UEMxLHk9UEMyLCBjb2xvcj1jbHVzdGVyKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0uNSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDMpICsKCiAgbGFicyhjb2xvcj0iQ2x1c3RlciIsCiAgICAgICB0aXRsZT0iZE5QWCIpICsKICBjb29yZF9lcXVhbChyYXRpbyA9IDEuNSkgICsgdGhlbWVfbWluaW1hbCgpKQoKYWN1dGUuZG5weC5wY2EuY2x1c3RlcmVkCgoKIGdnRXh0cmE6OmdnTWFyZ2luYWwoYWN1dGUuZG5weC5wY2EuY2x1c3RlcmVkLCB0eXBlPSJkZW5zaXR5Iixncm91cENvbG91ciA9IFRSVUUsIGdyb3VwRmlsbCA9IFRSVUUpCmBgYAoKCiMjIEZpZ3VyZSA0QgpgYGB7cn0KCm15X2NvbXBhcmlzb25zIDwtIGxpc3QoYygiMSIsICIyIiksIGMoIjIiLCAiMyIpLCBjKCIxIiwgIjMiKSkKCihjbHVzdGVyc19zb2ZhIDwtIHN1YmplY3RUYWJsZSAlPiUgCiAgICBpbm5lcl9qb2luKHBhdGllbnRfY2x1c3QsYnk9InN0dWR5X2lkIikgJT4lIAogICAgCiAgICBnZ3Bsb3QoYWVzKHg9Y2x1c3RlciwgeT1TT0ZBX3RvdGFsLCBjb2xvcj1jbHVzdGVyLCBmaWxsPWNsdXN0ZXIpKSArCiAgICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMixzaG93LmxlZ2VuZCA9IFQsIHNpemU9MC41LGFscGhhPS43KSArCiAgICBnZW9tX2JveHBsb3QoYWxwaGE9MSx3aWR0aD0wLjMsY29sb3I9ImJsYWNrIixvdXRsaWVyLmNvbG91ciA9IE5BLCBmYXR0ZW4gPSAyLGx3ZD0uMjUsc2hvdy5sZWdlbmQgPSBGKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKCJTZXF1ZW50aWFsIE9yZ2FuIEZhaWx1cmUgQXNzZXNzbWVudCAoU09GQSkgc2NvcmUiKSkgKyAKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9cGF0aWVudF9rY2x1c3QzKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDMpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMTYpKSArCiAgICBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0IiwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbC5zZXAgPSAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBULAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gInAuc2lnbmlmIiAsCiAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgICBzaXplPTIsCiAgICAgICAgICAgICAgICAgICAgICAgbHdkID0gLjIsCiAgICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvbnMgPW15X2NvbXBhcmlzb25zKSArCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSJub25lIikpCmBgYAoKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnN1YmplY3RUYWJsZSAlPiUgCiAgICBpbm5lcl9qb2luKHBhdGllbnRfY2x1c3QsYnk9InN0dWR5X2lkIikgJT4lIAogIHRyYW5zbXV0ZShzdHVkeV9pZCwKICAgICAgICAgICAgZW5kZW1pYywKICAgICAgICAgICAgc2V2ZXJlXzUgPSBpZmVsc2Uoc2V2ZXJlXzU9PTEsInllcyIsIm5vIiksIAogICAgICAgICAgICBzZXZlcml0eV9sYWIpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMoZW5kZW1pYyxzZXZlcmVfNSxzZXZlcml0eV9sYWIpKSAlPiUgCiAgbXV0YXRlKG5hbWUgPSBmYWN0b3IobmFtZSwgbGV2ZWxzID0gYygiZW5kZW1pYyIsInNldmVyZV81Iiwic2V2ZXJpdHlfbGFiIikpKSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gZmFjdG9yKHZhbHVlLCBsZXZlbHMgPSBjKCJwcmV2aW91c2x5X2V4cG9zZWQiLCJwcmltYXJ5X2luZmVjdGVkIiwibm8iLCJ5ZXMiLCJzZXZlcmUiLCJtb2RlcmF0ZSIsIm1pbGQiKSkpICU+JSAKICAKICBsZWZ0X2pvaW4ocGF0aWVudF9jbHVzdCkgJT4lIAogICAgbGVmdF9qb2luKHN1YmplY3RUYWJsZSAlPiUgdHJhbnNtdXRlKHN0dWR5X2lkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXZlcmVfNSA9IGlmZWxzZShzZXZlcmVfNT09MSwieWVzIiwibm8iKSwgCiAgICApKSAlPiUgCiAgCiAgZ2dwbG90KAogICAgYWVzKHggPSBuYW1lLAogICAgICAgICN5ID0gbiwKICAgICAgICBzdHJhdHVtID0gdmFsdWUsIAogICAgICAgIGFsbHV2aXVtID0gc3R1ZHlfaWQsCiAgICAgICAgbGFiZWwgPSB2YWx1ZSkpKwogIGdlb21fZmxvdyhhZXMoZmlsbCA9IHNldmVyZV81KSkgKwogIGdlb21fc3RyYXR1bShhZXMoZmlsbCA9IHZhbHVlKSx3aWR0aCA9IC40KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhlbmRlbWljMl9jb2wsYygieWVzIj0idG9tYXRvIiwibm8iID0gImdyZXk4MCIpLHBhdGllbnRfa2NsdXN0M19sYWIpKSArCiAgZ2VvbV90ZXh0KHN0YXQgPSAic3RyYXR1bSIpKwogIHRoZW1lX3ZvaWQoKSArCiAgbGFicyhmaWxsPU5VTEwpCmBgYAoKIyMgRmlndXJlIDRDCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnByb3QuZGF0YS40LmNvcnIgPC0gZGF0YS5sb25nICU+JQogIGlubmVyX2pvaW4oZGFwLnJlcyxieT1jKCJBc3NheSIsICJVbmlQcm90IikpICU+JSAKICBmaWx0ZXIocC5hZGo8PTAuMDUsCiAgICAgICAgIGFicyhsb2dGQyk+MSwKICApICU+JSAKICBwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9IE5QWCwgbmFtZXNfZnJvbSA9IEFzc2F5LGlkX2NvbHMgPSBzYW1wbGVfaWQpICU+JSAKICBpbm5lcl9qb2luKHNhbXBsZVRhYmxlX3NpbXBsZSAlPiUgZmlsdGVyKFRpbWU9PSJBY3V0ZSIpICU+JSB0cmFuc211dGUoc2FtcGxlX2lkLHN0dWR5X2lkKSwgYnk9InNhbXBsZV9pZCIpICU+JQogIGRwbHlyOjpzZWxlY3QoLXNhbXBsZV9pZCkgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfaWQsIGV2ZXJ5dGhpbmcoKSkgCgoKY2xpbmljYWwuZmVhdC5saXN0IDwtIGMoImluZl9yYmNfbWF4IiwgInJlc3BfcmF0ZV9tYXgiLCJzYXQiLCAic3lzdF9icF9taW4iLAogICAgICAgICAgICAgICAgICAgICAgICAicF9hbGF0IiwgInBfYXNhdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICJoYl9taW4iLCJ3YmNfY291bnQiLCJwbHRfY291bnRfbWluIiwiY3JwX21heCIsImJpbGlfbWF4IiwiY3JlYV9tYXgiLCJTT0ZBX2NucyIsIlNPRkFfbGl2ZXIiLCJTT0ZBX3JlbmFsIiwiU09GQV9jb2FnIiwiU09GQV9yZXNwIiwiU09GQV90b3RhbCIpCiAgCmNsaW4uZGF0YS40LmNvcnIgPC0KICBzdWJqZWN0VGFibGUgJT4lIAogICAgICBsZWZ0X2pvaW4oY2xpbmNoZW1fc3R1ZHlfcGF0c19hY3V0ZS53aWRlLCBieT0ic3R1ZHlfaWQiKSAlPiUgCgogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfaWQsIGFsbF9vZihjbGluaWNhbC5mZWF0Lmxpc3QpKQoKCm15X2NvbXBhcmlzb25zX3NldmVyZSA8LSBsaXN0KGMoInNldmVyZSIsICJtb2RlcmF0ZSIpLCBjKCJtb2RlcmF0ZSIsICJtaWxkIiksIGMoInNldmVyZSIsICJtaWxkIikpCgpkZiA8LSBjbGluLmRhdGEuNC5jb3JyICU+JSAKICBkcGx5cjo6c2VsZWN0KHN0dWR5X2lkLCBjbGluaWNhbC5mZWF0Lmxpc3QsIC1jb250YWlucygiU09GQSIpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHM9IC1zdHVkeV9pZCkgJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCkgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZ3JvdXBfYnkobmFtZSwgc2V2ZXJpdHlfbGFiKSAlPiUgCiAgbXV0YXRlKG5fZ3JvdXA9IGFzLmNoYXJhY3RlcihuKCkpLAogICAgICAgICAgICAgICAgICBsYWJlbF9ncm91cD0gZmFjdG9yKHBhc3RlMCgnbiA9ICcsIG5fZ3JvdXApKSkgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgIG11dGF0ZShsYWJlbF9wb3MgPSBtaW4odmFsdWUpLAogICAgICAgICAgc3ViY2F0ID0gY2FzZV93aGVuKG5hbWUgJWluJSBjKCJiaWxpX21heCIsICJwX2FsYXQiLCJwX2FzYXQiKSB+ICJMaXZlciBmdW5jdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSAlaW4lIGMoImhiX21pbiIsIndiY19jb3VudCIsICJwbHRfY291bnQiKSB+ICJCbG9vZCBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSAlaW4lIGMoInJlc3BfcmF0ZV9tYXgiLCJzYXQiLCJzeXN0X2JwX21pbiIpIH4gIkNpcmN1bGF0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdD1OQSkpICU+JSAKICAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUobmFtZSA9IGZhY3RvcihuYW1lLCBsZXZlbHMgPSBjKCJjcnBfbWF4IiwiY3JlYV9tYXgiLCJpbmZfcmJjX21heCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImhiX21pbiIsIndiY19jb3VudCIsInBsdF9jb3VudF9taW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiaWxpX21heCIsInBfYXNhdCIsInBfYWxhdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJlc3BfcmF0ZV9tYXgiLCJzYXQiLCJzeXN0X2JwX21pbiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSkgCgpzaW5nbGVfZmFjZXRfZnVuID0gZnVuY3Rpb24oZGF0YSkoIAogIGRhdGEgJT4lIAogICAgZ2dwbG90KGFlcyh4PXNldmVyaXR5X2xhYiwgeT12YWx1ZSwgZmlsbD0gc2V2ZXJpdHlfbGFiKSkgKwogICAgZ2VvbV92aW9saW4odHJpbT1GLCBzaG93LmxlZ2VuZCA9IEYsIHdpZHRoPS42LGx3ZD0uMjUpICsKICAgIGdlb21faml0dGVyKHNpemU9MC4wNSx3aWR0aCA9IC4xLCBzaG93LmxlZ2VuZCA9IEYpICsKICAgIGdlb21fYm94cGxvdChhZXMoZmlsbD1zZXZlcml0eV9sYWIpLGFscGhhPS43LCBvdXRsaWVyLnNoYXBlID0gTkEsd2lkdGg9LjIsIHNob3cubGVnZW5kID0gRixsd2Q9LjI1KSArCiAgICB0aGVtZV9idyhiYXNlX3NpemUgPSA2KSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoLjIsMCkpKwogICAgZmFjZXRfZ3JpZCh+bGFiZWxfbmFtZSkgKwogICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGF0aWVudF9rY2x1c3QzX2xhYikgKwogICAgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwuc2VwID0gIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICBoaWRlLm5zID0gVCwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLnNpZ25pZiIsIAogICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgIHNpemU9MiwKICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zX3NldmVyZSkgKwogICAgbGFicyhmaWxsPU5VTEwsCiAgICAgICAgIHg9TlVMTCkgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9ZGF0YSRsYWJlbF9ncm91cCkpCgoKIyMgCnBfbGlzdCA8LSBkZiAlPiUgCiAgbXV0YXRlKG5hbWUgPSBmYWN0b3IobmFtZSwgbGV2ZWxzID0gYygiY3JwX21heCIsImNyZWFfbWF4IiwiaW5mX3JiY19tYXgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoYl9taW4iLCJ3YmNfY291bnQiLCJwbHRfY291bnRfbWluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmlsaV9tYXgiLCJwX2FzYXQiLCJwX2FsYXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJyZXNwX3JhdGVfbWF4Iiwic2F0Iiwic3lzdF9icF9taW4iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSksCiAgICAgICAgIGxhYmVsX25hbWUgPSBjYXNlX3doZW4obmFtZSA9PSAiYmlsaV9tYXgiIH4gIkJpbGlydWJpblxuKFxVMDAzQkNtb2wvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImNyZWFfbWF4IiB+ICJDcmVhdGluaW5lXG4oXFUwMDNCQ21vbC9MKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAiY3JwX21heCIgfiAiQ1JQXG4obWcvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImhiX21pbiIgfiAiSGVtb2dsb2JpblxuKGcvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImluZl9yYmNfbWF4IiB+ICJQYXJhc2l0ZW1pYVxuKCUpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJwbHRfY291bnRfbWluIiB+ICJQbGF0ZWxldFxuKGNvdW50cykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInNhdCIgfiAiU2F0dXJhdGlvblxuKCUpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJwX2FzYXQiIH4gIkFTVFxuKFUvTCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInBfYWxhdCIgfiAiQUxUXG4oVS9MKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAicmVzcF9yYXRlX21heCIgfiAiUmVzcGlyYXRpb25zIHJhdGVcbihicG0pIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJ3YmNfY291bnQiIH4gIldoaXRlIGJsb29kIGNlbGxzXG4oY291bnRzKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAic3lzdF9icF9taW4iIH4gIlN5c3RvbGljIGJsb29kXG5wcmVzc3VyZSAobW1IZykiCiAgICAgICAgICAgICAgICksCiAgICAgICAgIGxhYmVsX3VuaXQgPSBjYXNlX3doZW4obmFtZSA9PSAiYmlsaV9tYXgiIH4gInVuaXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImNyZWFfbWF4IiB+ICJ1bml0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJjcnBfbWF4IiB+ICJtZy9MIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJoYl9taW4iIH4gImcvZEwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImluZl9yYmNfbWF4IiB+ICIlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJwbHRfY291bnRfbWluIiB+ICJjb3VudHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInNhdCIgfiAiJSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAicF9hc2F0IiB+ICJ1bml0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJwX2FsYXQiIH4gInVuaXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInJlc3BfcmF0ZV9tYXgiIH4gImJwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAid2JjX2NvdW50IiB+ICJjb3VudHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gInN5c3RfYnBfbWluIiB+ICJtbUhnIgogICAgICAgICAgICAgICApKSAlPiUgCiAgYXJyYW5nZShuYW1lKSAlPiUgCiAgZ3JvdXBfYnkobmFtZSkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKHNpbmdsZV9wbG90ID0gcHVycnI6Om1hcChkYXRhLCBzaW5nbGVfZmFjZXRfZnVuKSkKICAgICAgICAgCgpjbGluLmRhdGEuc2V2ZXJpdHkuZ3JvdXBzLm5ldyA8LSB3cmFwX3Bsb3RzKHBfbGlzdCRzaW5nbGVfcGxvdCwgbmNvbD0zKQoKY2xpbi5kYXRhLnNldmVyaXR5Lmdyb3Vwcy5uZXcuZGF0YSA8LSBwX2xpc3QgJT4lCiAgdW5uZXN0KGRhdGEpICU+JSAKICBjb21wYXJlX21lYW5zKAogICAgdmFsdWUgfiBzZXZlcml0eV9sYWIsIGRhdGEgPSAuLCBncm91cC5ieSA9ICJuYW1lIiwKICAgIG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIpICU+JSAKICB0cmFuc211dGUobmFtZSwgZ3JvdXAxLCBncm91cDIsIHAsIHAuYWRqLCBwLnNpZ25pZiwgbWV0aG9kKSAKCiMjIHNob3cgcGxvdApjbGluLmRhdGEuc2V2ZXJpdHkuZ3JvdXBzLm5ldwpgYGAKCgoKCiMjIEZpZ3VyZSA0RAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmRhdGFfbmVzdGVkLnBhdGNsdXN0IDwtIGRhdGEubG9uZyAlPiUgCiAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUsIGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgaW5uZXJfam9pbihwYXRpZW50X2NsdXN0LGJ5PSJzdHVkeV9pZCIpICU+JSAKICBtdXRhdGUoYWxsX3ZzXzEgPSBpZmVsc2UoY2x1c3Rlci5vcmlnICVpbiUgYygiMiIsIjMiKSwicmVzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjbHVzdGVyLm9yaWcgPT0iMSIsIjEiLE5BKSksCiAgICAgICAgIGFsbF92c18yID0gaWZlbHNlKGNsdXN0ZXIub3JpZyAlaW4lIGMoIjEiLCIzIiksInJlc3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY2x1c3Rlci5vcmlnID09IjIiLCIyIixOQSkpLAogICAgICAgICBhbGxfdnNfMyA9IGlmZWxzZShjbHVzdGVyLm9yaWcgJWluJSBjKCIyIiwiMSIpLCJyZXN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNsdXN0ZXIub3JpZyA9PSIzIiwiMyIsTkEpKSkgJT4lIAogIGdyb3VwX2J5KFVuaVByb3QsQXNzYXkpICU+JSAKICBuZXN0KCkKCmdfdnNfY29udiA8LSBkYXRhX25lc3RlZC5wYXRjbHVzdCAlPiUKICAgbXV0YXRlKGxtZS5yZXMgPSBwdXJycjo6bWFwKGRhdGEsIH4gbG1lcihOUFggfiBUaW1lICogc2V2ZXJpdHlfbGFiICsgKDF8c3R1ZHlfaWQpLCBSRU1MID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSAueCAlPiUgZHBseXI6OmZpbHRlcihUaW1lIT0iRDEwIikpKSwKICAgICAgICAgbG1lLnRpZHkgPSBwdXJycjo6bWFwKGxtZS5yZXMsIH4gYnJvb20ubWl4ZWQ6OnRpZHkoLikpLAogICAgICAgICBwb3N0aG9jLnRpbWVfZXhwb3N1cmUgPSBwdXJycjo6bWFwKGxtZS5yZXMsIH4gc3VtbWFyeShjb250cmFzdChlbW1lYW5zKC4sIH4gVGltZSAqIHNldmVyaXR5X2xhYiksIG1ldGhvZCA9ICJwYWlyd2lzZSIpKSAlPiUgdGliYmxlKCkpCiAgICAgICAgICkKCmdfdnNfY29udl9wYWRqIDwtIGdfdnNfY29udiAlPiUgCiAgdW5uZXN0KGNvbHM9InBvc3Rob2MudGltZV9leHBvc3VyZSIpICU+JSAKICBmaWx0ZXIoY29udHJhc3QgJWluJWMoIkFjdXRlIHNldmVyZSAtIE0xMiBzZXZlcmUiLAogICAgICAgICAgICAgICAgICAgICAgICAiQWN1dGUgbW9kZXJhdGUgLSBNMTIgbW9kZXJhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAiQWN1dGUgbWlsZCAtIE0xMiBtaWxkIikpICU+JSAKICAgICAgdHJhbnNtdXRlKEFzc2F5LCBVbmlQcm90LCBjb250cmFzdCwgZXN0aW1hdGUsU0UsZGYsdC5yYXRpbyxwLnZhbHVlKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICAgIGdyb3VwX2J5KGNvbnRyYXN0KSAlPiUgCiAgbXV0YXRlKHAuYWRqID0gcC5hZGp1c3QocC52YWx1ZSwgbWV0aG9kPSJmZHIiKSwKICAgICAgICAgICAgICAgICAgRkRSID0gaWZlbHNlKHAuYWRqIDw9IDAuMDEsIFRSVUUsRkFMU0UpKSAlPiUgCiAgICB1bmdyb3VwKCkgJT4lIAogIGFycmFuZ2UocC5hZGopCgoKCihzZXZlcml0eV9ncm91cHNfY29udl92b2xjIDwtIGdfdnNfY29udl9wYWRqICU+JSAKICBncm91cF9ieShjb250cmFzdCkgJT4lIAogIG11dGF0ZShzZXZlcml0eV9sYWIgPSBjYXNlX3doZW4oZ3JlcGwoInNldmVyZSIsY29udHJhc3QpIH4gInNldmVyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJtb2RlcmF0ZSIsY29udHJhc3QpIH4gIm1vZGVyYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm1pbGQiLGNvbnRyYXN0KSB+ICJtaWxkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSksCiAgICAgICAgIHNldmVyaXR5X2xhYiA9IGZhY3RvcihzZXZlcml0eV9sYWIsIGxldmVscz1jKCJzZXZlcmUiLCJtb2RlcmF0ZSIsIm1pbGQiKSksCiAgICAgICAgIHNpZ19jb2wgPSBjYXNlX3doZW4oRkRSPT1UIH4gc2V2ZXJpdHlfbGFiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gTkEpKSAlPiUgCiAgI3NsaWNlX21heChvcmRlcl9ieSA9IGVzdGltYXRlLCBuPTEpICU+JSAKICAgIGdncGxvdChhZXMoeD1zZXZlcml0eV9sYWIsIHk9IGVzdGltYXRlLCBjb2xvcj1zaWdfY29sKSkgKwogICAgZ2VvbV9qaXR0ZXIod2lkdGg9LjEsYWxwaGE9LjIsIHNob3cubGVnZW5kID0gRixzaXplPS41LCBzaGFwZT0xNikgKwogICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9IC4gJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoc2V2ZXJpdHlfbGFiKSAlPiUgc2xpY2VfbWF4KG49OCxvcmRlcl9ieSA9IGVzdGltYXRlKSwgYWVzKGxhYmVsPUFzc2F5KSwgc2hvdy5sZWdlbmQgPSBGLGZvcmNlID0gLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplPTAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuYWxwaGE9LjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPTEuNSxtYXgub3ZlcmxhcHMgPSAxNSwgY29sb3I9ImdyYXkzNSIpICsKICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhPSAuICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KHNldmVyaXR5X2xhYikgJT4lIHNsaWNlX21pbihuPTgsb3JkZXJfYnkgPSBlc3RpbWF0ZSksIGFlcyhsYWJlbD1Bc3NheSksIHNob3cubGVnZW5kID0gRixmb3JjZSA9IC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZT0wLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWdtZW50LmFscGhhPS4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT0xLjUsIG1heC5vdmVybGFwcyA9IDE1LCBjb2xvcj0iZ3JheTM1IikgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIAogICAgICAgICAgICAgICBsaW5ldHlwZSA9IDMpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYXRpZW50X2tjbHVzdDNfbGFiLG5hLnZhbHVlID0gImdyZXkiKSArCiAgICBsYWJzKHg9TlVMTCwKICAgICAgICAgdGl0bGU9IkVhY2ggZ3JvdXAgdnMgY29udmFsZWNlbmNlIiwKICAgICAgICAgc3VidGl0bGUgPSAibWl4ZWQgZWZmZWN0IG1vZGVsIGFwcHJvYWNoIC0gYWN1dGVfc2V2ZXJpdHkgdnMgbTEyX3NldmVyaXR5IiwKICAgICAgICAgY2FwdGlvbj0iRkRSIDwgMC4wMSIpKQpgYGAKCiMjIEZpZ3VyZSA0RQoKYGBge3J9CnJlcXVpcmUoVXBTZXRSKSAjIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9VcFNldFIvdmlnbmV0dGVzL2Jhc2ljLnVzYWdlLmh0bWwKCmdfdnNfY29udl9wYWRqX3RtcC5saXN0IDwtIGdfdnNfY29udl9wYWRqICU+JSAKICBncm91cF9ieShjb250cmFzdCkgJT4lIAogIG11dGF0ZShzZXZlcml0eV9sYWIgPSBjYXNlX3doZW4oZ3JlcGwoInNldmVyZSIsY29udHJhc3QpIH4gInNldmVyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJtb2RlcmF0ZSIsY29udHJhc3QpIH4gIm1vZGVyYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm1pbGQiLGNvbnRyYXN0KSB+ICJtaWxkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSksCiAgICAgICAgIHNldmVyaXR5X2xhYiA9IGZhY3RvcihzZXZlcml0eV9sYWIsIGxldmVscz1jKCJzZXZlcmUiLCJtb2RlcmF0ZSIsIm1pbGQiKSksCiAgICAgICAgIHNpZ19jb2wgPSBjYXNlX3doZW4oRkRSPT1UIH4gc2V2ZXJpdHlfbGFiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gTkEpKSAlPiUKICAgIGZpbHRlcihlc3RpbWF0ZT4xKSAlPiUgCiAgZ3JvdXBfYnkoc2V2ZXJpdHlfbGFiKSAlPiUKICBzdW1tYXJpc2UobGlzdCA9IGxpc3QoQXNzYXkpKSAlPiUKICBtdXRhdGUobGlzdCA9IHNldE5hbWVzKGxpc3QsIHNldmVyaXR5X2xhYikpICU+JQogIHB1bGwobGlzdCkKCnNldmVyZV9sb2cxIDwtIGludGVyc2VjdChzZXRkaWZmKGdfdnNfY29udl9wYWRqX3RtcC5saXN0JHNldmVyZSwgZ192c19jb252X3BhZGpfdG1wLmxpc3QkbWlsZCksCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXRkaWZmKGdfdnNfY29udl9wYWRqX3RtcC5saXN0JHNldmVyZSwgZ192c19jb252X3BhZGpfdG1wLmxpc3QkbW9kZXJhdGUpKQoKcGRmKHBhc3RlMChyZXN1bHQudG1wLmRpciwic2V2ZXJpdHlfZGFwc191cHNldC5wZGYiKSx3aWR0aCA9IDcsIGhlaWdodCA9IDMpIAooVXBTZXRSOjp1cHNldChmcm9tTGlzdChnX3ZzX2NvbnZfcGFkal90bXAubGlzdCksCiAgICAgICAgICAgICAgb3JkZXIuYnkgPSAiZnJlcSIscG9pbnQuc2l6ZSA9IDIsCiAgICAgICAgICAgICAgdGV4dC5zY2FsZSA9IDEuMiwKICAgICAgICAgICAgICNtYi5yYXRpbyA9IGMoMC42LCAwLjQpLAogICAgICAgICAgICAgIHNldHMuYmFyLmNvbG9yID0gYygic2V2ZXJlIiA9ICIjY2EwMDIwIiwibW9kZXJhdGUiID0gIiNmNGE1ODIiLCAibWlsZCIgPSAiIzkyYzVkZSIpLAogICAgICAgICAgICAgIGtlZXAub3JkZXIgPSBUUlVFLAogICAgICAgICAgICAgIG1haW5iYXIueS5sYWJlbCA9ICJOdW1iZXIgb2YgUHJvdGVpbnMiLCAKICAgICAgICAgICAgICBzZXRzLngubGFiZWwgPSAiUHJvdGVpbnMgcGVyIGdyb3VwIikpCmRldi5vZmYoKQpgYGAKCgojIyBTdXBwbGVtZW50YXJ5IFRhYmxlIFMzCmBgYHtyfQpsaWJyYXJ5KGd0c3VtbWFyeSkKKHNldmVyaXR5VGFibGUgPC0gc3ViamVjdFRhYmxlICU+JSAKICBtdXRhdGUod2JjX2NvdW50ID0gYXMubnVtZXJpYyh3YmNfY291bnQpLAogICAgICAgICBzYXQgPSBhcy5udW1lcmljKHNhdCkpICU+JSAKICBsZWZ0X2pvaW4ocGF0aWVudF9jbHVzdCwgYnk9InN0dWR5X2lkIikgJT4lIAogICAgdGJsX3N1bW1hcnkoaW5jbHVkZSA9IGMoaW5mX3JiY19tYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcnBfbWF4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlsaV9tYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcmVhX21heCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BfcmF0ZV9tYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeXN0X2JwX21pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsdF9jb3VudF9taW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYl9taW4pLAogICAgICAgICAgICAgIGJ5ID0gc2V2ZXJpdHlfbGFiLCAjIHNwbGl0IHRhYmxlIGJ5IGdyb3VwCiAgICAgICAgICAgICAgc3RhdGlzdGljID0gbGlzdCgKICAgICAgICAgICAgICAgIGFsbF9jb250aW51b3VzKCkgfiAie21lZGlhbn0gKHttaW59LXttYXh9KSIsCiAgICAgICAgICAgICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gLyB7Tn0gKHtwfSUpIgogICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgZGlnaXRzID0gYWxsX2NvbnRpbnVvdXMoKSB+IDIsCiAgICAgICAgICAgICAgbWlzc2luZ190ZXh0ID0gIihNaXNzaW5nKSIpICU+JSAKICBhZGRfbigpICU+JSAjIGFkZCBjb2x1bW4gd2l0aCB0b3RhbCBudW1iZXIgb2Ygbm9uLW1pc3Npbmcgb2JzZXJ2YXRpb25zCiAgYWRkX3AoKSAlPiUgIyB0ZXN0IGZvciBhIGRpZmZlcmVuY2UgYmV0d2VlbiBncm91cHMKICBtb2RpZnlfaGVhZGVyKGxhYmVsID0gIioqVmFyaWFibGUqKiIpICU+JSAjIHVwZGF0ZSB0aGUgY29sdW1uIGhlYWRlcgogIGJvbGRfbGFiZWxzKCkpCmBgYAoKCmBgYHtyfQpzdWJqZWN0VGFibGUgJT4lIAogIG11dGF0ZSh3YmNfY291bnQgPSBhcy5udW1lcmljKHdiY19jb3VudCksCiAgICAgICAgIHNhdCA9IGFzLm51bWVyaWMoc2F0KSkgJT4lIAogIGxlZnRfam9pbihwYXRpZW50X2NsdXN0LCBieT0ic3R1ZHlfaWQiKSAlPiUgCiAgdHJhbnNtdXRlKHN0dWR5X2lkLCAKICAgICAgICAgICAgc2V2ZXJpdHlfbGFiLAogICAgICAgICAgICBkaWZmX2FjdXRlU2FtcGxlX3RyZWF0bWVudCxkaWZmX2FjdXRlU2FtcGxlX3RyZWF0bWVudC5hYnMsCiAgICAgICAgICAgIGRpZmZfYWN1dGVTYW1wbGVfc3B0X2N1cnJlbnQsZGlmZl9hY3V0ZVNhbXBsZV9zcHRfY3VycmVudC5hYnMpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKHN0dWR5X2lkLHNldmVyaXR5X2xhYikpICU+JSAKCmNvbXBhcmVfbWVhbnMoCiAgICB2YWx1ZSB+IHNldmVyaXR5X2xhYiwgZGF0YSA9IC4sIGdyb3VwLmJ5ID0gIm5hbWUiLAogICAgbWV0aG9kID0gIndpbGNveC50ZXN0IikKYGBgCgojIyBTdXBwbGVtZW1lbnRhcnkgVGFibGUgUzQKCmBgYHtyfQojY2xpbi5kYXRhLnNldmVyaXR5Lmdyb3Vwcy5uZXcuZGF0YSAlPiUKICMgd3JpdGVfdHN2KHBhc3RlMChyZXN1bHQuZGlyLCJTdXBwbGVtZW50YXJ5X1RhYmxlUzRfQ2xpbmljYWxDaGVtaXN0cnlfc2V2ZXJpdHlfZ3JvdXBzLnRzdiIpKQoKY2xpbi5kYXRhLnNldmVyaXR5Lmdyb3Vwcy5uZXcuZGF0YSAlPiUgaGVhZCgpCmBgYAoKIyMjIEZpZ3VyZSBTOEEKYGBge3J9CnByb3QuaW5wdXQgPC0gcHJvdC5kYXRhLjQuY29yciAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9pZCIpCmNsaW4uaW5wdXQgPC0gY2xpbi5kYXRhLjQuY29yciAlPiUgZHBseXI6OnNlbGVjdChzdHVkeV9pZCxjKHBsdF9jb3VudF9taW4saW5mX3JiY19tYXgsY3JwX21heCxoYl9taW4sYmlsaV9tYXgsY3JlYV9tYXgscF9hbGF0LHBfYXNhdCkpICU+JSAjLGNvbnRhaW5zKCJTT0ZBIikpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygic3R1ZHlfaWQiKQoKY29yLnJlcyA8LSBwcm90LmlucHV0W3Jvd25hbWVzKGNsaW4uaW5wdXQpLF0gJT4lIAogIGNvcnJlbGF0aW9uOjpjb3JyZWxhdGlvbihkYXRhMiA9IGNsaW4uaW5wdXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJzcGVhcm1hbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICByZWR1bmRhbnQgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9hZGp1c3QgPSAiZmRyIikgJT4lIAogIHRpYmJsZSgpCmBgYAoKYGBge3J9CmRmIDwtIGNvci5yZXMgJT4lCiAgZmlsdGVyKG5fT2JzID49IDM3LCAKICAgICAgICAgcDw9MC4wNSwKICAgICAgICAgYWJzKHJobyk+PTAuNDUKICAgICAgICAgKSAlPiUgCiAgdHJhbnNtdXRlKGZyb209UGFyYW1ldGVyMiwgCiAgICAgICAgICAgIHRvPVBhcmFtZXRlcjEsCiAgICAgICAgICAgIHZhbHVlPXJobykgJT4lIAogIGdyb3VwX2J5KHRvKSAlPiUgCiAgbXV0YXRlKG5fcHJvdCA9bigpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShmcm9tKSAlPiUgCiAgbXV0YXRlKG5fY2xpbiA9IG4oKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgYXJyYW5nZShkZXNjKG5fcHJvdCksbl9jbGluKSAlPiUgCiAgIG11dGF0ZShmcm9tID0gY2FzZV93aGVuKGZyb209PSJjcnBfbWF4In4iQ1JQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tPT0icF9hbGF0In4iQUxUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tPT0icF9hc2F0In4iQVNUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tPT0icGx0X2NvdW50X21pbiJ+IlBsYXRlbGV0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbT09ImluZl9yYmNfbWF4IiB+IlBhcmFzaXRlbWlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tPT0iYmlsaV9tYXgifiJCaWxpcnViaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZyb209PSJoYl9taW4iIH4iSGVtb2dsb2JpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbT09ImNyZWFfbWF4In4iQ3JlYXRpbmluZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQ9ZnJvbSkpIAogIApkZgpgYGAKCmBgYHtyfQojc3RyaW5nIDwtIHVuaXF1ZShkZiRmcm9tKSAKI3N0cmluZyA8LSBzZXRkaWZmKHVuaXF1ZShkZiRmcm9tKSxuYW1lcyhjbGluX21hcmtlcl9jb2xzKSkKI2NvbC5ncmlkX2NsaW4gPC0gc2V0TmFtZXMoc2FtcGxlKGJyZXdlci5wYWwobGVuZ3RoKHN0cmluZyksbmFtZT0iU2V0MSIpKSxzdHJpbmcpCgpzdHJpbmdfcHJvdGVpbnMgPC0gdW5pcXVlKGRmJHRvKQpjb2wuZ3JpZC5wcm90IDwtIHNldE5hbWVzKHJlcCgiZ3JleTgwIixsZW5ndGgoc3RyaW5nX3Byb3RlaW5zKSksIHN0cmluZ19wcm90ZWlucykKCgoKY29sLmdyaWQgPC0gYyhjbGluX21hcmtlcl9jb2xzLAogICAgICAgICAgICAgICNjb2wuZ3JpZF9jbGluLCAKICAgICAgICAgICAgICBjb2wuZ3JpZC5wcm90KQoKIyMgaGlnaGxpZ2h0CiMgdGhyZWUtY29sdW1uIGRhdGEgZnJhbWUgaW4gd2hpY2ggdGhlIGZpcnN0IHR3byBjb2x1bW5zIGNvcnJlc3BvbmQgdG8gcm93IG5hbWVzIGFuZCBjb2x1bW4gbmFtZXMgaW4gdGhlIG1hdHJpeCwgYW5kIHRoZSB0aGlyZCBjb2x1bW4gY29ycmVzcG9uZHMgdG8gdGhlIGdyYXBoaWMgcGFyYW1ldGVycwpib3JkZXJfZGYgPSBkYXRhLmZyYW1lKGMoIlBhcmFzaXRlbWlhIiksIGMoIkNBTENBIiksIGMoMSkpCgoKcGRmKHBhc3RlMChyZXN1bHQudG1wLmRpciwiY2hvcmREaWFncmFtLnBkZiIpKSAjd2lkdGggNi45CgpjaXJjb3MucGFyKGdhcC5hZnRlciA9IGMocmVwKDEsIGxlbmd0aCh1bmlxdWUoZGZbWzFdXSkpLTEpLCAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICByZXAoMSwgbGVuZ3RoKHVuaXF1ZShkZltbMl1dKSktMSksIDE1KSkKY2hvcmREaWFncmFtKGRmLAogICAgICAgICAgICAjICBiaWcuZ2FwID0gMjUsCiAgICAgICAgICAgICBncmlkLmNvbCA9IGNvbC5ncmlkLAogICAgICAgICAgICAgI2Fubm90YXRpb25UcmFjayA9ICJncmlkIiwKICAgICAgICAgICAgICAgICAgICAgICAgYmlnLmdhcCA9IDEwLAogICAgICAgICAgICBzbWFsbC5nYXAgPSAxLApsaW5rLmJvcmRlciA9IGJvcmRlcl9kZiwKICAgICAgICAgICAgIGFubm90YXRpb25UcmFjayA9IE5VTEwsCiAgICAgICAgICAgICBwcmVBbGxvY2F0ZVRyYWNrcyA9IGxpc3QodHJhY2suaGVpZ2h0ID0gLjEpKSNtYXgoc3Ryd2lkdGgodW5saXN0KGRpbW5hbWVzKGRmKSkpKSkpCmNpcmNvcy50cmFjayh0cmFjay5pbmRleCA9IDEsIHBhbmVsLmZ1biA9IGZ1bmN0aW9uKHgsIHkpIHsKICBjaXJjb3MudGV4dChDRUxMX01FVEEkeGNlbnRlciwgCiAgICAgICAgICAgICAgQ0VMTF9NRVRBJHlsaW1bMV0sCiAgICAgICAgICAgICAgQ0VMTF9NRVRBJHNlY3Rvci5pbmRleCwKICAgICAgICAgICAgICBmYWNpbmcgPSAiY2xvY2t3aXNlIiwKICAgICAgICAgICAgICBjZXggPSAwLjYsCiAgICAgICAgICAgICAgbmljZUZhY2luZyA9IFRSVUUsIAogICAgICAgICAgICAgIGFkaiA9IGMoMCwgMC45KSkKfSwKYmcuYm9yZGVyID0gTkEpCgojCmRldi5vZmYoKQpjaXJjb3MuY2xlYXIoKQpgYGAKCiMgRmlndXJlIDUKKipJZGVudGlmaWNhdGlvbiBvZiBzZXZlcml0eS1hc3NvY2lhdGVkIHBsYXNtYSBwcm90ZW9taWMgcHJvZmlsZXMqKgoKYGBge3J9CiMjIFdHQ05BCiMjIGh0dHBzOi8vYmlvaW5mb3JtYXRpY3N3b3JrYm9vay5vcmcvdHV0b3JpYWxzL3dnY25hLmh0bWwjZ3NjLnRhYj0wCiNpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCiNCaW9jTWFuYWdlcjo6aW5zdGFsbCgiV0dDTkEiKQoKIyMgZGF0YSB3cmFuZ2xpbmcKc2VsZWN0ZWQuYXNzYXlzLndjbmEgPC0gZGFwLnJlcyAlPiUgZmlsdGVyKHAuYWRqIDw9IDAuMDEpICU+JSBwdWxsKEFzc2F5KQoKIyMgcmVxdWlyZXM6IHJvd3MgPSB0cmVhdG1lbnRzIGFuZCBjb2x1bW5zID0gZ2VuZSBwcm9iZXMKaW5wdXRfbWF0IDwtIGRhdGEud2lkZSAlPiUgCiAgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUgJT4lIGRwbHlyOjpzZWxlY3QoREFpZCxzdHVkeV9pZCxUaW1lLCBzYW1wbGVfaWQpLGJ5PSJzYW1wbGVfaWQiKSAlPiUgCiAgaW5uZXJfam9pbihzdWJqZWN0VGFibGUgJT4lIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfaWQpLGJ5PSJzdHVkeV9pZCIpICU+JSAKICBmaWx0ZXIoVGltZT09IkFjdXRlIikgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlX2lkIikgJT4lIAogICMjIHJlc3RyaWN0aW5nIHRvIHByb3RlaW5zLCBzaWduaWZpY2FudCBhYnVuZGFudCBvdmVyIGNvbnZhbGVzY2VuY2UgKG0xMiBzYW1wbGVzKQogIGRwbHlyOjpzZWxlY3Qoc2VsZWN0ZWQuYXNzYXlzLndjbmEpICU+JSAKICBhcy5tYXRyaXgoKSAlPiUKICBzY2FsZSgpCgppbnB1dF9tYXRbMTo1LDE6MTBdCmRpbShpbnB1dF9tYXQpCmBgYAoKIFNldCB1cAoKYGBge3J9CmFsbG93V0dDTkFUaHJlYWRzKCkgICAgICAgICAgIyBhbGxvdyBtdWx0aS10aHJlYWRpbmcgKG9wdGlvbmFsKQojPiBBbGxvd2luZyBtdWx0aS10aHJlYWRpbmcgd2l0aCB1cCB0byA0IHRocmVhZHMuCgojIENob29zZSBhIHNldCBvZiBzb2Z0LXRocmVzaG9sZGluZyBwb3dlcnMKcG93ZXJzID0gYyhjKDE6MTApLCBzZXEoZnJvbSA9IDEyLCB0byA9IDIwLCBieSA9IDIpKQoKIyBDYWxsIHRoZSBuZXR3b3JrIHRvcG9sb2d5IGFuYWx5c2lzIGZ1bmN0aW9uCnNmdCA9IHBpY2tTb2Z0VGhyZXNob2xkKGlucHV0X21hdCwgICAgICAgICAgICAgIyA8PSBJbnB1dCBkYXRhCiAgICAgICAgICAgICAgICAgICAgICAgICNibG9ja1NpemUgPSAzMCwKICAgICAgICAgICAgICAgICAgICAgICAgcG93ZXJWZWN0b3IgPSBwb3dlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSA1CikKI3NmdCRwb3dlckVzdGltYXRlCgojIyMjIFNjYWxlIGluZGVwZW5kZW5jZSAmIG1lYW4gY29ubmVjdGl2aXR5CgpzZnRfdGliYmxlIDwtIGFzX3RpYmJsZShzZnQkZml0SW5kaWNlcykKCnBsb3Quc2kgPC0gc2Z0X3RpYmJsZSAlPiUgCiAgZ2dwbG90KGFlcyh4PVBvd2VyLAogICAgICAgICAgICAgeT0tc2lnbihzbG9wZSkqU0ZULlIuc3EpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xhYmVsKGFlcyhsYWJlbD1Qb3dlcikpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjksIGNvbG9yPSJkYXJrcmVkIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJTY2FsZSBpbmRlcGVuZGVuY2UiLAogICAgICAgeT0iU2NhbGUgRnJlZSBUb3BvbG9neSBNb2RlbCBmaXRcbiBzaWduZWQgUl4yIiwKICAgICAgIHg9ICJTb2Z0IFRocmVzaG9sZCAocG93ZXIiKQoKcGxvdC5tZWFuayA8LSBzZnRfdGliYmxlICU+JSAKICBnZ3Bsb3QoYWVzKHg9UG93ZXIsCiAgICAgICAgICAgICB5PW1lYW4uay4pKSArCiAgICBnZW9tX2xhYmVsKGFlcyhsYWJlbD1Qb3dlcikpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZT0iTWVhbiBjb25uZWN0aXZpdHkiLAogICAgICAgeD0iU29mdCBUaHJlc2hvbGQgKHBvd2VyKSIsCiAgICAgICB5PSJNZWFuIENvbm5lY3Rpdml0eSIpCgpwbG90LnNpICsgcGxvdC5tZWFuawpgYGAKCgpgYGB7cn0KIyNCdWlsZCBjby1leHByZXNzaW9uIG5ldHdvcmsKCnBpY2tlZF9wb3dlciA9IDYjc2Z0JHBvd2VyRXN0aW1hdGUjNgp0ZW1wX2NvciA8LSBjb3IgICAgICAgCmNvciA8LSBXR0NOQTo6Y29yICAgICAgICAgIyBGb3JjZSBpdCB0byB1c2UgV0dDTkEgY29yIGZ1bmN0aW9uIChmaXggYSBuYW1lc3BhY2UgY29uZmxpY3QgaXNzdWUpCm5ldHdrIDwtIGJsb2Nrd2lzZU1vZHVsZXMoaW5wdXRfbWF0LCAgIyA8PSBpbnB1dCBoZXJlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyA9PSBBZGphY2VuY3kgRnVuY3Rpb24gPT0KICAgICAgICAgICAgICAgICAgICAgICAgICBwb3dlciA9IHBpY2tlZF9wb3dlciwgICMgPD0gcG93ZXIgaGVyZQogICAgICAgICAgICAgICAgICAgICAgICAgIG5ldHdvcmtUeXBlID0gInNpZ25lZCIsIyJzaWduZWQgaHlicmlkIiwjInNpZ25lZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyA9PSBUcmVlIGFuZCBCbG9jayBPcHRpb25zID09CiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVlcFNwbGl0ID0gNCwgI3NlbnNpdGl2ZSBtb2R1bGUgZGV0ZWN0aW9uIHNob3VsZCBiZSB0byBtb2R1bGUgc3BsaXR0aW5nLCAwIGxlYXN0IGFuZCA0IG1vc3Qgc2Vuc2l0aXZlCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFtUmVzcGVjdHNEZW5kcm8gPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICMgZGV0ZWN0Q3V0SGVpZ2h0ID0gMC43NSwKICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5Nb2R1bGVTaXplID0gMzAsIAogICAgICAgICAgICAgICAgICAgICAgICAgIG1heEJsb2NrU2l6ZSA9bmNvbChpbnB1dF9tYXQpLCM0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAjID09IE1vZHVsZSBBZGp1c3RtZW50cyA9PQogICAgICAgICAgICAgICAgICAgICAgICAgIHJlYXNzaWduVGhyZXNob2xkID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICBtZXJnZUN1dEhlaWdodCA9IDAuMjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyA9PSBUT00gPT0gQXJjaGl2ZSB0aGUgcnVuIHJlc3VsdHMgaW4gVE9NIGZpbGUgKHNhdmVzIHRpbWUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2F2ZVRPTXMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgIHNhdmVUT01GaWxlQmFzZSA9ICJFUiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyA9PSBPdXRwdXQgT3B0aW9ucwogICAgICAgICAgICAgICAgICAgICAgICAgIG51bWVyaWNMYWJlbHMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSAzKQoKY29yIDwtIHRlbXBfY29yICAgICAjIFJldHVybiBjb3IgZnVuY3Rpb24gdG8gb3JpZ2luYWwgbmFtZXNwYWNlCmBgYAoKCmBgYHtyIGNsdXN0ZXItZGVuZHJvfQojIyMjIyBDbHVzdGVyIERlbmRyb2dyYW0KIyBDb252ZXJ0IGxhYmVscyB0byBjb2xvcnMgZm9yIHBsb3R0aW5nCm1lcmdlZENvbG9ycyA9IGxhYmVsczJjb2xvcnMobmV0d2skY29sb3JzKQojIFBsb3QgdGhlIGRlbmRyb2dyYW0gYW5kIHRoZSBtb2R1bGUgY29sb3JzIHVuZGVybmVhdGgKKGNsdXN0ZXJfZGVuZHJvIDwtIHBsb3REZW5kcm9BbmRDb2xvcnMoCiAgbmV0d2skZGVuZHJvZ3JhbXNbWzFdXSwKICBtZXJnZWRDb2xvcnNbbmV0d2skYmxvY2tHZW5lc1tbMV1dXSwKICAiTW9kdWxlIGNvbG9ycyIsCiAgZGVuZHJvTGFiZWxzID0gRkFMU0UsCiAgaGFuZyA9IDAuMDMsCiAgYWRkR3VpZGUgPSBUUlVFLAogIGd1aWRlSGFuZyA9IDAuMDUgKSkKCm1vZHVsZV9kZiA8LSBkYXRhLmZyYW1lKAogIGFzc2F5X2lkID0gbmFtZXMobmV0d2skY29sb3JzKSwKICBBc3NheSA9IGdzdWIoIlxcXy4qIiwiIixuYW1lcyhuZXR3ayRjb2xvcnMpKSwKICBjb2xvcnMgPSBsYWJlbHMyY29sb3JzKG5ldHdrJGNvbG9ycykKKQoKbW9kdWxlX2RmWzE6NSxdCgp0bXAgPC0gdW5pcXVlKG1vZHVsZV9kZiRjb2xvcnMpCm1vZHVsZS5jb2xzIDwtIHNldE5hbWVzKHRtcCwgdG1wKQpgYGAKCgojIyBTdXBwbGVtZW50YXJ5IEZpZ3VyZSA5CiMjIyBGaWd1cmUgUzlBCmBgYHtyIG53LW1vZHVsZS1zaXplfQojIyBob3cgbWFueSBwcm90ZWlzIGluIGVhY2ggbW9kdWxlCihtb2R1bGVfb3ZlcnZpZXcgPC0gbW9kdWxlX2RmICU+JSAKICBncm91cF9ieShjb2xvcnMpICU+JSAKICBjb3VudCgpICU+JSAKICAKICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmVvcmRlcihjb2xvcnMsLW4pLCB5ID0gbiwgZmlsbCA9IGNvbG9ycywgbGFiZWwgPSBuKSkgKwogICAgICAgICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHNob3cubGVnZW5kID0gRikgKwogIGdlb21fdGV4dChzdGF0ID0gInN1bSIsIHZqdXN0ID0gLTAuNSxzaG93LmxlZ2VuZCA9IEYsIHNpemU9MikgKwogIHNjYWxlX3lfY29udGludW91cygjbGltaXRzPWMoMCwzMDApLAogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBjKDAsIDIwKSkgKwogICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwtMSkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9bW9kdWxlLmNvbHMpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKQogICAgKSArIAogIGxhYnModGl0bGUgPSAiV0dDTkEgYW5hbHlzaXMgLSBwcm90ZWluIG5ldHdvcmsgbW9kdWxlcyIsCiAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgiYmFzZWQgb24gIixkaW0oaW5wdXRfbWF0KVsyXSwiIHByb3RlaW5zIChkaWZmZXJlbnRpYWwgYWJ1bmRhbnQgcHJvdGVpbnMpXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgInByb2ZpbGVkIGluICIsZGltKGlucHV0X21hdClbMV0sIiBhY3V0ZSBtYWxhcmlhIHNhbXBsZXMiKSwKICAgICAgIHg9IldHQ05BIHByb3RlaW4gbW9kdWxlcyIsCiAgICAgICB5PSJuIFByb3RlaW5zIikgCikKICAKYGBgCgoKYGBge3J9CiMjIyMgZ2VuZXJhdGUgYW5kIGV4cG9ydCBuZXR3b3JrcyBmb3IgYWxsIG1vZHVsZXMKCmFzc2F5c19vZl9pbnRlcmVzdCA9IG1vZHVsZV9kZiAjJT4lCiAgI3N1YnNldChjb2xvcnMgJWluJSBjKCJ0dXJxdW9pc2UiKSkKCm5weF9vZl9pbnRlcmVzdCA9IGlucHV0X21hdFssYXNzYXlzX29mX2ludGVyZXN0JGFzc2F5X2lkXQpucHhfb2ZfaW50ZXJlc3RbMTo1LDE6NV0KIyMgY29sdW1uczogQXNzYXlzCiMjIHJvd3M6IHNhbXBsZV9pZAoKVE9NID0gVE9Nc2ltaWxhcml0eUZyb21FeHByKG5weF9vZl9pbnRlcmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvd2VyID0gcGlja2VkX3Bvd2VyKQoKIyBBZGQgZ2VuZSBuYW1lcyB0byByb3cgYW5kIGNvbHVtbnMKcm93Lm5hbWVzKFRPTSkgPSBjb2xuYW1lcyhucHhfb2ZfaW50ZXJlc3QpCmNvbG5hbWVzKFRPTSkgPSBjb2xuYW1lcyhucHhfb2ZfaW50ZXJlc3QpCgplZGdlX2xpc3QgPSBkYXRhLmZyYW1lKFRPTSkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJBc3NheTEiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHM9LUFzc2F5MSxuYW1lc190byA9ICJBc3NheTIiLHZhbHVlc190byA9ICJhZGphY2VuY3kiKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUKICAgIGZpbHRlcihBc3NheTEhPUFzc2F5MikgJT4lIAogIHJpZ2h0X2pvaW4obW9kdWxlX2RmICU+JSB0cmFuc211dGUobW9kdWxlMSA9IGNvbG9ycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFzc2F5MSA9IEFzc2F5KSkgJT4lIAogIHJpZ2h0X2pvaW4obW9kdWxlX2RmICU+JSB0cmFuc211dGUobW9kdWxlMiA9IGNvbG9ycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFzc2F5MiA9IEFzc2F5KSkgJT4lIAogIG5hLm9taXQoKQoKYGBgCgojIyBGaWd1cmUgNUEKCmBgYHtyfQojI0hlYXRtYXAgLSBwcm90ZWluIGFkamFjZW5jeQoKbWF0IDwtIGNvcihucHhfb2ZfaW50ZXJlc3QsIG1ldGhvZCA9ICJwZWFyc29uIikKcm93LmFubm8uZGYgPC0gZGF0YS5mcmFtZShhc3NheV9pZCA9IHJvd25hbWVzKG1hdCkpICU+JSBsZWZ0X2pvaW4obW9kdWxlX2RmKSAlPiUgZHBseXI6OnJlbmFtZShNb2R1bGUgPSBjb2xvcnMpIAoKKGFzc2F5X2Fkal9obSA8LSBtYXQgJT4lIAogIEhlYXRtYXAobmFtZT0icHJvdGVpbi1wcm90ZWluIGNvcnJlbGF0aW9uIHIiLAogICAgICAgICAgcmlnaHRfYW5ub3RhdGlvbiA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gcm93LmFubm8uZGYgJT4lIHRyYW5zbXV0ZShNb2R1bGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3QoTW9kdWxlID0gbW9kdWxlLmNvbHMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaCA9ICJyb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsZV9hbm5vX3NpemUgPSB1bml0KDEsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfYW5ub3RhdGlvbl9uYW1lID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfcm90ID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfZ3AgPSBncGFyKGZvbnRzaXplPTYpLAoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWVfc2lkZSA9ICJ0b3AiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gNikpKSwKICAgICAgICAgIHJvd19zcGxpdCA9IHJvdy5hbm5vLmRmJE1vZHVsZSwKICAgICAgICAgIGNvbHVtbl9zcGxpdCA9IHJvdy5hbm5vLmRmJE1vZHVsZSwKICAgICAgICAgIHJvd19nYXAgPSB1bml0KDAsICJtbSIpLAogICAgICAgICAgY29sdW1uX2dhcCA9IHVuaXQoMCwgIm1tIiksIAogICAgICAgICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDMsICJtbSIpLAogICAgICAgICAgcm93X2RlbmRfZ3AgPSBncGFyKGx3ZD0uMSksCiAgICAgICAgICBjb2x1bW5fZGVuZF9ncCA9IGdwYXIobHdkPS4xKSwKICAgICAgICAgIGNvbHVtbl9kZW5kX2hlaWdodCA9IHVuaXQoMywgIm1tIiksIAogICAgICAgICAgYm9yZGVyID0gVFJVRSwKICAgICAgICAgIGJvcmRlcl9ncCA9IGdwYXIobHdkPS4xKSwKICAgICAgICAgIGNvbHVtbl90aXRsZSA9IE5VTEwsCiAgICAgICAgICByb3dfdGl0bGUgPSBOVUxMLAogICAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBGLAogICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGLAogICAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX3dpZHRoID0gdW5pdCgyLCAiY20iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX2hlaWdodCA9IHVuaXQoLjIsICJjbSIpKQogICAgICAgICAgKSkKYGBgCgpgYGB7cn0KIyBHZXQgTW9kdWxlIEVpZ2VuZ2VuZXMgcGVyIGNsdXN0ZXIKTUVzMCA8LSBtb2R1bGVFaWdlbmdlbmVzKGlucHV0X21hdCwgbWVyZ2VkQ29sb3JzKSRlaWdlbmdlbmVzCgojIFJlb3JkZXIgbW9kdWxlcyBzbyBzaW1pbGFyIG1vZHVsZXMgYXJlIG5leHQgdG8gZWFjaCBvdGhlcgpNRXMwIDwtIG9yZGVyTUVzKE1FczApCm1vZHVsZV9vcmRlciA9IG5hbWVzKE1FczApICU+JSBnc3ViKCJNRSIsIiIsIC4pCgojIEFkZCB0cmVhdG1lbnQgbmFtZXMKI01FczAkREFpZCA8LSByb3cubmFtZXMoTUVzMCkKCiMgdGlkeSBkYXRhCm1NRSA8LSBNRXMwICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlX2lkIikgJT4lIAogIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJtb2R1bGUiLCB2YWx1ZXNfdG8gPSAibW9kdWxlX2VpZ2VuZ2VuZXMiICxjb2xzID0gLXNhbXBsZV9pZCkgJT4lCiAgICAgIHNlcGFyYXRlKHNhbXBsZV9pZCwgIlxcfCIsIGludG8gPSBjKCJzdHVkeV9pZCIsIlRpbWUiKSxyZW1vdmUgPSBGKSAlPiUgCiAgbXV0YXRlKG1vZHVsZSA9IGdzdWIoIk1FIiwgIiIsIG1vZHVsZSksCiAgICAgICAgIG1vZHVsZSA9IGZhY3Rvcihtb2R1bGUsIGxldmVscyA9IG1vZHVsZV9vcmRlcikpICU+JSAKICBpbm5lcl9qb2luKHN1YmplY3RUYWJsZSwgCiAgICAgICAgICAgICBieT0ic3R1ZHlfaWQiKSAKYGBgCgojIyBGaWd1cmUgNUIKYGBge3J9CiMjIE1vZHVsZS10cmFpdCByZWxhdGlvbnNoaXAKCmNvcnJfbW9kdWxlX2VpZ2VuZ2VuZV9tZXRhX3JlcyA8LSBtTUUgJT4lIAogIGRwbHlyOjpzZWxlY3QobW9kdWxlLCBtb2R1bGVfZWlnZW5nZW5lcyxjb250YWlucygiU09GQSIpKSAlPiUgCiAgZ3JvdXBfYnkobW9kdWxlKSAlPiUgCiAgY29ycmVsYXRpb24ocF9hZGp1c3QgPSAiZmRyIikgCgpkZiA8LSB0aWJibGUoY29ycl9tb2R1bGVfZWlnZW5nZW5lX21ldGFfcmVzKSAlPiUgCiAgZmlsdGVyKFBhcmFtZXRlcjE9PSJtb2R1bGVfZWlnZW5nZW5lcyIpICU+JSAKICAgIG11dGF0ZShyNGZpbGwgPSBjYXNlX3doZW4ocD4wLjA1IH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQ9cikpICAKKG1vZHVsZV90cmFpdF9wbG90IDwtIGdncGxvdChkYXRhID0gZGYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PVBhcmFtZXRlcjIsIHk9R3JvdXAsIGZpbGw9cjRmaWxsLGxhYmxlPXIpKSArCiAgICBnZW9tX3RpbGUoKSArCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHIgJT4lIHJvdW5kKDIpKSwKICAgICAgICAgICAgICAgICAgY29sb3IgPSBpZmVsc2UocjRmaWxsPT0wLCAiZ3JleTIwIiwgImJsYWNrIikpLAogICAgICAgICAgICAgIHNpemU9MSkgKwogICAgc2NhbGVfY29sb3VyX2lkZW50aXR5KCkgKwogICAgdGhlbWVfYncoKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50MigKICAgICAgbG93ID0gImJsdWUiLAogICAgICBoaWdoID0gInJlZCIsCiAgICAgIG1pZCA9ICJ3aGl0ZSIsCiAgICAgIG1pZHBvaW50ID0gMCwKICAgICAgbGltaXQgPSBjKC0xLDEpKSArCiAgICBsYWJzKHRpdGxlID0gIk1vZHVsZS10cmFpdCBSZWxhdGlvbnNoaXBzIiwKICAgICAgICAgeT0iV0dDTkEgbW9kdWxlcyIsCiAgICAgICAgIHggPSBOVUxMLCAKICAgICAgICAgZmlsbD0icmhvIikgKwogICAgdGhlbWUoI2F4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yPSByZXYoYygieWVsbG93IiwidHVycXVvaXNlIiwicmVkIiwiZ3JleSIsImdyZWVuIiwiYnJvd24iLCJibHVlIikpKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3I9IHJldihjKCJ5ZWxsb3ciLCJ0dXJxdW9pc2UiLCJyZWQiLCJncmV5IiwiZ3JlZW4iLCJicm93biIsImJsdWUiKSkpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSkKYGBgCgoKYGBge3J9CiMjIyMgTW9kdWxlIG1lbWJlcnNoaXAKCiMjIyAgR2V0IE1vZHVsZSBFaWdlbmdlbmVzIHBlciBjbHVzdGVyCk1FcyA8LSBtb2R1bGVFaWdlbmdlbmVzKGlucHV0X21hdCwgbWVyZ2VkQ29sb3JzKSRlaWdlbmdlbmVzCgojIyBjYWxjdWxhdGUgTW9kdWxlIG1lbWJlcnNoaXAKZ2VuZU1vZHVsZU1lbWJlcnNoaXAgPC0gYXMuZGF0YS5mcmFtZShjb3IoaW5wdXRfbWF0LCBNRXMsIHVzZSA9ICJwIikpIAoKZ2VuZU1vZHVsZU1lbWJlcnNoaXAudGlkeSA8LSBnZW5lTW9kdWxlTWVtYmVyc2hpcCAlPiUKICByb3duYW1lc190b19jb2x1bW4oIkFzc2F5IikgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gLUFzc2F5KSAlPiUgCiAgdHJhbnNtdXRlKEFzc2F5LAogICAgICAgICAgICBNb2R1bGUgPSBzdHJfcmVtb3ZlKG5hbWUsICJNRSIpLAogICAgICAgICAgICBnTU0gPSB2YWx1ZSkKCiMjIGNhbGN1bGF0ZSBwdmFsdWUgZm9yIGdlbmVNb2R1bGVNZW1iZXJzaGlwCk1NUHZhbHVlLnRpZHkgPC0gYXMuZGF0YS5mcmFtZShjb3JQdmFsdWVTdHVkZW50KGFzLm1hdHJpeChnZW5lTW9kdWxlTWVtYmVyc2hpcCksIG5yb3coaW5wdXRfbWF0KSkpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigiQXNzYXkiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtQXNzYXkpICU+JSAKICB0cmFuc211dGUoQXNzYXksCiAgICAgICAgICAgIE1vZHVsZSA9IHN0cl9yZW1vdmUobmFtZSwgIk1FIiksCiAgICAgICAgICAgIHB2YWx1ZSA9IHZhbHVlKSAKCmdNTS50aWR5IDwtIGdlbmVNb2R1bGVNZW1iZXJzaGlwLnRpZHkgJT4lIHJpZ2h0X2pvaW4oTU1QdmFsdWUudGlkeSxieT1jKCJBc3NheSIsIk1vZHVsZSIpKSAKCm1vZHVsZV9zcGVjaWZpY19NTSA8LSBtb2R1bGVfZGYgJT4lIAogIHRyYW5zbXV0ZShBc3NheSwKICAgICAgICAgICAgTW9kdWxlID0gY29sb3JzKSAlPiUgCiAgaW5uZXJfam9pbihnTU0udGlkeSkKYGBgCgojIyBTdXBwbGVtZW50YXJ5IEZpZ3VyIFM5QgpgYGB7cn0KKHR1cnF1b2lzZV9tb2R1bGVfcmVzdHJpY3Rpb25zX2RlbnNpdHkgPC0gbW9kdWxlX3NwZWNpZmljX01NICU+JSAKICAgbXV0YXRlKCItbG9nMTAocHZhbHVlKSIgPSAtbG9nMTAocHZhbHVlKSkgJT4lIAogICBwaXZvdF9sb25nZXIoY29scyA9IGMoZ01NLCItbG9nMTAocHZhbHVlKSIpKSAlPiUgCiAgIG11dGF0ZShuYW1lX2xhYmVsID0gY2FzZV93aGVuKG5hbWU9PSJnTU0ifiJ0aHJlc2hvbGQgPiAwLjYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lPT0iLWxvZzEwKHB2YWx1ZSkifiJ0aHJlc2hvbGQgPCAwLjA1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSksCiAgICAgICAgICBuYW1lX2xhYmVsID0gZmFjdG9yKG5hbWVfbGFiZWwpLAogICAgICAgICAgY3V0b2ZmID0gY2FzZV93aGVuKG5hbWU9PSJnTU0ifiAwLjYsIzAuNzUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT09Ii1sb2cxMChwdmFsdWUpIn4gLWxvZzEwKDAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gTkEpLAogICAgICAgICAgY3V0b2ZmX3Bvc195ID0gY2FzZV93aGVuKG5hbWU9PSJnTU0ifiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU9PSItbG9nMTAocHZhbHVlKSJ+IDAuMDQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBOQSkKICAgKSAlPiUgCiAgIGdncGxvdChhZXMoeD12YWx1ZSkpICsKICAgZ2VvbV9kZW5zaXR5KHNob3cubGVnZW5kID0gRixsaW5ld2lkdGg9LjIsZmlsbD0idHVycXVvaXNlIikgKwogICB0aGVtZV9taW5pbWFsKCkgKwogICBmYWNldF93cmFwKH5uYW1lLCBuY29sID0gMSxsYWJlbGxlciA9IGxhYmVsbGVyKG5hbWU9YygiZ01NIiA9ICJNb2R1bGUgbWVtYmVyc2hpcCIsICItbG9nMTAocHZhbHVlKSIgPSAiLWxvZzEwKHB2YWx1ZSkiKSksc2NhbGVzID0gImZyZWUiKSArCiAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9Y3V0b2ZmKSxsaW5ldHlwZT0iZGFzaGVkIikgKwogICBnZW9tX3RleHQoYWVzKHg9Y3V0b2ZmLAogICAgICAgICAgICAgICAgIHk9Y3V0b2ZmX3Bvc195LAogICAgICAgICAgICAgICAgIGxhYmVsPW5hbWVfbGFiZWwpLCAKICAgICAgICAgICAgIHNpemU9MSwKICAgICAgICAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFKSArCiAgIGxhYnMoeT0iZGVuc2l0eSIsCiAgICAgICAgeD0iIikpCmBgYAoKIyMgRmlndXJlIDVDCgpgYGB7cn0KcmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlIDwtIG1vZHVsZV9zcGVjaWZpY19NTSAlPiUgCiAgZmlsdGVyKE1vZHVsZT09InR1cnF1b2lzZSIsCiAgICAgICAgIGdNTSA+IDAuNiwjMC43NSwKICAgICAgICAgcHZhbHVlIDwgMC4wNQogICAgICAgICApICU+JSAKICBhcnJhbmdlKC1wdmFsdWUpICU+JSAKICBwdWxsKEFzc2F5KSAKCmxlbmd0aChyZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UpCgpkYXRhLmZyYW1lKEFzc2F5ID0gcmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlKSAlPiUgCiAgbGVmdF9qb2luKGRhcC5yZXMgJT4lIAogICAgICAgICAgICAgIHRyYW5zbXV0ZShBc3NheSwgVW5pUHJvdCkpICU+JQogIHRyYW5zbXV0ZShVbmlQcm90KSAlPiUgCiAgd3JpdGVfdHN2KHBhc3RlMChyZXN1bHQudG1wLmRpciwicmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlLnRzdiIpKQogICNoZWFkKCkKYGBgCgpgYGB7cn0KIyNPbmxpbmUgcmVhY3RvbWUKI3JlYWN0b21lX3Jlc3VsdDwtIHJlYWRfZGVsaW0oIi4uL01hbnVzY3JpcHQvMjAyNTAyMjZfcmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlX1JlYWN0b21lT1JBX1Jlc3VsdC50eHQiKSAlPiUgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKQpyZWFjdG9tZV9yZXN1bHQ8LSByZWFkX2RlbGltKCIuLi9NYW51c2NyaXB0LzIwMjUwMzI1X3Jlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZV9SZWFjdG9tZU9SQV9SZXN1bHQudHh0IikgJT4lIGphbml0b3I6OmNsZWFuX25hbWVzKCkKCgoocmVhY3RvbWVfb3JhIDwtIHJlYWN0b21lX3Jlc3VsdCAlPiUgCiAgYXJyYW5nZShlbnRpdGllc19mZHIpICU+JSAKICBoZWFkKG49MTApICU+JSAKICAgIG11dGF0ZShmYWNldF9sYWIgPSAidHVycXVvaXNlIG1vZHVsZSIpICU+JSAKCiAgIGdncGxvdChhZXMoeD1mY3RfcmVvcmRlcihwYXRod2F5X25hbWUsLWxvZzEwKGVudGl0aWVzX2ZkcikpLCAKICAgICAgICAgICAgICB5PS1sb2cxMChlbnRpdGllc19mZHIpKSkgKwoKICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuMSkgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3I9LWxvZzEwKGVudGl0aWVzX2ZkcikpLAogICAgICAgICAgICAgICBzaXplPTIpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9bnVtYmVyX2VudGl0aWVzX2ZvdW5kKSwKICAgICAgICAgICAgICBzaXplPTIsIG51ZGdlX3kgPSAuMSwgY29sb3I9ImJsYWNrIikrCiAgICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZzEwIikgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJfd3JhcCh4LCB3aWR0aCA9IDQ1KSkgKwogICAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYgKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgY29vcmRfZmxpcCgpICsKICAgIGZhY2V0X2dyaWQofmZhY2V0X2xhYikgKwogICAgZ3VpZGVzKHNpemUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZT1UUlVFKSwKICAgICAgICAgICApICsKICAgICBsYWJzKHRpdGxlID0gIlJlYWN0b21lIGRhdGFiYXNlIHY4NiIsCiAgICAgICBjb2xvcj0iLWxvZzEwXG4oRkRSKSIsCiAgICAgICB5PSItbG9nMTAoRkRSKSIsCiAgICAgICB4PU5VTEwpCikKYGBgCgojIyBGaWd1cmUgNUQKYGBge3J9CndyYXBwZXIgPC0gZnVuY3Rpb24oeCwgLi4uKSAKewogIHBhc3RlKHN0cndyYXAoeCwgLi4uKSwgY29sbGFwc2UgPSAiXG4iKQp9CgphID0gIkltbXVub3JlZ3VsYXRvcnkgaW50ZXJhY3Rpb25zIGJldHdlZW4gYSBMeW1waG9pZCBhbmQgYSBub24tTHltcGhvaWQgY2VsbCIKZGYgPC0gcmVhY3RvbWVfcmVzdWx0ICU+JSAKICBhcnJhbmdlKGVudGl0aWVzX2ZkcikgJT4lIAogIGhlYWQobj0xMCkgJT4lIAogIGZpbHRlcihwYXRod2F5X25hbWU9PWEpICU+JSAKICB0cmFuc211dGUocGF0aHdheV9uYW1lLCBzdWJtaXR0ZWRfZW50aXRpZXNfZm91bmQpICU+JSAKICBzZXBhcmF0ZV9yb3dzKHN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCwgc2VwPSI7XFxzKiIpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBkYXRhLmxvbmcgJT4lIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIHRyYW5zbXV0ZShBc3NheSxOUFgsVW5pUHJvdCxzYW1wbGVfaWQsc3R1ZHlfaWQsVGltZSkgJT4lIGZpbHRlcihUaW1lPT0iQWN1dGUiKSwKICAgIGJ5PWMoInN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCI9IlVuaVByb3QiKQogICkgJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCxieT0ic3R1ZHlfaWQiKQoKKHJlYWN0b21lX29yYV9JSUJMTkwgPC0gZGYgJT4lICBncm91cF9ieShBc3NheSwgc2V2ZXJpdHlfbGFiKSAlPiUgCiAgICBzdW1tYXJpc2UoTlBYbWVhbiA9IG1lYW4oTlBYKSwKICAgICAgICAgICAgICBOUFhtZWRpYW4gPSBtZWRpYW4oTlBYKSwKICAgICAgICAgICAgICBOUFhzZCA9IHNkKE5QWCksCiAgICAgICAgICAgICAgTlBYbiA9IG4oKSwKICAgICAgICAgICAgICBOUFhzZSA9IE5QWHNkIC8gc3FydChOUFhuKQogICAgKSAlPiUgCiAgICBtdXRhdGUoTlBYY2k5NSA9IE5QWHNlICogcXQoLjk3NSwgTlBYbiAtIDEpKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9QXNzYXksIHk9TlBYbWVhbiwgZ3JvdXA9c2V2ZXJpdHlfbGFiLCBjb2xvcj1zZXZlcml0eV9sYWIpKSArCiAgICBnZW9tX3BvaW50KHNpemU9LjI1KSArCiAgICBnZW9tX3BvbHlnb24oZmlsbD1OQSwgc2hvdy5sZWdlbmQgPSBGLCBsd2Q9MC4yKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh4ID0gQXNzYXksCiAgICAgICAgICAgICAgICAgICAgICB5bWluPU5QWG1lYW4tTlBYY2k5NSwgCiAgICAgICAgICAgICAgICAgICAgICB5bWF4PU5QWG1lYW4rTlBYY2k5NSwgKSwKICAgICAgICAgICAgICAgICAgbGluZXdpZHRoPS41LCAKICAgICAgICAgICAgICAgICAgd2lkdGg9LjIsCiAgICAgICAgICAgICAgICAgIGFscGhhPS41KSArCiAgICAjIE1ha2UgaXQgY2lyY3VsYXIhCiAgICBjb29yZF9wb2xhcihjbGlwID0gIm9mZiIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHg9IiIsCiAgICAgICAgIHk9Im1lYW4gKE5QWCkgKy0gOTUlIENJIiwKCiAgICAgICAgIHRpdGxlID0gd3JhcHBlcihhLCB3aWR0aCA9IDQwKSwKICAgICAgICAgICAgICAgICAgY29sb3I9Im1lYW4gKE5QWCkgKy0gOTUlIENJIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDNfbGFiKSArCiAgICAjIEFubm90YXRlIHRoZSBiYXJzIGFuZCB0aGUgbG9sbGlwb3BzIHNvIHRoZSByZWFkZXIgdW5kZXJzdGFuZHMgdGhlIHNjYWxpbmcKICAgIGFubm90YXRlKHggPSAwLCB5ID0gMCwgbGFiZWwgPSAiMCIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDEsIGxhYmVsID0gIjEiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogICAgYW5ub3RhdGUoeCA9IDAsIHkgPSAyLCBsYWJlbCA9ICIyIiwgZm9udGZhY2UgPTIsIGdlb20gPSAidGV4dCIsIGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSAxLjUpICsKICAgIGFubm90YXRlKHggPSAwLCB5ID0gMywgbGFiZWwgPSAiMyIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSA0KSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSwgZmFjZT0nYm9sZCcpLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKICApCmBgYAoKYGBge3J9CmEgPSAiTmV1dHJvcGhpbCBkZWdyYW51bGF0aW9uIgpkZiA8LSByZWFjdG9tZV9yZXN1bHQgJT4lIAogIGFycmFuZ2UoZW50aXRpZXNfZmRyKSAlPiUgCiAgaGVhZChuPTEwKSAlPiUgCiAgZmlsdGVyKHBhdGh3YXlfbmFtZT09YSkgJT4lIAogIHRyYW5zbXV0ZShwYXRod2F5X25hbWUsIHN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCkgJT4lIAogIHNlcGFyYXRlX3Jvd3Moc3VibWl0dGVkX2VudGl0aWVzX2ZvdW5kLCBzZXA9IjtcXHMqIikgJT4lIAogIGxlZnRfam9pbigKICAgIGRhdGEubG9uZyAlPiUgaW5uZXJfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUsIGJ5PSJzYW1wbGVfaWQiKSAlPiUgdHJhbnNtdXRlKEFzc2F5LE5QWCxVbmlQcm90LHNhbXBsZV9pZCxzdHVkeV9pZCxUaW1lKSAlPiUgZmlsdGVyKFRpbWU9PSJBY3V0ZSIpLAogICAgYnk9Yygic3VibWl0dGVkX2VudGl0aWVzX2ZvdW5kIj0iVW5pUHJvdCIpCiAgKSAlPiUgCiAgaW5uZXJfam9pbihwYXRpZW50X2NsdXN0LGJ5PSJzdHVkeV9pZCIpCgoocmVhY3RvbWVfb3JhX05EIDwtIGRmICU+JSAgZ3JvdXBfYnkoQXNzYXksIHNldmVyaXR5X2xhYikgJT4lIAogICAgc3VtbWFyaXNlKE5QWG1lYW4gPSBtZWFuKE5QWCksCiAgICAgICAgICAgICAgTlBYbWVkaWFuID0gbWVkaWFuKE5QWCksCiAgICAgICAgICAgICAgTlBYc2QgPSBzZChOUFgpLAogICAgICAgICAgICAgIE5QWG4gPSBuKCksCiAgICAgICAgICAgICAgTlBYc2UgPSBOUFhzZCAvIHNxcnQoTlBYbikKICAgICkgJT4lIAogICAgbXV0YXRlKE5QWGNpOTUgPSBOUFhzZSAqIHF0KC45NzUsIE5QWG4gLSAxKSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PUFzc2F5LCB5PU5QWG1lYW4sIGdyb3VwPXNldmVyaXR5X2xhYiwgY29sb3I9c2V2ZXJpdHlfbGFiKSkgKwogICAgZ2VvbV9wb2ludChzaXplPS4yNSkgKwogICAgZ2VvbV9wb2x5Z29uKGZpbGw9TkEsIHNob3cubGVnZW5kID0gRiwgbHdkPTAuMikgKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeCA9IEFzc2F5LAogICAgICAgICAgICAgICAgICAgICAgeW1pbj1OUFhtZWFuLU5QWGNpOTUsIAogICAgICAgICAgICAgICAgICAgICAgeW1heD1OUFhtZWFuK05QWGNpOTUsICksCiAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aD0uNSwgICAgCiAgICAgICAgICAgICAgICAgIHdpZHRoPS4yLAogICAgICAgICAgICAgICAgICBhbHBoYT0uNSkgKwogICAgIyBNYWtlIGl0IGNpcmN1bGFyIQogICAgY29vcmRfcG9sYXIoY2xpcCA9ICJvZmYiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh4PSIiLAogICAgICAgICB0aXRsZSA9IHdyYXBwZXIoYSwgd2lkdGggPSA0MCksCiAgICAgICAgICAgICAgICAgIGNvbG9yPSJtZWFuIChOUFgpICstIDk1JSBDSSIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9cGF0aWVudF9rY2x1c3QzX2xhYikgKwogICAgIyBBbm5vdGF0ZSB0aGUgYmFycyBhbmQgdGhlIGxvbGxpcG9wcyBzbyB0aGUgcmVhZGVyIHVuZGVyc3RhbmRzIHRoZSBzY2FsaW5nCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDAsIGxhYmVsID0gIjAiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogICAgYW5ub3RhdGUoeCA9IDAsIHkgPSAxLCBsYWJlbCA9ICIxIiwgZm9udGZhY2UgPTIsIGdlb20gPSAidGV4dCIsIGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSAxLjUpICsKICAgIGFubm90YXRlKHggPSAwLCB5ID0gMiwgbGFiZWwgPSAiMiIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDMsIGxhYmVsID0gIjMiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJncmF5MTIiLCBzaXplID0gNCksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTUsIGZhY2U9J2JvbGQnKSwKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCiAgKQpgYGAKCmBgYHtyfQphID0gIlRORlIyIG5vbi1jYW5vbmljYWwgTkYta0IgcGF0aHdheSIKZGYgPC0gcmVhY3RvbWVfcmVzdWx0ICU+JSAKICBhcnJhbmdlKGVudGl0aWVzX2ZkcikgJT4lIAogIGhlYWQobj0xMCkgJT4lIAogIGZpbHRlcihwYXRod2F5X25hbWU9PWEpICU+JSAKICB0cmFuc211dGUocGF0aHdheV9uYW1lLCBzdWJtaXR0ZWRfZW50aXRpZXNfZm91bmQpICU+JSAKICBzZXBhcmF0ZV9yb3dzKHN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCwgc2VwPSI7XFxzKiIpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBkYXRhLmxvbmcgJT4lIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlLCBieT0ic2FtcGxlX2lkIikgJT4lIHRyYW5zbXV0ZShBc3NheSxOUFgsVW5pUHJvdCxzYW1wbGVfaWQsc3R1ZHlfaWQsVGltZSkgJT4lIGZpbHRlcihUaW1lPT0iQWN1dGUiKSwKICAgIGJ5PWMoInN1Ym1pdHRlZF9lbnRpdGllc19mb3VuZCI9IlVuaVByb3QiKQogICkgJT4lIAogIGlubmVyX2pvaW4ocGF0aWVudF9jbHVzdCxieT0ic3R1ZHlfaWQiKQoKKHJlYWN0b21lX29yYV9UTkZSMiA8LSBkZiAlPiUgIGdyb3VwX2J5KEFzc2F5LCBzZXZlcml0eV9sYWIpICU+JSAKICAgIHN1bW1hcmlzZShOUFhtZWFuID0gbWVhbihOUFgpLAogICAgICAgICAgICAgIE5QWG1lZGlhbiA9IG1lZGlhbihOUFgpLAogICAgICAgICAgICAgIE5QWHNkID0gc2QoTlBYKSwKICAgICAgICAgICAgICBOUFhuID0gbigpLAogICAgICAgICAgICAgIE5QWHNlID0gTlBYc2QgLyBzcXJ0KE5QWG4pCiAgICApICU+JSAKICAgIG11dGF0ZShOUFhjaTk1ID0gTlBYc2UgKiBxdCguOTc1LCBOUFhuIC0gMSkpICU+JSAKICAgIGdncGxvdChhZXMoeD1Bc3NheSwgeT1OUFhtZWFuLCBncm91cD1zZXZlcml0eV9sYWIsIGNvbG9yPXNldmVyaXR5X2xhYikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0uMjUpICsKICAgIGdlb21fcG9seWdvbihmaWxsPU5BLCBzaG93LmxlZ2VuZCA9IEYsIGx3ZD0wLjIpICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHggPSBBc3NheSwKICAgICAgICAgICAgICAgICAgICAgIHltaW49TlBYbWVhbi1OUFhjaTk1LCAKICAgICAgICAgICAgICAgICAgICAgIHltYXg9TlBYbWVhbitOUFhjaTk1KSwKICAgICAgICAgICAgICAgICAgbGluZXdpZHRoPS41LAogICAgICAgICAgICAgICAgICB3aWR0aD0uMiwKICAgICAgICAgICAgICAgICAgYWxwaGE9LjUpICsKICAgICMgTWFrZSBpdCBjaXJjdWxhciEKICAgIGNvb3JkX3BvbGFyKGNsaXAgPSAib2ZmIikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoeD1OVUxMLAogICAgICAgICBjb2xvcj0ibWVhbiAoTlBYKSArLSA5NSUgQ0kiLAogICAgICAgICB0aXRsZSA9IHdyYXBwZXIoYSwgd2lkdGggPSA0MCkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9cGF0aWVudF9rY2x1c3QzX2xhYikgKwogICAgIyBBbm5vdGF0ZSB0aGUgYmFycyBhbmQgdGhlIGxvbGxpcG9wcyBzbyB0aGUgcmVhZGVyIHVuZGVyc3RhbmRzIHRoZSBzY2FsaW5nCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDAsIGxhYmVsID0gIjAiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogICAgYW5ub3RhdGUoeCA9IDAsIHkgPSAxLCBsYWJlbCA9ICIxIiwgZm9udGZhY2UgPTIsIGdlb20gPSAidGV4dCIsIGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSAxLjUpICsKICAgIGFubm90YXRlKHggPSAwLCB5ID0gMiwgbGFiZWwgPSAiMiIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICBhbm5vdGF0ZSh4ID0gMCwgeSA9IDMsIGxhYmVsID0gIjMiLCBmb250ZmFjZSA9MiwgZ2VvbSA9ICJ0ZXh0IiwgY29sb3IgPSAiZ3JheTEyIiwgc2l6ZSA9IDEuNSkgKwogIGFubm90YXRlKHggPSAwLCB5ID0gNCwgbGFiZWwgPSAiNCIsIGZvbnRmYWNlID0yLCBnZW9tID0gInRleHQiLCBjb2xvciA9ICJncmF5MTIiLCBzaXplID0gMS41KSArCiAgICB0aGVtZSgKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyYXkxMiIsIHNpemUgPSA0KSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSwgZmFjZT0nYm9sZCcpLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKKQpgYGAKCgojIEZpZ3VyZSA2CioqU2V2ZXJpdHktYXNzb2NpYXRlZCBwcm9maWxlcyBvZiBjb25kZW5zZWQgMTEtIHByb3RlaW4gc2lnbmF0dXJlIGluIG1hbGFyaWEgYW5kIG90aGVyIGZlYnJpbGUgaW5mZWN0aW9ucy4qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShtaXhPbWljcykKZGF0YS5tbyA8LSBkZl9hY3V0ZV9wYXRjbHVzdF9pbmNsX2NvbnYgJT4lIAogIGZpbHRlcihBc3NheSAlaW4lIHJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBBc3NheSwgdmFsdWVzX2Zyb20gPSBOUFgsIGlkX2NvbHM9YyhzZXZlcml0eV9sYWIsc2FtcGxlX2lkKSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlX2lkIikKClggPC0gZGF0YS5tbyAlPiUgZHBseXI6OnNlbGVjdCgtYyhzZXZlcml0eV9sYWIpKQpZIDwtIGRhdGEubW8kc2V2ZXJpdHlfbGFiCiMjIyMjCmRhdGEucGNhIDwtIG1peE9taWNzOjpwY2EoWCwgbmNvbXA9MTAsIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSkKcGxvdChkYXRhLnBjYSkKcGxvdEluZGl2KGRhdGEucGNhLCAKICAgICAgICAgIGdyb3VwID0gWSwKICAgICAgICAgIGluZC5uYW1lcyA9IEYsCiAgICAgICAgICBsZWdlbmQgPSBUUlVFLCAKICAgICAgICAgIGNvbC5wZXIuZ3JvdXAgPSBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYsCiAgICAgICAgICB0aXRsZSA9ICdQQ0Egb24gYWxsIE5QWCBkYXRhJykKIyMjIyMKIyMjIFBMUy1EaXNjcmltaW5hbnQgQW5hbHlzaXMgYmFzZWQgb24gc2V2ZXJpdHkgZ3JvdXBzCgpkYXRhLnBsc2RhIDwtIG1peE9taWNzOjpwbHNkYShYLCBZLCBuY29tcCA9IDEwKQojIHRha2VzIGEgY291cGxlIG9mIG1pbnV0ZXMgdG8gcnVuCnBlcmYuZGF0YS5wbHNkYSA8LSBwZXJmKGRhdGEucGxzZGEsIAogICAgICAgICAgICAgICAgICAgICAgICB2YWxpZGF0aW9uID0gIk1mb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgZm9sZHMgPSA1LAogICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzc0JhciA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgIGF1YyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICBucmVwZWF0ID0gMTApICMxMDAKIyMjIyMjIyMjIyMjIyMjIwoocGxvdChwZXJmLmRhdGEucGxzZGEsIGNvbCA9IGNvbG9yLm1peG8oMTozKSwgc2QgPSBUUlVFLCBsZWdlbmQucG9zaXRpb24gPSAiaG9yaXpvbnRhbCIpKQoKIyMjIyMjCmxpc3Qua2VlcFggPC0gYygxOjEwKSAjIGdyaWQgb2YgcG9zc2libGUga2VlcFggdmFsdWVzIHRoYXQgd2lsbCBiZSB0ZXN0ZWQgZm9yIGVhY2ggY29tcG9uZW50CnR1bmUuc3Bsc2RhIDwtIHR1bmUuc3Bsc2RhKFgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBuY29tcCA9IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWxpZGF0aW9uID0gIk1mb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9sZHMgPSA1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3NCYXIgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzdCA9ICJjZW50cm9pZHMuZGlzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUgPSAiQkVSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC5rZWVwWCA9IGxpc3Qua2VlcFgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBucmVwZWF0ID0gMTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjcHVzID0gOCkKIyMjIyMKIyMgVGhlIGNsYXNzaWZpY2F0aW9uIGVycm9yIHJhdGVzIGZvciBlYWNoIGNvbXBvbmVudCBjb25kaXRpb25hbCBvbiB0aGUgbGFzdCBjb21wb25lbnQgYXJlIHJlcHJlc2VudGVkIGJlbG93LCBmb3IgYWxsIGNvbXBvbmVudHMgc3BlY2lmaWVkIGluIHRoZSB0dW5lIGZ1bmN0aW9uLgpwbG90KHR1bmUuc3Bsc2RhKQplcnJvciA8LSB0dW5lLnNwbHNkYSRlcnJvci5yYXRlICAjIGVycm9yIHJhdGUgcGVyIGNvbXBvbmVudCBmb3IgdGhlIGtlZXBYIGdyaWQKbmNvbXAgPC0gdHVuZS5zcGxzZGEkY2hvaWNlLm5jb21wJG5jb21wCm5jb21wCm5jb21wID0gMgojIyMjIwpzZWxlY3Qua2VlcFggPC0gdHVuZS5zcGxzZGEkY2hvaWNlLmtlZXBYWzE6bmNvbXBdICAjIG9wdGltYWwgbnVtYmVyIG9mIHZhcmlhYmxlcyB0byBzZWxlY3QKc2VsZWN0LmtlZXBYCgojIyMjIwoKc3Bsc2RhLmRhdGEgPC0gbWl4T21pY3M6OnNwbHNkYShYLCBZLCBuY29tcCA9IG5jb21wLCBrZWVwWCA9IHNlbGVjdC5rZWVwWCkgCgojIyMjIwoKcGxvdEluZGl2KHNwbHNkYS5kYXRhLCAKICAgICAgICAgIGNvbXAgPSBjKDEsMiksCiAgICAgICAgICBncm91cCA9IFksIAogICAgICAgICAgaW5kLm5hbWVzID0gRiwgCiAgICAgICAgICBlbGxpcHNlID0gVFJVRSwKICAgICAgICAgICNjb2wucGVyLmdyb3VwID0gIHBhdGllbnRfa2NsdXN0M19sYWIsCiAgICAgICAgICBsZWdlbmQgPSBULCAKICAgICAgICAgIHRpdGxlID0gJ3NQTFMtREEgb24gZGF0YSwgY29tcCAxICYgMicpCgpwbG90TG9hZGluZ3Moc3Bsc2RhLmRhdGEsIGNvbXAgPSAxLG5kaXNwbGF5PTIwLCB0aXRsZSA9ICdMb2FkaW5ncyBvbiBjb21wIDEnLGxlZ2VuZC5jb2xvciA9ICBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYsIAogICAgICAgICAgICAgY29udHJpYiA9ICdtYXgnLCBtZXRob2QgPSAnbWVhbicpCgpwbG90TG9hZGluZ3Moc3Bsc2RhLmRhdGEsIGNvbXAgPSAyLG5kaXNwbGF5ID0gMTAsIHRpdGxlID0gJ0xvYWRpbmdzIG9uIGNvbXAgMicsIGxlZ2VuZC5jb2xvciA9ICBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYsIAogICAgICAgICAgICAgY29udHJpYiA9ICdtYXgnLCBtZXRob2QgPSAnbWVhbicpCgphdWMuc3Bsc2RhIDwtIGF1cm9jKHNwbHNkYS5kYXRhLCByb2MuY29tcCA9IDIsIHByaW50ID0gRkFMU0UpICMgQVVST0MgZm9yIHRoZSBmaXJzdCBjb21wb25lbnQKYXVjLnNwbHNkYSRncmFwaC5Db21wMQoKYXVyb2Moc3Bsc2RhLmRhdGEsIHJvYy5jb21wID0gMSwgcHJpbnQgPSBGQUxTRSkgCmBgYAoKIyMgRmlndXJlIDZBCmBgYHtyfQpzcGxzZGEua2NsdXN0LmNsdXN0ZXJzIDwtIHBsb3RJbmRpdihzcGxzZGEuZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXAgPSBjKDEsMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gWSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZC5uYW1lcyA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGxpcHNlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sLnBlci5ncm91cCA9IHBhdGllbnRfa2NsdXN0M19sYWJfY29udiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gJ3NQTFMtREEgb24gZGF0YSwgY29tcCAxICYgMicpCgooc3Bsc2RhLmtjbHVzdC5jbHVzdGVycy5nZ3Bsb3QgPC0gc3Bsc2RhLmtjbHVzdC5jbHVzdGVycyRkZiAlPiUgCiAgICBtdXRhdGUoZ3JvdXAgPSBmYWN0b3IoZ3JvdXAsIGxldmVscz1jKCJzZXZlcmUiLCJtb2RlcmF0ZSIsIm1pbGQiLCJjb252YWxlc2NlbmNlIikpKSAlPiUgIAogICAgCiAgICBnZ3Bsb3QoYWVzKHg9eCx5PXksY29sb3I9Z3JvdXApKSArCiAgICBnZ2ZvcmNlOjpnZW9tX21hcmtfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoZ3JvdXApLCBmaWxsPWdyb3VwKSxhbHBoYT0uMSxzaG93LmxlZ2VuZCA9IEYsIGV4cGFuZCA9IHVuaXQoMC41LCJtbSIpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC41KSArIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpICsKICAgIAogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnModGl0bGUgPSAic3BhcnNlIFBMUy1EQSIsCiAgICAgICAgIGNvbG9yPSBOVUxMLAogICAgICAgICB4PXBhc3RlMCgiWC12YXJpYXRlIDE6ICIscm91bmQoc3Bsc2RhLmRhdGEkcHJvcF9leHBsX3ZhciRYW1sxXV0qMTAwLDEpLCIlIGV4cGwuIHZhciIpLAogICAgICAgICB5PXBhc3RlMCgiWC12YXJpYXRlIDI6ICIscm91bmQoc3Bsc2RhLmRhdGEkcHJvcF9leHBsX3ZhciRYW1syXV0qMTAwLDEpLCIlIGV4cGwuIHZhciIpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSAKKQoKYGBgCgojIyBGaWd1cmUgNkIKYGBge3J9CnBsc2RhX2xvYWRpbmdzLmRmIDwtICAgCiAgZGF0YS5mcmFtZShzcGxzZGEuZGF0YSRsb2FkaW5ncyRYKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJBc3NheSIpICU+JSAKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAiY29tcCIsdmFsdWVzX3RvID0gInZhbHVlcyIsY29scyA9IC1Bc3NheSkgJT4lIAogIGZpbHRlcih2YWx1ZXMgIT0gMCwKICAgICAgICAgY29tcCAlaW4lIGMoImNvbXAxIiwiY29tcDIiKSkgJT4lIAogIGdyb3VwX2J5KGNvbXApICU+JSAKICBtdXRhdGUodmFsdWVzID0gc2NhbGVzOjpyZXNjYWxlKHZhbHVlcywgdG89YygtMSwxKSkpICU+JSAKICB1bmdyb3VwKCkgCgoocGxzZGFfbG9hZGluZ3Mudm9sY2Fuby5hbHQgPC0gIHBsc2RhX2xvYWRpbmdzLmRmICU+JSAKICAgIGdncGxvdChhZXMoeD1mY3RfcmVvcmRlcihBc3NheSx2YWx1ZXMsLmRlc2MgPSBUKSwgeT12YWx1ZXMsIGNvbG9yPWNvbXAsZmlsbD1jb21wKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuNSxhbHBoYT0xKSArCiAgICBnZW9tX2NvbCh3aWR0aCA9IDAuMDEpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKGNvbXAxID0gIiMxZjc4YjQiLGNvbXAyID0gIiNiMmRmOGEiKSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoY29tcDEgPSAiIzFmNzhiNCIsY29tcDIgPSAiI2IyZGY4YSIpKSArCiAgICBsYWJzKHg9IiIsCiAgICAgICAgIGZpbGw9TlVMTCwKICAgICAgICAgY29sb3I9TlVMTCwKICAgICAgICAgeT0ic2NhbGVkIGxvYWRpbmcgdmFsdWVzIiwKICAgICAgICAgdGl0bGU9InNQTFNEQSBsb2FkaW5ncyIpICsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbj0icmlnaHQiLCAKICAgICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMCwgInB0IikpKQpgYGAKCmBgYHtyfQptYWxhcmlhLnNldmVyaXR5LnNpZ2FudHVyZSA8LSBkYXRhLmZyYW1lKHNwbHNkYS5kYXRhJGxvYWRpbmdzJFgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oIkFzc2F5IikgJT4lIAogIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJjb21wIix2YWx1ZXNfdG8gPSAidmFsdWVzIixjb2xzID0gLUFzc2F5KSAlPiUgCiAgZmlsdGVyKHZhbHVlcyAhPSAwLAogICAgICAgICBjb21wICVpbiUgYygiY29tcDEiLCJjb21wMiIpCiAgICAgICAgICkKYGBgCgojIyBGaWd1cmUgNkMKYGBge3J9Cm15X2NvbXBhcmlzb25zX3NldmVyZV9jb252IDwtIGxpc3QoYygic2V2ZXJlIiwgIm1vZGVyYXRlIiksIGMoIm1vZGVyYXRlIiwgIm1pbGQiKSwgYygic2V2ZXJlIiwgIm1pbGQiKSxjKCJtaWxkIiwiY29udmFsZXNjZW5jZSIpKQoKc3Bsc2RhLmMxLnRvcDkgPC0gcGxzZGFfbG9hZGluZ3MuZGYgJT4lIAogICNmaWx0ZXIoY29tcD09ImNvbXAxIikgJT4lIAogIHNsaWNlX21heChuPTksIG9yZGVyX2J5ID0gYWJzKHZhbHVlcykpICU+JSAKICAjYXJyYW5nZShjb21wKSAlPiUgCiAgI3NsaWNlX21pbihuPTksIG9yZGVyX2J5ID0gdmFsdWVzKSAlPiUgCiAgICBwdWxsKEFzc2F5KSMgJT4lIAoKKHNwbHNkYS5jMS50b3A5IDwtIGRmX2FjdXRlX3BhdGNsdXN0X2luY2xfY29udiAlPiUgCgogICAgZHBseXI6OmZpbHRlcihBc3NheSAlaW4lIGMoc3Bsc2RhLmMxLnRvcDkpKSAlPiUgCiAgICBtdXRhdGUoQXNzYXkgPSBmYWN0b3IoQXNzYXksIGxldmVscyA9IGMoc3Bsc2RhLmMxLnRvcDkpKSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PXNldmVyaXR5X2xhYiwgeT1OUFgsIGNvbG9yPXNldmVyaXR5X2xhYiwgZmlsbD1zZXZlcml0eV9sYWIpKSArIAogICAgZ2VvbV92aW9saW4odHJpbSA9IEYsYWxwaGE9LjkpICsKICAgIGdlb21faml0dGVyKHNpemU9MC4yNSxzaG93LmxlZ2VuZCA9IEYsIHdpZHRoID0gMC4wNSwgYWxwaGE9MSwgY29sb3I9ImdyZXkyMCIpICsKICAgIGdlb21fYm94cGxvdChhbHBoYT0uNyx3aWR0aD0wLjI1LG91dGxpZXIuc2hhcGUgPSBOQSxjb2xvcj0iYmxhY2siLCBmYXR0ZW4gPSAyLGx3ZD0uMjUsc2hvdy5sZWdlbmQgPSBGKSArCiAgICBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0IiwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbC5zZXAgPSAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBULAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gInAuc2lnbmlmIiAsCiAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgICBzaXplPTIsCiAgICAgICAgICAgICAgICAgICAgICAgbHdkID0gLjIsCiAgICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvbnMgPW15X2NvbXBhcmlzb25zX3NldmVyZV9jb252LAogICAgICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKwogICAgZmFjZXRfd3JhcCh+QXNzYXksbmNvbCA9IDMsc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh4PSIiLAogICAgICAgICBjb2xvcj1OVUxMLAogICAgICAgICBmaWxsPU5VTEwpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IHBhdGllbnRfa2NsdXN0M19sYWJfY29udikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpKQpgYGAKCmBgYHtyfQpwbHNkYS5zZWxlY3Rpb24gPC0gbWFsYXJpYS5zZXZlcml0eS5zaWdhbnR1cmUgJT4lIHB1bGwoQXNzYXkpCgpkYXRhLmZyYW1lKEFzc2F5ID0gcGxzZGEuc2VsZWN0aW9uKSAlPiUgCiAgbGVmdF9qb2luKHVuaXZlcnNlLnByb3RlaW5zLGJ5PSJBc3NheSIpICU+JSAKICB0cmFuc211dGUoQXNzYXksIFVuaVByb3QpIyAlPiUgCiAgI3dyaXRlX3RzdihwYXN0ZTAocmVzdWx0LmRpciwiTUlQX1NldmVyaXR5X1Byb3RlaW5fc2lnbmF0dXJlX3VuaXByb3RpZC50c3YiKSkKYGBgCgojIyBGaWd1cmUgNkQKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgRXhwbG9yZSAxNTM2IGRhdGEgc2V0IC0gTUdIIENvdmlkLTE5IHN0dWR5LCBGaWxiaW4gZXQgYWwuIDIwMjEKIyMjIyBNYWtlIGRhdGEgcmVhZHkKIyBpZGVudGlmeSBwcm90ZWlucyB3aXRoIE5QWCBiZWxvdyBMT0QgaW4gbW9yZSB0aGFuIDcwJSBvZiBzYW1wbGVzCmFzc2F5czJybSA8LSBjb3ZpZF9OUFhkYXRhICU+JSAKICBtdXRhdGUoYmVsb3dMT0QgPSBMT0Q+TlBYKSAlPiUgCiAgZ3JvdXBfYnkoQXNzYXkpICU+JSAKICBjb3VudChiZWxvd0xPRCxzb3J0PVRSVUUpICU+JSAKICBmaWx0ZXIoYmVsb3dMT0Q9PVQsCiAgICAgICAgIG4gPiBsZW5ndGgodW5pcXVlKGNvdmlkX05QWGRhdGEkU2FtcGxlSUQpKSowLjcpICU+JSAKICBwdWxsKEFzc2F5KQoKIyByZW1vdmUgcHJvdGVpbnMgaWRlbnRpZmllZCBhYm92ZSBmcm9tIGRhdGEKY292aWRfTlBYZGF0YV9ybSA8LSBjb3ZpZF9OUFhkYXRhICU+JSAKICBmaWx0ZXIoIUFzc2F5JWluJWFzc2F5czJybSwgVGltZXBvaW50PT0iRDAiKSAlPiUKICBkcGx5cjo6c2VsZWN0KFNhbXBsZUlELCBzdWJqZWN0X2lkLCBBc3NheSwgTlBYLCBQYW5lbCkKCiMgaWRlbnRpZnkgcHJvdGVpbnMgd2l0aCBkaWZmZXJlbnQgdmFsdWVzIGluIGRpZmZlcmVudCBwYW5lbHMKYXNzYXlzMnJtIDwtIGNvdmlkX05QWGRhdGFfcm0gJT4lCiAgZ3JvdXBfYnkoc3ViamVjdF9pZCwgQXNzYXkpICU+JQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBmaWx0ZXIobiA+IDFMKSAlPiUKICBwdWxsKEFzc2F5KSAlPiUKICB1bmlxdWUoKQoKIyBvbmUgZXhhbXBsZSBvZiB0aGUgcHJvdGVpbnMgaWRlbnRpZmllZCBhYm92ZQpjb3ZpZF9OUFhkYXRhX3JtICU+JSBmaWx0ZXIoc3ViamVjdF9pZD09MSxBc3NheT09IkNYQ0w4IikKCiMgY29udmVydCBkYXRhIHRvIHdpZGUgZm9ybWF0CmNvdmlkX05QWGRhdGFfd2lkZSA8LSBjb3ZpZF9OUFhkYXRhX3JtICU+JQogICMjIHZhbHVlc19mbiBjYWxjdWxhdGVzIG1lZGlhbiB2YWx1ZXMgZm9yIGR1cGxpY2F0ZWQgZmVhdHVyZXMgKGR1cGxpY2F0ZWQgYmVjYXVzZSBwYXJ0IG9mIGV2ZXJ5IG9saW5rIHBhbmVsKQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBBc3NheSwgdmFsdWVzX2Zyb20gPSBOUFgsaWRfY29scyA9IHN1YmplY3RfaWQsIHZhbHVlc19mbiA9IG1lZGlhbikKCiMgbWFrZSBkYXRhIHJlYWR5IGZvciBHU1ZBCmNvdmlkX05QWGRhdGFfbWF0IDwtIGNvdmlkX05QWGRhdGFfd2lkZSAlPiUgIAogIGNvbHVtbl90b19yb3duYW1lcygic3ViamVjdF9pZCIpICU+JQogIGFzLm1hdHJpeCgpICU+JSAKICB0KCkKYGBgCgoKYGBge3J9CiMjIyMgUnVuIHNpbmdsZSBzYW1wbGUgZ2VuZSBzZXQgZW5yaWNobWVudCBhbmFseXNpcwpsaWJyYXJ5KEdTVkEpCiMgcnVuIHNzZ3NlYSBvbiBzaWduYXR1cmUgZnJvbSBzUExTREEKR1NFX3Jlc3VsdHMgPC0gZ3N2YShleHByID0gY292aWRfTlBYZGF0YV9tYXQsCiAgICAgICAgICAgICAgICAgICAgZ3NldC5pZHgubGlzdCA9IGxpc3Qoc2lnPXBsc2RhLnNlbGVjdGlvbiksdmVyYm9zZT1GLAogICAgICAgICAgICAgICAgICAgIG1ldGhvZD0ienNjb3JlIikKCiNkYXRhX3Bsb3Rfc1BMU0RBIDwtIGRhdGEuZnJhbWUoZ3JvdXA9YXMuZmFjdG9yKGNvdmlkX2NsaW5pY2FsRGF0YSRXSE8uMCksc2NvcmU9YXMudmVjdG9yKEdTRV9yZXN1bHRzKSkKCkdTRUFfcmVzdWx0X2RmIDwtIGRhdGEuZnJhbWUoc3ViamVjdF9pZCA9IGNvbG5hbWVzKGNvdmlkX05QWGRhdGFfbWF0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc0VTID0gYXMudmVjdG9yKEdTRV9yZXN1bHRzKSkgJT4lIAogIHJpZ2h0X2pvaW4obWdoLmNvdmlkLm1ldGEgJT4lIHRyYW5zbXV0ZShzdWJqZWN0X2lkPSBhcy5jaGFyYWN0ZXIoc3ViamVjdF9pZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdob18wID0gYXMuZmFjdG9yKHdob18wKSksIGJ5PSJzdWJqZWN0X2lkIikKCiMgc2hvdyByZXN1bHRzCihNR0hfY292aWRfc3NFUyA8LSBHU0VBX3Jlc3VsdF9kZiAlPiUgCiAgZ2dwbG90KGFlcyh4PXdob18wLCB5PXNzRVMsIGZpbGw9d2hvXzApKSArCiAgICBnZW9tX2ppdHRlcih3aWR0aD0wLjE1LHNpemU9LjMsYWxwaGE9LjIpICsKICMgZ2VvbV92aW9saW4od2lkdGg9MS41LCB0cmltID0gRiwgYWxwaGE9MC43LHNob3cubGVnZW5kID0gRixsd2Q9LjI1KSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPS4zLGFscGhhPS42LCBmYXR0ZW4gPSAyLGx3ZD0uMjUsb3V0bGllci5jb2xvdXIgPSBOQSkgKwogICNnZW9tX2JveHBsb3QoYWxwaGE9MC42LCB3aWR0aD0uMiwgc2hvdy5sZWdlbmQgPSBGKSsKICB0aGVtZV9taW5pbWFsKCkrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHk9InNzRVMgc2NvcmUgKHpzY29yZSkiLHg9IlNldmVyaXR5IGdyb3VwIixmaWxsPSIiKSkKCmBgYAoKIyMgRmlndXJlIDZFCgoKYGBge3J9CiMjIyMgTWFrZSBkYXRhIHJlYWR5CgpNSVAubG9uZyA8LSBkYXRhLmxvbmcgJT4lIAogIGxlZnRfam9pbihzYW1wbGVUYWJsZV9zaW1wbGUpICU+JQogIGZpbHRlcighZ3JlcGwoIkQxMCIsc2FtcGxlX2lkKSkgJT4lIAogICAgbGVmdF9qb2luKHBhdGllbnRfY2x1c3QpICU+JSAKICBtdXRhdGUoc2FtcGxlX3R5cGUgPSBjYXNlX3doZW4oVGltZT09IkFjdXRlIiB+IHBhc3RlMChzZXZlcml0eV9sYWIsIiBtYWxhcmlhIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gcGFzdGUwKCNUaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYWxhcmlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIGNvbnZhbGVzY2VuY2UiKSkpICU+JSAKICB0cmFuc211dGUoc2FtcGxlX2lkLCBzYW1wbGVfdHlwZSwgQXNzYXksIE5QWCkKCgpkYXRhX3RmX21pcF93aWRlIDwtIFRGLmxvbmcgJT4lIAogIGJpbmRfcm93cyhNSVAubG9uZykgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBBc3NheSwgdmFsdWVzX2Zyb20gPSBOUFgsIGlkX2NvbHMgPSBjKHNhbXBsZV9pZCxzYW1wbGVfdHlwZSksIHZhbHVlc19mbiA9IG1lZGlhbikgCgphbGwubWF0IDwtIGRhdGFfdGZfbWlwX3dpZGUgJT4lCiAgZHBseXI6OnNlbGVjdCgtYyhzYW1wbGVfdHlwZSkpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoInNhbXBsZV9pZCIpICU+JSAKICBhcy5tYXRyaXgoKSAlPiUgCiAgdCgpCmBgYAoKCmBgYHtyfQojIyMjIFJ1biBzaW5nbGUgc2FtcGxlIGdlbmUgc2V0IGVucmljaG1lbnQgYW5hbHlzaXMKbGlicmFyeShHU1ZBKQojIHJ1biBzc2dzZWEgb24gc2lnbmF0dXJlIGZyb20gc1BMU0RBCkdTRV9yZXN1bHRzIDwtIGdzdmEoZXhwciA9IGFsbC5tYXQsCiAgICAgICAgICAgICAgICAgICAgZ3NldC5pZHgubGlzdCA9IGxpc3Qoc2lnPXBsc2RhLnNlbGVjdGlvbiksI2xpc3Qoc2lnPXNldmVyaXR5X3NpZ25hdHVyZV9wcm90ZWlucyksCiAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1GLAogICAgICAgICAgICAgICAgICAgIG1ldGhvZD0ienNjb3JlIikKCgpHU0VBX3Jlc3VsdF9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZV9pZCA9IGNvbG5hbWVzKGFsbC5tYXQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzRVMgPSBhcy52ZWN0b3IoR1NFX3Jlc3VsdHMpKSAlPiUgCiAgbGVmdF9qb2luKGRhdGFfdGZfbWlwX3dpZGUgJT4lIGRwbHlyOjpzZWxlY3Qoc2FtcGxlX2lkLHNhbXBsZV90eXBlKSwgYnk9InNhbXBsZV9pZCIpICU+JSAKICBsZWZ0X2pvaW4oCiAgVEZfU09GQSAlPiUgdHJhbnNtdXRlKHNhbXBsZV9pZCA9IHBhc3RlMChzdHVkeV9pZCwifEFjdXRlIiksIFNPRkFfdG90YWwpICU+JQogIGJpbmRfcm93cygKICAgIHN1YmplY3RUYWJsZSAlPiUgdHJhbnNtdXRlKHNhbXBsZV9pZCA9IHBhc3RlMChzdHVkeV9pZCwifEFjdXRlIiksIFNPRkFfdG90YWwpCiAgKSkgJT4lIAogIG11dGF0ZShzYW1wbGVfdHlwZSA9IGNhc2Vfd2hlbihzYW1wbGVfdHlwZSA9PSAiSW5mbHVlbnNhIEEiIH4gIkluZmx1ZW56YSBBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX3R5cGUgPT0gIkluZmx1ZW5zYSBCIiB+ICJJbmZsdWVuemEgQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gc2FtcGxlX3R5cGUpKQoKIyBzaG93IHJlc3VsdHMKCihURl9zc0VTX3Bsb3QgPC0gR1NFQV9yZXN1bHRfZGYgJT4lIApnZ3Bsb3QoYWVzKHg9ZmN0X3Jlb3JkZXIoc2FtcGxlX3R5cGUsc3NFUywgbWVkaWFuLC5kZXNjID0gVCksIHk9c3NFUywgZmlsbD1zYW1wbGVfdHlwZSkpICsKICBnZW9tX2ppdHRlcih3aWR0aD0wLjE1LHNpemU9LjMsYWxwaGE9LjIpICsKICBnZW9tX2JveHBsb3Qod2lkdGg9LjMsYWxwaGE9LjYsIGZhdHRlbiA9IDIsbHdkPS4yNSxvdXRsaWVyLmNvbG91ciA9IE5BKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJzZXZlcmUgbWFsYXJpYSI9cGF0aWVudF9rY2x1c3QzX2xhYltbM11dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vZGVyYXRlIG1hbGFyaWEiPXBhdGllbnRfa2NsdXN0M19sYWJbWzJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtaWxkIG1hbGFyaWEiPXBhdGllbnRfa2NsdXN0M19sYWJbWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYWxhcmlhIGNvbnZhbGVzY2VuY2UiPXBhdGllbnRfa2NsdXN0M19sYWJfY29udltbNF1dKSwKICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gIiM4ZGQzYzciKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxsaW5ldHlwZT0iZG90dGVkIikgKwogIGxhYnModGl0bGU9IkV2YWx1YXRpb24gb2YgbWFsYXJpYSBkaXNlYXNlIHNldmVyaXR5IHNpZ25hdHVyZSIsCiAgICAgICB4PU5VTEwsCiAgICAgICB5PSJHZW5lIFNldCBWYXJpYXRpb24gQW5hbHlzaXNcbnNpbmdsZSBzYW1wbGUgZW5yaWNobWVudCBzY29yZVxuKHpzY29yZSkiLAogICAgICAgZmlsbD0iIikgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gbGFiZWxfd3JhcCg4KSkgKQoKYGBgCgojIyBTdXBwbGVtZW50YXJ5IFRhYmxlIFM1CgpgYGB7cn0KbWFsYXJpYS5zZXZlcml0eS5zaWdhbnR1cmUgJT4lIAogIGFycmFuZ2UodmFsdWVzKSAlPiUgCiAgZHBseXI6OnJlbmFtZShpbXBvcnRhbmNlID0gdmFsdWVzKSAlPiUgCiAgaGVhZCgpCiAgI3dyaXRlX3RzdihwYXN0ZTAocmVzdWx0LmRpciwiU3VwcGxlbWVudGFyeV9UYWJsZVM1X1NldmVyaXR5U2lnbmF0dXJlLnRzdiIpKQpgYGAKCiMjIFN1cHBsZW1lbnRhcnkgVGFibGUgUzYgClRGIGNvaG9ydCAtIHNhbXBsZVRhYmxlCgpgYGB7cn0KIyNndHN1bW1hcnkKbGlicmFyeShndHN1bW1hcnkpCgpURl9zYW1wbGVUYWJsZSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtc2FtcGxlX3R5cGUpICU+JSAKICBpbm5lcl9qb2luKEdTRUFfcmVzdWx0X2RmLCBieT0ic2FtcGxlX2lkIikgJT4lIAogIHRyYW5zbXV0ZShzYW1wbGVfdHlwZSwgCiAgICAgICAgICAgIFNPRkFfdG90YWwgPSBhcy5udW1lcmljKFNPRkFfdG90YWwpLAogICAgICAgICAgICBhZ2UgPSBhcy5udW1lcmljKGFnZSksCiAgICAgICAgICAgIGdlbmRlcikgJT4lIAogIGZpbHRlcighZ3JlcGwoIk1hbGFyaWF8bWFsYXJpYSIsIHNhbXBsZV90eXBlKSkgJT4lIAogIAogIHRibF9zdW1tYXJ5KGluY2x1ZGUgPSBjKHNhbXBsZV90eXBlLCBhZ2UsIGdlbmRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICBTT0ZBX3RvdGFsKSwKICAgICAgICAgICAgICBieSA9IHNhbXBsZV90eXBlLAogICAgICAgICAgICAgIHN0YXRpc3RpYyA9IGxpc3QoYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0te21heH0pIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbF9jYXRlZ29yaWNhbCgpIH4gIntufSAvIHtOfSAoe3B9JSkiCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAjZGlnaXRzID0gYWxsX2NvbnRpbnVvdXMoKSB+IDIKICAgICAgICAgICAgICBkaWdpdHMgPSBjKGFnZSB+IDApCiAgICAgICAgICAgICAgKQpgYGAKCgoKIyBGaWd1cmUgNyAKKipBIHByb3RlaW4tY2VudHJpYyB2aWV3IG9uIGludGVncmF0ZWQgYW5hbHlzaXMgdG8gYXNjZXJ0YWluIGltbXVuZSBjZWxsIGNvbW11bmljYXRpb24gYXNzb2NpYXRlZCB3aXRoIGRpc2Vhc2Ugc2V2ZXJpdHkqKgoKCiMjIEZpZ3VyZSA3QQpgYGB7cn0Kc2ltaWxhcl9tb2R1bGVzIDwtIGMocmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlLAogICAgICAgICAgICAgICAgICAgICBtb2R1bGVfZGYgJT4lIGZpbHRlcihjb2xvcnM9PSJicm93biIpICU+JSBwdWxsKEFzc2F5KSwKICAgICAgICAgICAgICAgICAgICAgbW9kdWxlX2RmICU+JSBmaWx0ZXIoY29sb3JzPT0iYmx1ZSIpICU+JSBwdWxsKEFzc2F5KSkKbGlicmFyeShldWxlcnIpCmV1bGVyX3Bsb3QgPC0gZXVsZXIoCiAgbGlzdCgKICAgICJEaWZmZXJlbnRpYWxcbmFidW5kYW50XG5wcm90ZWluc1xuaW5cbmFjdXRlIG1hbGFyaWEiPXNlbGVjdGVkLmFzc2F5cy53Y25hLAogICAgIlNldmVyaXR5IGFzc29jaWF0ZWRcbnByb3RlaW5zIGluIHBsYXNtYSIgPSByZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UpCikKCnBsb3QoZXVsZXJfcGxvdCwKICAgICBmaWxscyA9IGMoIndoaXRlIiwKICAgICAgICAgICAgICAgInR1cnF1b2lzZSIpLAogICAgICAgICAgICAgICAKICAgICBxdWFudGl0aWVzID0gVFJVRSwKICAgICBsdHkgPSAxLCMxOjMsCiAgICAgZm9udHNpemU9NiwKICAgICBsYWJlbHMgPSBsaXN0KGZvbnRzaXplPTUpLAogICAgIHNoYXBlID0gImVsbGlwc2UiKSAKCmBgYAoKCiMjIEZpZ3VyZSA3QgoKYGBge3J9CnNlY3JldG9tZV9sb2NhdGlvbl9kYXBfc2V2ZXJpdHkgPC0gZGFwLnJlcyAlPiUgCiAgZmlsdGVyKEFzc2F5ICVpbiUgcmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlKSAlPiUgCiAgaW5uZXJfam9pbihocGFfMjQuMCwgYnk9YygiQXNzYXkiPSJnZW5lIiwiVW5pUHJvdCI9InVuaXByb3QiKSkgJT4lIAogIG11dGF0ZShzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMgPSBjYXNlX3doZW4oc2VjcmV0b21lX2xvY2F0aW9uPT0iTm90IHNlY3JldGVkIn4gcGFzdGUwKHNlY3JldG9tZV9sb2NhdGlvbiwiIC0gIixybmFfdGlzc3VlX3NwZWNpZmljaXR5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBzZWNyZXRvbWVfbG9jYXRpb24pKSAlPiUgCiAgZ3JvdXBfYnkoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSAlPiUgCiBtdXRhdGUobl9zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMgPSBuKCkpICNjb3VudChzb3J0ID0gVFJVRSkgCgoKIyMgcGxvdCBldmVyeXRoaW5nCihocGEucHJvdGVpbi5vcmlnaW4ub3ZlcnZpZXdfc2V2ZXJpdHkgPC0gc2VjcmV0b21lX2xvY2F0aW9uX2RhcF9zZXZlcml0eSAlPiUgCiAgICB1bmdyb3VwKCkgJT4lIAogICAgdHJhbnNtdXRlKHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyA9IGZhY3RvcihzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gcmV2KGMoIlNlY3JldGVkIHRvIGJsb29kIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW50cmFjZWxsdWxhciBhbmQgbWVtYnJhbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCBpbiBvdGhlciB0aXNzdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgdG8gZXh0cmFjZWxsdWxhciBtYXRyaXgiLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIHRvIGRpZ2VzdGl2ZSBzeXN0ZW0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gYnJhaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCAtIHVua25vd24gbG9jYXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCBpbiBmZW1hbGUgcmVwcm9kdWN0aXZlIHN5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIG1hbGUgcmVwcm9kdWN0aXZlIHN5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBzZWNyZXRlZCAtIFRpc3N1ZSBlbnJpY2hlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBUaXNzdWUgZW5oYW5jZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc2VjcmV0ZWQgLSBHcm91cCBlbnJpY2hlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBzZWNyZXRlZCAtIExvdyB0aXNzdWUgc3BlY2lmaWNpdHkiKSkpLAogICAgICAgICAgICAgIG5fc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSAlPiUgCiAgICBkaXN0aW5jdCgpICU+JSAKICAgIGdncGxvdChhZXMoeCA9IHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYywgeSA9IG5fc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjLCBmaWxsID0gc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSkgKwogICAgZ2VvbV9jb2wod2lkdGggPSAwLjUpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9bl9zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpLHNpemU9MiwgbnVkZ2VfeSA9IC0uMikgKwogICAgY29vcmRfZmxpcCgpICsKICAgIHNjYWxlX3lfY29udGludW91cyh0cmFucz0icHNldWRvX2xvZyIsbmFtZSA9ICJOdW1iZXIgb2YgcHJvdGVpbnNcbmFzc29jaWF0ZWQgd2l0aCBzZXZlcml0eSIsCiAgICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LixsYWJlbHMgPSBOVUxMLGJyZWFrcyA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjbmFtZSA9ICJOdW1iZXIgb2YgREFQcyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksIAogICAgICAgICAgICAgICAgICAgICAgICNleHBhbmQ9YygwLC4xNSkKICAgICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBjKDAsMCkKICAgICAgICAgICAgICAgICAgICAgICApICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKwoKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1zZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWNfY29scywKICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IHNlY3JldG9tZV9sb2NhdGlvbl9kYXAub3JkZXIpICsKICAgIGxhYnMoZmlsbD0iUHJvdGVpblxub3JpZ2luXG5ieSBIUEEiLAogICAgICAgICB4PU5VTEwpKQoKIyMgcGxvdCBldmVyeXRoaW5nCihocGEucHJvdGVpbi5vcmlnaW4ub3ZlcnZpZXdfc2V2ZXJpdHkgPC0gc2VjcmV0b21lX2xvY2F0aW9uX2RhcF9zZXZlcml0eSAlPiUgCiAgICB1bmdyb3VwKCkgJT4lIAogICAgdHJhbnNtdXRlKHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYyA9IGZhY3RvcihzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiU2VjcmV0ZWQgdG8gYmxvb2QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbnRyYWNlbGx1bGFyIGFuZCBtZW1icmFuZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIG90aGVyIHRpc3N1ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCB0byBleHRyYWNlbGx1bGFyIG1hdHJpeCIsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgdG8gZGlnZXN0aXZlIHN5c3RlbSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWNyZXRlZCBpbiBicmFpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIC0gdW5rbm93biBsb2NhdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY3JldGVkIGluIGZlbWFsZSByZXByb2R1Y3RpdmUgc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VjcmV0ZWQgaW4gbWFsZSByZXByb2R1Y3RpdmUgc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm90IHNlY3JldGVkIC0gVGlzc3VlIGVucmljaGVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBzZWNyZXRlZCAtIFRpc3N1ZSBlbmhhbmNlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdCBzZWNyZXRlZCAtIEdyb3VwIGVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm90IHNlY3JldGVkIC0gTG93IHRpc3N1ZSBzcGVjaWZpY2l0eSIpKSwKICAgICAgICAgICAgICBuX3NlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykgJT4lIAogICAgZGlzdGluY3QoKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMsIHkgPSBuX3NlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYywgZmlsbCA9IHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykpICsKICAgIGdlb21fY29sKHdpZHRoID0gMC41KSArCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsPW5fc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSxzaXplPTIsIG51ZGdlX3kgPTEuNSkgKyAjMC4xCiAgICAjY29vcmRfZmxpcCgpICsKICAgIHNjYWxlX3lfY29udGludW91cygjdHJhbnM9InBzZXVkb19sb2ciLAogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTnVtYmVyIG9mIHByb3RlaW5zIiwKICAgICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uLGxhYmVscyA9IE5VTEwsYnJlYWtzID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNuYW1lID0gIk51bWJlciBvZiBEQVBzIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwgCiAgICAgICAgICAgICAgICAgICAgICAgI2V4cGFuZD1jKDAsLjE1KQogICAgICAgICAgICAgICAgICAgICAgICNleHBhbmQgPSBjKDAsMC4xKSwKICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsNTEpCiAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LGFuZ2xlPTkwLGhqdXN0ID0gMSx2anVzdCA9IDAuNSksCiAgICAgICAgICAjYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsYW5nbGU9NDUsaGp1c3QgPSAxKSwKICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAoKICAgICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsKCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9c2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjX2NvbHMsCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBzZWNyZXRvbWVfbG9jYXRpb25fZGFwLm9yZGVyKSArCiAgICBsYWJzKGZpbGw9IlByb3RlaW5cbm9yaWdpblxuYnkgSFBBIiwKICAgICAgICAgeD1OVUxMKSkKYGBgCgojIyBGaWd1cmUgN0MKYGBge3J9CnByb3RlaW5zMmxhYmVsIDwtIGRmX2FjdXRlX3BhdGNsdXN0X2luY2xfY29udiAlPiUgCiAgZ3JvdXBfYnkoVW5pUHJvdCxBc3NheSwgc2V2ZXJpdHlfbGFiKSAlPiUgCiAgc3VtbWFyaXNlKE5QWG1lYW4gPSBtZWFuKE5QWCksCiAgICAgICAgICAgIE5QWG1lZGlhbiA9IG1lZGlhbihOUFgpLAogICAgICAgICAgICBOUFhzZCA9IHNkKE5QWCksCiAgICAgICAgICAgIE5QWG4gPSBuKCksCiAgICAgICAgICAgIE5QWHNlID0gTlBYc2QgLyBzcXJ0KE5QWG4pCiAgKSAlPiUgCiAgI3VuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKE5QWGNpOTUgPSBOUFhzZSAqIHF0KC45NzUsIE5QWG4gLSAxKSkgJT4lIAogIGxlZnRfam9pbigKICAgIHNlY3JldG9tZV9sb2NhdGlvbl9kYXBfc2V2ZXJpdHkgJT4lCiAgICBmaWx0ZXIoQXNzYXkgJWluJSByZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UpICU+JQogIHRyYW5zbXV0ZShBc3NheSxzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpLCBieT0iQXNzYXkiCiAgKSAlPiUgCiAgZmlsdGVyKHNldmVyaXR5X2xhYj09InNldmVyZSIsCiAgICAgICAgIEFzc2F5ICVpbiUgcmVzdHJpY3RlZF9tb2R1bGVfdHVycXVvaXNlLAogICAgICAgICAhaXMubmEoc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSkgJT4lIAogIAogIGdyb3VwX2J5KHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykgJT4lIAogICN0cmFuc211dGUoQXNzYXksTlBYLCBzZXZlcml0eV9sYWIsIHNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYykgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIHNsaWNlX21heChvcmRlcl9ieSA9IE5QWG1lYW4sbiA9IDMpICU+JSBwdWxsKEFzc2F5KQpgYGAKCgoKYGBge3IgZmlnLmhlaWdodCA9IDEuNSwgZmlnLndpZHRoPSA0fQp0bXAuZGYgPC0gZGZfYWN1dGVfcGF0Y2x1c3RfaW5jbF9jb252ICU+JSAKICBncm91cF9ieShVbmlQcm90LEFzc2F5LCBzZXZlcml0eV9sYWIpICU+JSAKICBzdW1tYXJpc2UoTlBYbWVhbiA9IG1lYW4oTlBYKSwKICAgICAgICAgICAgTlBYbWVkaWFuID0gbWVkaWFuKE5QWCksCiAgICAgICAgICAgIE5QWHNkID0gc2QoTlBYKSwKICAgICAgICAgICAgTlBYbiA9IG4oKSwKICAgICAgICAgICAgTlBYc2UgPSBOUFhzZCAvIHNxcnQoTlBYbikKICApICU+JSAKICAjdW5ncm91cCgpICU+JSAKICBtdXRhdGUoTlBYY2k5NSA9IE5QWHNlICogcXQoLjk3NSwgTlBYbiAtIDEpKSAlPiUgCiAgZmlsdGVyKEFzc2F5JWluJXJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSkgJT4lIAogIGxlZnRfam9pbigKICAgIHNlY3JldG9tZV9sb2NhdGlvbl9kYXBfc2V2ZXJpdHklPiUgCiAgICAgIHRyYW5zbXV0ZShBc3NheSwgc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSwgYnk9IkFzc2F5IikKCih0dXJxb2lzZV9hbGxQcm90ZWluc19sYWIgPC0gdG1wLmRmICU+JSAKICBnZ3Bsb3QoYWVzKHg9ZmN0X3Jlb3JkZXIoQXNzYXksTlBYbWVhbiwuZGVzYyA9IEYpLCB5PU5QWG1lYW4pKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xNixzaXplPS41LGFlcyhjb2xvcj1zZXZlcml0eV9sYWIpKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeCA9IEFzc2F5LCNyZW9yZGVyKHN0cl93cmFwKEFzc2F5LCA1KSwgZXN0aW1hdGUpLAogICAgICAgICAgICAgICAgICAgIHltaW49TlBYbWVhbi1OUFhjaTk1LCAKICAgICAgICAgICAgICAgICAgICB5bWF4PU5QWG1lYW4rTlBYY2k5NSwKICAgICAgICAgICAgICAgICAgICBjb2xvcj1zZXZlcml0eV9sYWIpLAogICAgICAgICAgICAgICAgbGluZXdpZHRoPS4yLCAgICAjIFRoaW5uZXIgbGluZXMKICAgICAgICAgICAgICAgIHdpZHRoPS4yLAogICAgICAgICAgICAgICAgYWxwaGE9LjUpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLGx0eT01LCBsd2Q9LjIpICsKICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhID0gLiAlPiUgZmlsdGVyKEFzc2F5ICVpbiUgcHJvdGVpbnMybGFiZWwsI2MoIkxHQUxTOSIsIkhBVkNSMiIsIklMNCIsIklMNFIiLCJDRDcwIiwiUERDRDEiLCJDRDI3NCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V2ZXJpdHlfbGFiID09ICJzZXZlcmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBBc3NheSwgY29sb3VyPXNlY3JldG9tZV9sb2NhdGlvbl90aXNzdWVfc3BlYywgbnVkZ2VfeT1OUFhtZWFuKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gLjksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yY2VfcHVsbCA9IDMsICMgZG8gbm90IHB1bGwgdG93YXJkIGRhdGEgcG9pbnRzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yY2UgPSAuMTUsICMgU3RyZW5ndGggb2YgdGhlIHJlcHVsc2lvbiBmb3JjZS4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBEbyBub3QgcmVwZWwgZnJvbSB0b3Agb3IgYm90dG9tIGVkZ2VzLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDEsIEluZiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uICAgID0gInkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlICAgICAgICA9IDkwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ICAgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMS8yMCwgICAgIyMgc2VnbWVudCB3aWR0aAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQubGluZXdpZHRoID0gMS8xMiwjMC4wMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4wNCwgJ25wYycpKSwgICAgICMgRHJhdyBhbiBhcnJvdyBmcm9tIHRoZSBsYWJlbCB0byB0aGUgZGF0YSBwb2ludC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSA1MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXguaXRlciA9IDNlMywgICAgICMgTWF4aW11bSBpdGVyYXRpb25zIG9mIHRoZSBuYWl2ZSByZXB1bHNpb24gYWxnb3JpdGhtIE8obl4yKS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmV5MTAiCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKC0xLjUsOC41KSxleHBhbmQgPSBjKDAsMCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGF0aWVudF9rY2x1c3QzX2xhYl9jb252KSArCiAgICAgIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsKCiAgI2Nvb3JkX2ZsaXAoKSArCiAgCiAgbGFicyh4PSJTZXZlcml0eSBhc3NvY2lhdGVkIHByb3RlaW5zIGluIHBsYXNtYSIsCiAgICAgICB5PSJOUFgiLAogICAgICAgY29sb3I9TlVMTCwKICAgICAgIGNhcHRpb24gPSAibWVhbk5QWCArLSBjaTk1IikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsYW5nbGU9OTAsaGp1c3Q9MSx2anVzdD0uNSxzaXplID0gMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShzaXplID0gLjEpLAogICAgICAgICNheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICkKKQoKcmVxdWlyZShwYXRjaHdvcmspCihwX2Fubm90YXRpb24gPC0gI3NlY3JldG9tZV9sb2NhdGlvbl9kYXBfc2V2ZXJpdHklPiUgCiAgICAjdHJhbnNtdXRlKEFzc2F5LCBzZWNyZXRvbWVfbG9jYXRpb25fdGlzc3VlX3NwZWMpICU+JSAKICAgIyBsZWZ0X2pvaW4odG1wLmRmLGJ5PSJBc3NheSIpICU+JSAKICAgIHRtcC5kZiAlPiUgCiAgICBtdXRhdGUoZHVtbXkueSA9ICJIUEEiKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmVvcmRlcihBc3NheSxOUFhtZWFuLC5kZXNjID0gRiksIHkgPSBkdW1teS55LCBmaWxsID0gc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjKSkgKwogICAgZ2VvbV90aWxlKGxpbmVqb2luID0gInJvdW5kIikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gc2VjcmV0b21lX2xvY2F0aW9uX3Rpc3N1ZV9zcGVjX2NvbHMpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpIAogICNzY2FsZV95X2Rpc2NyZXRlKGV4cGFuZD1jKDAsLTAuMSkpCiAgICMgdGhlbWUoYXNwZWN0LnJhdGlvID0gMS8xMDApCiAgKQoKdGVzdF9wbG90IDwtIHBfYW5ub3RhdGlvbiAvIHR1cnFvaXNlX2FsbFByb3RlaW5zX2xhYiArIHBsb3RfbGF5b3V0KGhlaWdodCA9IGMoLjUsIDQpKQp0ZXN0X3Bsb3QKYGBgCgoKIyMgRmlndXJlIDdECgpgYGB7cn0KIyMgY3JlYXRlIGEgZ2VuZSBuYW1lIC0gdW5pcHJvdCBkaWN0aW9uYXJ5Cm5hbWVfdXBfZGljdCA8LSBocGFfMjQuMCAlPiUgdHJhbnNtdXRlKGdlbmUsIHVuaXByb3QpCgpsaWdhbmQucSA8LSBkYXAucmVzICU+JSBmaWx0ZXIocC5hZGogPD0wLjAxLCBsb2dGQyA+IC4xKSAlPiUgCiAgbGVmdF9qb2luKGNwZGIucHJvdGVpbl9pbnB1dCwKICAgICAgICAgICAgYnk9YygiVW5pUHJvdCI9InVuaXByb3QiKSkgIyU+JSAKICAjcHVsbChVbmlQcm90KQoKbGVuZ3RoKGxpZ2FuZC5xKQoKCmludGVyYWN0aW9uX2RpY3QgPC0gY3BkYi5pbnRlcmFjdGlvbl9pbnB1dCAlPiUgCiAgZmlsdGVyKHBhcnRuZXJfYSAlaW4lIGxpZ2FuZC5xJFVuaVByb3QsCiAgICAgICAgIGRpcmVjdGlvbmFsaXR5ID09ICJMaWdhbmQtUmVjZXB0b3IiCiAgICAgICAgI2RpcmVjdGlvbmFsaXR5ICVpbiUgYygiTGlnYW5kLVJlY2VwdG9yIiwiUmVjZXB0b3ItUmVjZXB0b3IiLCJMaWdhbmQtTGlnYW5kIikKICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKHByb3RlaW5fbmFtZV9iX3N0cmlwID0gZ3N1YigiX0hVTUFOIiwiIixwcm90ZWluX25hbWVfYiksCiAgICAgICAgIHByb3RlaW5fbmFtZV9hID0gZ3N1YigiX0hVTUFOIiwiIixwcm90ZWluX25hbWVfYSkpICU+JSAKICBtdXRhdGUocHJvdGVpbl9uYW1lX2JfY29tcGxleCA9IGNhc2Vfd2hlbihpcy5uYShwcm90ZWluX25hbWVfYikgfiBzdHJfcmVtb3ZlKGludGVyYWN0b3JzLHBhc3RlMChwcm90ZWluX25hbWVfYSwiLSIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBwcm90ZWluX25hbWVfYikpICU+JQogICBzZXBhcmF0ZV9sb25nZXJfZGVsaW0ocHJvdGVpbl9uYW1lX2JfY29tcGxleCwgZGVsaW0gPSAiKyIpICU+JSAKICAgbGVmdF9qb2luKGhwYV8yNC4wICU+JSB0cmFuc211dGUocHJvdGVpbl9uYW1lX2JfY29tcGxleCA9IGdlbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pcHJvdF9iX2NvbXBsZXggPSB1bmlwcm90KSwgYnk9YygicHJvdGVpbl9uYW1lX2JfY29tcGxleCIpKSAlPiUgCiAgbXV0YXRlKHByb3RlaW5fbmFtZV9iID0gY2FzZV93aGVuKGlzLm5hKHByb3RlaW5fbmFtZV9iKSB+IHByb3RlaW5fbmFtZV9iX2NvbXBsZXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHByb3RlaW5fbmFtZV9iKSwKICAgICAgICAgcGFydG5lcl9iX25ldyA9IGNhc2Vfd2hlbihpcy5uYSh1bmlwcm90X2JfY29tcGxleCkgfiBwYXJ0bmVyX2IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSB1bmlwcm90X2JfY29tcGxleCkpICU+JSAKICB0cmFuc211dGUocGFydG5lcl9hLCBwYXJ0bmVyX2IsIHBhcnRuZXJfYl9uZXcpICU+JSAKICBtdXRhdGUodW5pcHJvdF9hID0gcGFydG5lcl9hLAogICAgICAgICB1bmlwcm90X2IgPSBwYXJ0bmVyX2JfbmV3KSAlPiUgCiAgdHJhbnNtdXRlKHNvdXJjZSA9IHVuaXByb3RfYSwKICAgICAgICAgICAgcmVjaXBpZW50ID0gdW5pcHJvdF9iKSAlPiUgCiAgbGVmdF9qb2luKG5hbWVfdXBfZGljdCAlPiUgZHBseXI6OnJlbmFtZShzb3VyY2VfZ2VuZSA9IGdlbmUpLCBieT1jKCJzb3VyY2UiID0gInVuaXByb3QiKSkgJT4lIAogIGxlZnRfam9pbihuYW1lX3VwX2RpY3QgJT4lIGRwbHlyOjpyZW5hbWUocmVjaXBpZW50X2dlbmUgPSBnZW5lKSwgYnk9YygicmVjaXBpZW50IiA9ICJ1bmlwcm90IikpCmludGVyYWN0aW9uX2RpY3QKYGBgCgpgYGB7cn0KCmNlbGx0eXBlX2wyX2ZyZXEgPC0gdGliYmxlKHBibWNfYWN1dGVAbWV0YS5kYXRhKSAlPiUgCiAgZ3JvdXBfYnkoQ2VsbFR5cGVfTDIpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lCiAgbXV0YXRlKGZyZXEgPSBuIC8gc3VtKG4pLAogICAgICAgICBQZXJjZW50YWdlID0gZnJlcSoxMDApIAoKY2VsbHR5cGVfbDJfb2ZfbDFfZnJlcSA8LSB0aWJibGUocGJtY19hY3V0ZUBtZXRhLmRhdGEpICU+JSAKICBncm91cF9ieShDZWxsVHlwZV9MMSxDZWxsVHlwZV9MMikgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSAlPiUKICBncm91cF9ieShDZWxsVHlwZV9MMSkgJT4lIAogIG11dGF0ZShmcmVxID0gbiAvIHN1bShuKSwKICAgICAgICAgUGVyY2VudGFnZSA9IGZyZXEqMTAwKSAKCmBgYAoKCgpjaXJjb3NwbG90IGZ1bmN0aW9uCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpteV9uaWNlX2NpcmNvc3Bsb3QgPC0gZnVuY3Rpb24oYXNzYXlzMnBsb3RfY2lyY29zLCBzY2FsZV9yYW5nZSwgZXhwcmVzc2lvbl90aHJlc2hvbGQsIHBkZl9maWxlX25hbWUpewogIApwYm1jX2FjdXRlLmF2Zy5sb25nX3RvdXJxdW9pc2UgPC0gcGJtY19hY3V0ZS5hdmcubG9uZyAlPiUgCiAgZmlsdGVyKGNlbGx0eXBlICE9ICJ1bmRlZmluZWQiLAogICAgICAgICBnZW5lICVpbiUgYXNzYXlzMnBsb3RfY2lyY29zLAogICAgICAgICApICU+JSAKICBtdXRhdGUoZ2VuZV9jdCA9IHBhc3RlMChnZW5lLCJfIixjZWxsdHlwZSkpICU+JSAKICBncm91cF9ieShnZW5lKSAlPiUgCiAgbXV0YXRlKGF2Z0V4cCA9IHNjYWxlczo6cmVzY2FsZShhdmdFeHAsIHRvPXNjYWxlX3JhbmdlKSkgJT4lICAjYygwLDEpCiAgdW5ncm91cCgpIAoKbWF0IDwtIHBibWNfYWN1dGUuYXZnLmxvbmdfdG91cnF1b2lzZSAlPiUgCiAgICBmaWx0ZXIoYXZnRXhwID5leHByZXNzaW9uX3RocmVzaG9sZCkgJT4lICMuNQogIGxlZnRfam9pbih0aWJibGUocGJtY0BtZXRhLmRhdGEpICU+JSB0cmFuc211dGUoY2VsbHR5cGVfMSA9IENlbGxUeXBlX0wxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZWxsdHlwZSA9IENlbGxUeXBlX0wyKSAlPiUgZGlzdGluY3QoKSwgYnk9ImNlbGx0eXBlIikgJT4lIAogIG11dGF0ZShjZWxsdHlwZV8xID0gZmFjdG9yKGNlbGx0eXBlXzEsIGxldmVscz0gYygiREMiLCJNb25vY3l0ZXMiLCJOSyIsImdkVCIsIkIiLCJDRDQrIFQiLCJDRDgrIFQiKSksCiAgICAgICAgIGNlbGx0eXBlID0gZmFjdG9yKGNlbGx0eXBlLCBsZXZlbHMgPSBjKCJtREMiLCAicERDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDE0IG1vbm9jeXRlcyIsICJDRDE2IG1vbm9jeXRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOSyBDRDU2ZGltIENEMTYrIiwgIk5LIENENTZkaW0iLCJOSyBDRDU2YnJpZ2h0IiwiTksgcHJvbGlmLiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWZDIrIGdkVCIsICJWZDItIGdkVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCIG5haXZlIiwgIkIgbWVtb3J5IiwgIlBsYXNtYSBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDQgbmFpdmUiLCAiQ0Q0IFRyZWcgQ0Q4MCsiLCAiQ0Q0IFRyZWcgQ0Q4MC0iLCAiQ0Q0IFRmaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDQgZWZmZWN0LiBhY3RpdmF0ZWQiLCAiQ0Q0IGVmZmVjdC4gbWVtb3J5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNENCB0cmFucy4gbWVtb3J5IiwiQ0Q0IGNlbnRyYWwgbWVtb3J5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNEOCBuYWl2ZSIsICJDRDggdHJhbnMuIG1lbW9yeSIsICJDRDggVGZoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5LVCIsICJDRDggZWZmZWN0LiBtZW1vcnkiKSkpICU+JSAKICBhZGRfcm93bmFtZXMoKSAKCgp0bXAgPC0gbWF0ICU+JSBkcGx5cjo6cmVuYW1lKGluZGV4ID0gcm93bmFtZSkgCgpkZl9saW5rIDwtIGludGVyYWN0aW9uX2RpY3QgJT4lIAogIHRyYW5zbXV0ZShzb3VyY2VfZ2VuZSwgcmVjaXBpZW50X2dlbmUpICU+JSAKICBsZWZ0X2pvaW4odG1wICU+JSAKICAgICAgICAgICAgICAgZmlsdGVyKGdlbmUgJWluJSBpbnRlcmFjdGlvbl9kaWN0JHNvdXJjZV9nZW5lKSAlPiUKICAgICAgICAgICAgICAgdHJhbnNtdXRlKGZyb21faW5kZXggPSBpbmRleCwKICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUpLCAKICAgICAgICAgICAgIGJ5PWMoInNvdXJjZV9nZW5lIj0iZ2VuZSIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShmcm9tX2luZGV4KSkgJT4lIAogIGxlZnRfam9pbih0bXAgJT4lIAogICAgICAgICAgICAgICB0cmFuc211dGUodG9faW5kZXggPSBpbmRleCwKICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUpLCAKICAgICAgICAgICAgIGJ5PWMoInJlY2lwaWVudF9nZW5lIj0iZ2VuZSIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYSh0b19pbmRleCkpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICByaWdodF9qb2luKG1hdCAlPiUgdHJhbnNtdXRlKGdlbmUsIGNlbGx0eXBlKSAlPiUgCiAgICAgICAgICAgICAgIGxlZnRfam9pbihkYXRhLmZyYW1lKGNlbGx0eXBlID0gbmFtZXMoTDJfY29sb3JzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZV9jZWxsdHlwZV9jb2xvcnMgPSBMMl9jb2xvcnMpKSwKICAgICAgICAgICAgICBieT1jKCJzb3VyY2VfZ2VuZSI9ImdlbmUiKSkgJT4lIAogIAogIHRyYW5zbXV0ZShmcm9tX2luZGV4ID0gYXMuaW50ZWdlcihmcm9tX2luZGV4KSwKICAgICAgICAgICAgdG9faW5kZXggPSBhcy5pbnRlZ2VyKHRvX2luZGV4KSwKICAgICAgICAgICAgc291cmNlX2NlbGx0eXBlID0gY2VsbHR5cGUsCiAgICAgICAgICAgIHNvdXJjZV9nZW5lLAogICAgICAgICAgICByZWNpcGllbnRfZ2VuZSkgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZGlzdGluY3QoKQoKIyMgZ29hbAojIyBmcm9tX2luZGV4OyB0b19pbmRleCBkYXRhIGZyYW1lCgoKbWF0X2dleCA8LSBtYXQgJT4lIGFycmFuZ2UoY2VsbHR5cGUpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygiZ2VuZV9jdCIpICU+JSAKICBkcGx5cjo6c2VsZWN0KGF2Z0V4cCkKCm1hdF9ucHggPC0gbWF0ICU+JQogIHRyYW5zbXV0ZShnZW5lX2N0LCBnZW5lKSAlPiUgCiAgbGVmdF9qb2luKGRmX2FjdXRlX3BhdGNsdXN0X2luY2xfY29udiAlPiUgCiAgICAgICAgICAgICAgdHJhbnNtdXRlKEFzc2F5LCBOUFgsc2V2ZXJpdHlfbGFiKSAlPiUgCiAgICAgICAgICAgICAgI2ZpbHRlcihBc3NheSAlaW4lIHJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSkgJT4lIAogICAgICAgICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzZXZlcml0eV9sYWIsIHZhbHVlc19mcm9tID0gTlBYLHZhbHVlc19mbiA9IG1lZGlhbikKICAgICAgICAgICAgLCBieT1jKCJnZW5lIj0iQXNzYXkiKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWdlbmUpICU+JSAKICBkaXN0aW5jdCgpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygiZ2VuZV9jdCIpICU+JQogIHJlbG9jYXRlKHNldmVyZSwgbW9kZXJhdGUsIG1pbGQsIGNvbnZhbGVzY2VuY2UpCgoKIyMgbGVnZW5kcwpjb2xfbnB4IDwtIGNvbG9yUmFtcDIoYyhtaW4obWF0X25weCxuYS5ybSA9IFQpLAogICAgICAgICAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgICAgICAgICBtYXgobWF0X25weCxuYS5ybSA9IFQpLzIsCiAgICAgICAgICAgICAgICAgICAgICAgIG1heChtYXRfbnB4LG5hLnJtID0gVCkpLAogICAgICAgICAgICAgICAgICAgICAgYygiI2VkZjhlOSIsIiNiYWU0YjMiLCAiIzc0YzQ3NiIsIiMyMzhiNDUiKSkKCiNtYXRfbnB4IDwtIG1hdF9ucHggJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gc2NhbGVzOjpyZXNjYWxlKC4sIHRvPWMoNCwwKSkpKQpjZWxsX2ZyZXFfY29sb3IgPC0gY29sb3JSYW1wMihjKDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluKGNlbGx0eXBlX2wyX2ZyZXEkUGVyY2VudGFnZSxuYS5ybSA9IFQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4oY2VsbHR5cGVfbDJfZnJlcSRQZXJjZW50YWdlLG5hLnJtPVQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChjZWxsdHlwZV9sMl9mcmVxJFBlcmNlbnRhZ2UsbmEucm0gPSBUKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIiNmMmYwZjciLCIjY2JjOWUyIiwiIzllOWFjOCIsIiM2YTUxYTMiKSkKCmxnZF9ucHggPSBMZWdlbmQodGl0bGUgPSAiTlBYIiwgY29sX2Z1biA9IGNvbF9ucHgsCiAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTYsZm9udGZhY2U9ImJvbGQiKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemU9NikpCgpsZ2RfZ2V4ID0gTGVnZW5kKHRpdGxlID0gIkdFWCIsIGNvbF9mdW4gPSBzY2FsZWRfMDFfY29sLAogICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT02LGZvbnRmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplPTYpKQoKbGdkX2NlbGx0eXBlX2ZyZXEgPSBMZWdlbmQodGl0bGUgPSAiQ2VsbCBmcmVxdWVuY3lcbm9mIENENDUrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX2Z1biA9IGNlbGxfZnJlcV9jb2xvciwKICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9Nixmb250ZmFjZT0iYm9sZCIpLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZT02KSkKCmxnZF9zZXZlcml0eSA9IExlZ2VuZCh0aXRsZSA9ICJTZXZlcml0eSBncm91cCIsIAogICAgICAgICAgICAgICAgICAgICAgYXQgPSBjKCJzZXZlcmUiLCJtb2RlcmF0ZSIsIm1pbGQiLCJjb252YWxlc2NlbmNlIiksCiAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfZ3AgPSBncGFyKGZpbGwgPSBjKCIjY2EwMDIwIiwiI2Y0YTU4MiIsIiM5MmM1ZGUiLCJncmV5NTAiKSksCiAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemU9Nixmb250ZmFjZT0iYm9sZCIpLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZT02KSkKCgpsZ2RfY2VsbHR5cGUgPSBMZWdlbmQodGl0bGUgPSAiQ2VsbHR5cGVzIiwgCiAgICAgICAgICAgICAgICAgICAgICBhdCA9IGMoIkRDIiwiTW9ub2N5dGVzIiwiTksiLCJnZFQiLCJCIiwiQ0Q0KyBUIiwiQ0Q4KyBUIiksCiAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfZ3AgPSBncGFyKGZpbGwgPSBjKCIjY2E1MzY5IiwiIzY4OGJjYyIsIiM4NzYxY2MiLCAiI2FlOTUzZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjYzM2MWFhIiwiIzY4YTc0OCIsIiNjYzY5M2QiKSksCiAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMSwKICAgICAgICAgICAgICAgICAgICAgICNucm93ID0gMSwKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZT02LGZvbnRmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplPTYpKQoKbGdkX2NlbGx0eXBlXzIgPSBMZWdlbmQodGl0bGUgPSAiQ2VsbHR5cGVzIiwgCiAgICAgICAgICAgICAgICAgICAgICBhdCA9IGMoIm1EQyIsInBEQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNEMTQgbW9ub2N5dGVzIiwiQ0QxNiBtb25vY3l0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOSyBDRDU2ZGltIENEMTYrIiwiTksgQ0Q1NmRpbSIsIk5LQ0Q1NmJyaWdodCIsIk5LIHByb2xpZi4iLCJOS1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWZDIrIGdkVCIsIlZkMi0gZ2RUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQiBuYWl2ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkIgbWVtb3J5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGxhc21hIGNlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q0IG5haXZlIiwgIkNENCBUcmVnIENEODArIiwgIkNENCBUcmVnIENEODAtIiwgIkNENCBUZmgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDQgZWZmZWN0LiBhY3RpdmF0ZWQiLCJDRDQgZWZmZWN0LiBtZW1vcnkiLCJDRDQgdHJhbnMubWVtb3J5IiwiQ0QgY2VudHJhbCBtZW1vcnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDggbmFpdmUiLCAiQ0Q4IHRyYW5zLiBtZW1vcnkiLCJDRDhUZmgiLCJDRDggZWZmZWN0LiBtZW1vcnkiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjLChMMl9jb2xvcnMpLAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2dwID0gZ3BhcihmaWxsID0gTDJfY29sb3JzKSwKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgbmNvbD0xLAogICAgICAgICAgICAgICAgICAgICAgI25yb3cgPSA0LAogICAgICAgICAgICAgICAgICAgICAgdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplPTYsZm9udGZhY2U9ImJvbGQiKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemU9NikpCgpjaXJjbGVfc2l6ZSA9IHVuaXQoMSwgInNucGMiKSAjIHNucGMgdW5pdCBnaXZlcyB5b3UgYSBzcXVhcmUgcmVnaW9uCgojIyA9PSBjaXJjb3MuaGVhdG1hcC5nZXQueCBzdGFydCA9PT09CgojIyBBIGZ1bmN0aW9uIHRvIGV4dHJhY3Qgcm93IGluZGljaWVzLCB1c2VmdWwgZm9yIGxhYmVsbGluZwoKIyMgc291cmNlOiBodHRwczovL3JkcnIuaW8vZ2l0aHViL2pva2VyZ29vL2NpcmNsaXplL3NyYy9SL2NpcmNvcy5oZWF0bWFwLlIKIyA9PSB0aXRsZQojIEdldCB0aGUgeC1wb3NpdGlvbiBmb3IgaGVhdG1hcCByb3dzCiMKIyA9PSBwYXJhbQojIC1yb3dfaW5kIEEgdmVjdG9yIG9mIHJvdyBpbmRpY2llcy4KIwojID09IHZhbHVlCiMgQSB0aHJlZS1jb2x1bW4gZGF0YSBmcmFtZSBvZiB0aGUgc2VjdG9yLCB0aGUgeC1wb3NpdGlvbnMgb24gdGhlIGNvcnJlc3BvbmRpbmcgc2VjdG9ycywgYW5kIHRoZSBvcmlnaW5hbCByb3cgaW5kaWNpZXMuCmNpcmNvcy5oZWF0bWFwLmdldC54ID0gZnVuY3Rpb24ocm93X2luZCkgewoJZW52ID0gY2lyY29zLnBhcigiX190ZW1wZW52X18iKQoJc3BsaXQgPSBlbnYkY2lyY29zLmhlYXRtYXAuc3BsaXQKCglyb3dfaW5kX2x0ID0gc3BsaXQocm93X2luZCwgc3BsaXRbcm93X2luZF0pCglyb3dfaW5kX2x0ID0gcm93X2luZF9sdFtzYXBwbHkocm93X2luZF9sdCwgbGVuZ3RoKSA+IDBdCgkKCXggPSBOVUxMCglmb3IoaSBpbiByb3dfaW5kX2x0KSB7CgoJCXN1YnNldCA9IGdldC5jZWxsLm1ldGEuZGF0YSgic3Vic2V0Iiwgc2VjdG9yLmluZGV4ID0gc3BsaXRbaVsxXV0pCgkJb3JkZXIgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInJvd19vcmRlciIsIHNlY3Rvci5pbmRleCA9IHNwbGl0W2lbMV1dKQoJCQoJCXggPSBjKHgsIHdoaWNoKCgxOmxlbmd0aChzcGxpdCkpW3N1YnNldF1bb3JkZXJdICVpbiUgaSkpCgl9CglkZiA9IGRhdGEuZnJhbWUoc2VjdG9yID0gcmVwKG5hbWVzKHJvd19pbmRfbHQpLCB0aW1lcyA9IHNhcHBseShyb3dfaW5kX2x0LCBsZW5ndGgpKSwgCgkJeCA9IHggLSAwLjUsIHJvd19pbmQgPSB1bmxpc3Qocm93X2luZF9sdCkpCglyb3duYW1lcyhkZikgPSBOVUxMCglkZgp9CiMjID09IGNpcmNvcy5oZWF0bWFwLmdldC54IGVuZCA9PT09Cgp0b3RhbF9zZWN0aW9ucyA8LSBsZW5ndGgobGV2ZWxzKG1hdCRjZWxsdHlwZSkpCgoKIyMgdGhlIGZ1bmN0aW9uIHRvIG1ha2UgdGhlIHBsb3QKY2lyY2xpemVfcGxvdCA9IGZ1bmN0aW9uKCkgewogICAgY2lyY29zLmNsZWFyKCkKCiAgY2lyY29zLnBhcihnYXAuYWZ0ZXIgPSBjKHJlcCgyLHRvdGFsX3NlY3Rpb25zLTEpLDEwKSwgCiAgICAgICAgICAgICBwb2ludHMub3ZlcmZsb3cud2FybmluZyA9IFQpCiNjaXJjb3MucGFyKHN0YXJ0LmRlZ3JlZSA9IDkwLCBnYXAuZGVncmVlID0gMTAsZ2FwLmFmdGVyID0gYygzKSkKCiMjIGR1bW15IHRyYWNrLCBpbnZpc2libGUsIG5lZWRlZCBmb3Igc3BsaXQKY2lyY29zLmhlYXRtYXAobWF0X2dleCwKICAgICAgICAgICAgICAgY2x1c3RlciA9IEYsCiAgICAgICAgICAgICAgIHNwbGl0ID0gZHJvcGxldmVscyhtYXQkY2VsbHR5cGUpLAogICAgICAgICAgICAgICBjb2wgPSBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCBjKCJ3aGl0ZSIsICJ3aGl0ZSIsICJ3aGl0ZSIpKSwgCiAgICAgICAgICAgICAgIHRyYWNrLmhlaWdodCA9IDAuMjEsIzAuMDAwMDAwMDAxLAogICAgICAgICAgICAgICApCgojIyBjZWxsdHlwZSBhbm5vdGF0aW9uIHRyYWNrCmNpcmNvcy5oZWF0bWFwKG1hdCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJnZW5lX2N0IikgJT4lIGRwbHlyOjpzZWxlY3QoY2VsbHR5cGUpLCAKICAgICAgICAgICAgICAgY29sID0gTDJfY29sb3JzLCAKICAgICAgICAgICAgICAgdHJhY2suaGVpZ2h0ID0gMC4wOCwKICAgICAgICAgICAgICAgcm93bmFtZXMuc2lkZSA9ICJub25lIiwKICkKCiMjIGNlbGx0eXBlIGZyZXF1ZW5jeSB0cmFjawpjaXJjb3MuaGVhdG1hcChtYXQgJT4lIGNvbHVtbl90b19yb3duYW1lcygiZ2VuZV9jdCIpICU+JSB0cmFuc211dGUoQ2VsbFR5cGVfTDIgPSBjZWxsdHlwZSkgJT4lIGxlZnRfam9pbihjZWxsdHlwZV9sMl9mcmVxLCBieT0iQ2VsbFR5cGVfTDIiKSAlPiUgcHVsbChQZXJjZW50YWdlKSwgY29sID0gY2VsbF9mcmVxX2NvbG9yLCB0cmFjay5oZWlnaHQgPSAwLjAxKQoKIyMgY2VsbHR5cGUgYW5ub3RhdGlvbiB0YWNrIG5hbWluZwpjaXJjb3MudHJhY2tQbG90UmVnaW9uKHRyYWNrLmluZGV4ID0gMSwgcGFuZWwuZnVuID0gZnVuY3Rpb24oeCwgeSkgewogIHhsaW0gPSBnZXQuY2VsbC5tZXRhLmRhdGEoInhsaW0iKQogIHlsaW0gPSBnZXQuY2VsbC5tZXRhLmRhdGEoInlsaW0iKQogIHNlY3Rvci5uYW1lID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJzZWN0b3IuaW5kZXgiKQogIGNpcmNvcy50ZXh0KG1lYW4oeGxpbSksCiAgICAgICAgICAgICAgeWxpbVsxXSArIC4xLCAKICAgICAgICAgICAgICBzZWN0b3IubmFtZSwgCiAgICAgICAgICAgICAgZmFjaW5nID0gImNsb2Nrd2lzZSIsIAogICAgICAgICAgICAgIG5pY2VGYWNpbmcgPSBUUlVFLCBjZXg9LjYsCiAgICAgICAgICAgICAgYWRqID0gYygwLCAwLjUpLCBjb2wgPSAiZ3JleTQwIikKfSwgYmcuYm9yZGVyID0gTkEpCgojIyBjZWxsdHlwZSBnZW5lIGV4cHJlc3Npb24gdHJhY2sKY2lyY29zLmhlYXRtYXAobWF0X2dleCwKICAgICAgICAgICAgICAgY2x1c3RlciA9IEYsIAogICAgICAgICAgICAgICBjb2wgPSBzY2FsZWRfMDFfY29sLCAKICAgICAgICAgICAgICAgdHJhY2suaGVpZ2h0ID0gMC4wNCwKICAgICAgICAgICAgICAgIyByb3duYW1lcy5zaWRlID0gIm91dHNpZGUiLAogICAgICAgICAgICAgICBiZy5ib3JkZXIgPSAiZ3JleTgwIiwgCiAgICAgICAgICAgICAgIGJnLmx3ZCA9IC4xLAogICAgICAgICAgICAgICBiZy5sdHkgPSAuMSwgCiAgICAgICAgICAgICAgIHNob3cuc2VjdG9yLmxhYmVscyA9IEYKKQoKIyMgcGxhc21hIE5QWCB0cmFjCmNpcmNvcy5oZWF0bWFwKG1hdF9ucHgsIGNvbCA9IGNvbF9ucHgsIHRyYWNrLmhlaWdodCA9IDAuMDkpCgojIyBhZGQgYW5ub3RhdGlvbiB0byByb3cgb2YgbnB4IGRhdGEKY2lyY29zLnRyYWNrKHRyYWNrLmluZGV4ID0gZ2V0LmN1cnJlbnQudHJhY2suaW5kZXgoKSwgcGFuZWwuZnVuID0gZnVuY3Rpb24oeCwgeSkgewogICAgaWYoQ0VMTF9NRVRBJHNlY3Rvci5udW1lcmljLmluZGV4ID09IHRvdGFsX3NlY3Rpb25zKSB7ICMgdGhlIGxhc3Qgc2VjdG9yICMyNgogICAgICAjIyBjb252YWwKICAgICAgICBjaXJjb3MucmVjdChDRUxMX01FVEEkY2VsbC54bGltWzJdICsgY29udmVydF94KDEsICJtbSIpLCAwLAogICAgICAgICAgICAgICAgICAgIENFTExfTUVUQSRjZWxsLnhsaW1bMl0gKyBjb252ZXJ0X3goNCwgIm1tIiksIDEsICMxMAogICAgICAgICAgICAgICAgICAgIGNvbCA9ICJncmV5NTAiLCBib3JkZXIgPSBOQSkKICAgICAgIyMgbWlsZCAgCiAgICAgIGNpcmNvcy5yZWN0KENFTExfTUVUQSRjZWxsLnhsaW1bMl0gKyBjb252ZXJ0X3goMSwgIm1tIiksIDEsCiAgICAgICAgICAgICAgICAgICAgQ0VMTF9NRVRBJGNlbGwueGxpbVsyXSArIGNvbnZlcnRfeCg0LCAibW0iKSwgMiwgIzUKICAgICAgICAgICAgICAgICAgICBjb2wgPSAiIzkyYzVkZSIsIGJvcmRlciA9IE5BKQogICAgICAjIyBtb2RlcmF0ZQogICAgICAgIGNpcmNvcy5yZWN0KENFTExfTUVUQSRjZWxsLnhsaW1bMl0gKyBjb252ZXJ0X3goMSwgIm1tIiksIDIsCiAgICAgICAgICAgICAgICAgICAgQ0VMTF9NRVRBJGNlbGwueGxpbVsyXSArIGNvbnZlcnRfeCg0LCAibW0iKSwgMywgIzEwCiAgICAgICAgICAgICAgICAgICAgY29sID0gIiNmNGE1ODIiLCBib3JkZXIgPSBOQSkKICAgICAgICAjIyBzZXZlcmUKICAgICAgICBjaXJjb3MucmVjdChDRUxMX01FVEEkY2VsbC54bGltWzJdICsgY29udmVydF94KDEsICJtbSIpLCAzLAogICAgICAgICAgICAgICAgICAgIENFTExfTUVUQSRjZWxsLnhsaW1bMl0gKyBjb252ZXJ0X3goNCwgIm1tIiksIDQsICMxMAogICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjY2EwMDIwIiwgYm9yZGVyID0gTkEpCiAgICAgICAKICAgIH0KfSwgYmcuYm9yZGVyID0gTkEpCgojIyBBbm5vdGF0ZSBzb3VyY2UgZ2VuZXMKcm93X2luZCA8LSBtYXQgJT4lIGZpbHRlcihnZW5lJWluJWRmX2xpbmskc291cmNlX2dlbmUpICU+JSBtdXRhdGUocm93bmFtZSA9IGFzLmludGVnZXIocm93bmFtZSkpICU+JSBwdWxsKHJvd25hbWUpCnBvc19zbyA9IGNpcmNvcy5oZWF0bWFwLmdldC54KHJvd19pbmQpCnBvc19zbyA8LSBwb3Nfc28gJT4lIHJpZ2h0X2pvaW4obWF0ICU+JSBmaWx0ZXIoZ2VuZSVpbiVkZl9saW5rJHNvdXJjZV9nZW5lKSAlPiUgbXV0YXRlKHJvd19pbmQgPSBhcy5pbnRlZ2VyKHJvd25hbWUpKSwgYnk9InJvd19pbmQiKQoKIyMgQW5ub3RhdGUgcmVjaXBpZW50IGdlbmVzCnJvd19pbmQgPC0gbWF0ICU+JSBmaWx0ZXIoZ2VuZSVpbiVkZl9saW5rJHJlY2lwaWVudF9nZW5lKSAlPiUgbXV0YXRlKHJvd25hbWUgPSBhcy5pbnRlZ2VyKHJvd25hbWUpKSAlPiUgcHVsbChyb3duYW1lKQpwb3NfcmVjID0gY2lyY29zLmhlYXRtYXAuZ2V0Lngocm93X2luZCkKcG9zX3JlYyA8LSBwb3NfcmVjICU+JSByaWdodF9qb2luKG1hdCAlPiUgZmlsdGVyKGdlbmUlaW4lZGZfbGluayRyZWNpcGllbnRfZ2VuZSkgJT4lIG11dGF0ZShyb3dfaW5kID0gYXMuaW50ZWdlcihyb3duYW1lKSksIGJ5PSJyb3dfaW5kIikKCnBvcyA8LSBiaW5kX3Jvd3MocG9zX3NvLCBwb3NfcmVjKQoKIyMgbGFibGUgYWxsIG90aGVyIGdlbmVzCgojIyBBbm5vdGF0ZSBzb3VyY2UgZ2VuZXMKcm93X2luZF9hbGxvdGhlcnMgPC0gbWF0ICU+JSBmaWx0ZXIoIWdlbmUgJWluJSBjKGRmX2xpbmskc291cmNlX2dlbmUsZGZfbGluayRyZWNpcGllbnRfZ2VuZSkpICU+JSBtdXRhdGUocm93bmFtZSA9IGFzLmludGVnZXIocm93bmFtZSkpICU+JSBwdWxsKHJvd25hbWUpCgpwb3NfYWxsb3RoZXJzID0gY2lyY29zLmhlYXRtYXAuZ2V0Lngocm93X2luZF9hbGxvdGhlcnMpICU+JSAKICBsZWZ0X2pvaW4obWF0ICU+JSBtdXRhdGUocm93X2luZCA9IGFzLmludGVnZXIocm93bmFtZSkpLCBieT0icm93X2luZCIpCgojIyBqb2luIGFsbCBsYWJsZSBpbmZvCnBvc19hbGwgPC0gYmluZF9yb3dzKHBvcyAlPiUgbXV0YXRlKGNvbCA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAuNCksCiAgICAgICAgICAgICAgICAgICAgIHBvc19hbGxvdGhlcnMgJT4lIG11dGF0ZShjb2wgPSAiZ3JleSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPS4yKSkKCmNpcmNvcy5sYWJlbHMocG9zX2FsbCRzZWN0b3IsIAogICAgICAgICAgICAgIHBvc19hbGwkeCwKICAgICAgICAgICAgICBjb25uZWN0aW9uX2hlaWdodCA9LjAxLAogICAgICAgICAgICAgIGNleCA9cG9zX2FsbCRzaXplLAogICAgICAgICAgICAgIHNpZGU9Imluc2lkZSIsCiAgICAgICAgICAgICAgY29sID0gcG9zX2FsbCRjb2wsIAogICAgICAgICAgICAgIGxhYmVscyA9IHBvc19hbGwkZ2VuZSkKCiMjIGFkZCBjb25uZWN0aW9ucwpmb3IoaSBpbiBzZXFfbGVuKG5yb3coZGZfbGluaykpKSB7CgoKICAgICAgICBjaXJjb3MuaGVhdG1hcC5saW5rKGRmX2xpbmskZnJvbV9pbmRleFtpXSwKICAgICAgICAgICAgICAgICAgICAgICAgZGZfbGluayR0b19pbmRleFtpXSwKICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gcmFuZF9jb2xvcigxKSwKICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IDEuNSwKICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uYWwgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICBhcnIud2lkdGggPSAuMTI1LAogICAgICAgICAgICAgICAgICAgICAgICBhcnIubGVuZ3RoID0gLjIsCiAgICAgICAgICAgICAgICAgICAgICAgIGFyci5sd2QgPSAuMSwKICAgICAgICAgICAgICAgICAgICAgICBhcnIuY29sID0gImJsYWNrIikKfQoKCiAgY2lyY29zLmNsZWFyKCkKfQoKbGlicmFyeShncmlkQmFzZSkKcGRmKHBhc3RlMChyZXN1bHQudG1wLmRpcixwZGZfZmlsZV9uYW1lLCIucGRmIikpIyxwYXBlciA9ICJhNHIiKQpwbG90Lm5ldygpCgpjaXJjbGVfc2l6ZSA9IHVuaXQoMSwgInNucGMiKSAjIHNucGMgdW5pdCBnaXZlcyB5b3UgYSBzcXVhcmUgcmVnaW9uCgpwdXNoVmlld3BvcnQodmlld3BvcnQoeCA9IDAuNSwgeSA9IDEsIzAuNSwKICAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gY2lyY2xlX3NpemUsIAogICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gY2lyY2xlX3NpemUsCiAgICBqdXN0ID0gIGMoImNlbnRlciIsICJ0b3AiKSkpCnBhcihvbWkgPSBncmlkT01JKCksIG5ldyA9IFRSVUUpCmNpcmNsaXplX3Bsb3QoKQp1cFZpZXdwb3J0KCkKCmRyYXcocGFja0xlZ2VuZChsZ2RfZ2V4LCBsZ2RfbnB4LAogICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhvcml6b250YWwiKSwKICAgICB5ID0gdW5pdCgxLCAibnBjIikgLSBjaXJjbGVfc2l6ZSouMSwgCiAgICAgeCA9IHVuaXQoMS4wNCwibnBjIikgLSBjaXJjbGVfc2l6ZSowLjEsCiAgICAganVzdCA9IGMoImNlbnRlciIsInJpZ2h0IikpCgpkcmF3KHBhY2tMZWdlbmQobGdkX2NlbGx0eXBlX2ZyZXEsCiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpLAogICAgICN5ID0gdW5pdCgxLCAibnBjIikgLSBjaXJjbGVfc2l6ZSouMSwgCiAgICAgeCA9IHVuaXQoMS4wNCwibnBjIikgLSBjaXJjbGVfc2l6ZSowLjEsCiAgICAganVzdCA9IGMoImNlbnRlciIsInJpZ2h0IikpCgoKZHJhdyhwYWNrTGVnZW5kKGxnZF9zZXZlcml0eSwKICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiksCiAgICAgeSA9IHVuaXQoMSwgIm5wYyIpIC0gY2lyY2xlX3NpemUqLjgsIAogICAgIHggPSB1bml0KDEuMCwibnBjIikgLSBjaXJjbGVfc2l6ZSowLjExLAogICAgIGp1c3QgPSBjKCJib3R0b20iLCJsZWZ0IikpCmRldi5vZmYoKQpyZXR1cm4oY2lyY2xpemVfcGxvdCgpKQp9CmBgYAoKYGBge3J9Cm15X25pY2VfY2lyY29zcGxvdChhc3NheXMycGxvdF9jaXJjb3MgPSByZXN0cmljdGVkX21vZHVsZV90dXJxdW9pc2UsCiAgICAgICAgICAgICAgICAgICBzY2FsZV9yYW5nZSA9IGMoMCwxKSwKICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb25fdGhyZXNob2xkID0gMC41LAogICAgICAgICAgICAgICAgICAgcGRmX2ZpbGVfbmFtZSA9ICJJbW11bmVDZWxsX1Byb3RlaW5fQ2lyY29zUGxvdF9zZXZlcml0eW1vZHVsZSIKICAgICAgICAgICAgICAgICAgICkKYGBgCgojIyBGaWd1cmUgN0UKYGBge3J9Cm15X2NvbXBhcmlzb25zX3NldmVyZV9jb252IDwtIGxpc3QoYygic2V2ZXJlIiwgIm1vZGVyYXRlIiksIGMoIm1vZGVyYXRlIiwgIm1pbGQiKSwgYygic2V2ZXJlIiwgIm1pbGQiKSxjKCJtaWxkIiwiY29udmFsZXNjZW5jZSIpKQoKc2VsZWN0aW9uIDwtIGMoIkxHQUxTOSIsIklMNCIsIkNEMjc0IiwiQ0Q3MCIpCgooc2V2ZXJpdHlfbGlnYW5kX25weCA8LSBkZl9hY3V0ZV9wYXRjbHVzdF9pbmNsX2NvbnYgJT4lIAoKICAgIGRwbHlyOjpmaWx0ZXIoQXNzYXkgJWluJSBjKHNlbGVjdGlvbikpICU+JSAKICAgIG11dGF0ZShBc3NheSA9IGZhY3RvcihBc3NheSwgbGV2ZWxzID0gYyhzZWxlY3Rpb24pKSkgJT4lIAogICAgZ2dwbG90KGFlcyh4PXNldmVyaXR5X2xhYiwgeT1OUFgsIGNvbG9yPXNldmVyaXR5X2xhYiwgZmlsbD1zZXZlcml0eV9sYWIpKSArIAogICAgZ2VvbV92aW9saW4odHJpbSA9IEYsYWxwaGE9LjkpICsKICAgIGdlb21faml0dGVyKHNpemU9MC4yNSxzaG93LmxlZ2VuZCA9IEYsIHdpZHRoID0gMC4wNSwgYWxwaGE9MSwgY29sb3I9ImdyZXkyMCIpICsKICAgIGdlb21fYm94cGxvdChhbHBoYT0uNyx3aWR0aD0wLjI1LG91dGxpZXIuc2hhcGUgPSBOQSxjb2xvcj0iYmxhY2siLCBmYXR0ZW4gPSAyLGx3ZD0uMjUsc2hvdy5sZWdlbmQgPSBGKSArCiAgICBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0IiwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbC5zZXAgPSAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBULAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gInAuc2lnbmlmIiAsCiAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgICBzaXplPTIsCiAgICAgICAgICAgICAgICAgICAgICAgbHdkID0gLjIsCiAgICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvbnMgPW15X2NvbXBhcmlzb25zX3NldmVyZV9jb252LAogICAgICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKwogICAgZmFjZXRfd3JhcCh+QXNzYXksbnJvdyA9IDIsc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh4PSIiLAogICAgICAgICBjb2xvcj1OVUxMLAogICAgICAgICBmaWxsPU5VTEwpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IHBhdGllbnRfa2NsdXN0M19sYWJfY29udikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBwYXRpZW50X2tjbHVzdDNfbGFiX2NvbnYpKQpgYGAKCiMjIEZpZ3VyZSA3RgoKYGBge3J9CiNGQUNzX2RhdGEgJT4lIGRpc3RpbmN0KGZlYXR1cmUpCgpjZWxsc3Vic2V0Lm9yZGVyIDwtIEZBQ3NfZGF0YSAlPiUgCiAgZmlsdGVyKGZlYXR1cmUlaW4lYygiQ0Q0K0NEMzgrSExBRFIrIFQgY2VsbHMiLCJDRDgrQ0QzOCtITEFEUisgVCBjZWxscyIpLAojICAgIGdyZXBsKCJUcmVnIixmZWF0dXJlKQogICAgKSAlPiUgZGlzdGluY3QoZmVhdHVyZSkgJT4lIHB1bGwoKQoKdGVzdF9jb3JyZWxhdGlvbl9pbnB1dCA8LSBGQUNzX2RhdGEgJT4lIAogIGZpbHRlcihUaW1lPT0iQWN1dGUiLAogICAgICAgICBmZWF0dXJlJWluJQogICAgICAgICAgIGMoCiAgICAgICAgICAgIkNENCtDRDM4K0hMQURSKyBUIGNlbGxzIiwKICAgICAgICAgICAiQ0Q4K0NEMzgrSExBRFIrIFQgY2VsbHMiCiAgICAgICAgICkKICApICU+JSAKICB0cmFuc211dGUoc2FtcGxlX2lkID0gc2FtcGxlSUQsCiAgICAgICAgICAgIHR5cGVfZmVhdHVyZSA9IHBhc3RlMCgiRkFDU18iLGZlYXR1cmUpLAogICAgICAgICAgICB2YWx1ZSkgJT4lIAogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gdmFsdWUsIG5hbWVzX2Zyb20gPSB0eXBlX2ZlYXR1cmUpICU+JSAKICBpbm5lcl9qb2luKAogICAgIyMgUGxhc21hIHByb3RlaW4gZGF0YSBmcm9tIHRoaXMgcGFwZXIKICAgIGRhdGEubG9uZyAlPiUgCiAgICAgIGlubmVyX2pvaW4oc2FtcGxlVGFibGVfc2ltcGxlKSAlPiUgCiAgICAgIGZpbHRlcihBc3NheSAlaW4lIHJlc3RyaWN0ZWRfbW9kdWxlX3R1cnF1b2lzZSkgJT4lIAogICAgICB0cmFuc211dGUoCiAgICAgICAgc2FtcGxlX2lkLAogICAgICAgIHR5cGVfYXNzYXkgPSBwYXN0ZTAoIlBFQV8iLEFzc2F5KSwKICAgICAgICBOUFgpICU+JSAKICAgICAgcGl2b3Rfd2lkZXIodmFsdWVzX2Zyb20gPSBOUFgsIG5hbWVzX2Zyb20gPSB0eXBlX2Fzc2F5KSwKICAgIGJ5PSJzYW1wbGVfaWQiKQpgYGAKCgpgYGB7ciB9CnRlc3RfY29ycmVsYXRpb25fcmVzIDwtIHRlc3RfY29ycmVsYXRpb25faW5wdXQgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlX2lkIikgJT4lIAogIGNvcnJlbGF0aW9uKHBfYWRqdXN0ID0gImZkciIsbWV0aG9kID0gInNwZWFybWFuIixyZWR1bmRhbnQgPSBGKSAlPiUgCiAgdGliYmxlKCkKYGBgCgoKYGBge3J9CmNvci5nIDwtIHRlc3RfY29ycmVsYXRpb25fcmVzICU+JSAKICBmaWx0ZXIoUGFyYW1ldGVyMSE9UGFyYW1ldGVyMikgJT4lIAogIGZpbHRlcigKICAgICFncmVwbCgiUEVBIixQYXJhbWV0ZXIxKSwKICAgICFncmVwbCgiRkFDUyIsUGFyYW1ldGVyMikKICApICU+JSAKICAgYXJyYW5nZSgtYWJzKHJobykpICU+JSAKICBmaWx0ZXIocDw9MC4wNSkgJT4lIAogICAgIHRyYW5zbXV0ZShmcm9tID0gUGFyYW1ldGVyMSwjID0gc3RyX3JlbW92ZShQYXJhbWV0ZXIxLCAiRkFDU18iKSwKICAgICAgICAgICAgdG8gPSBQYXJhbWV0ZXIyLCMgPSBzdHJfcmVtb3ZlKFBhcmFtZXRlcjIsICJQRUFfIiksCiAgICAgICAgICAgIHJobywKICAgICAgICAgICAgcAogICAgICAgICAgICApICU+JSAKICBhc190YmxfZ3JhcGgoZGlyZWN0ZWQgPSBGKQoKbm9kZV90YWJsZSA8LSBhc190aWJibGUoY29yLmcpICU+JSAKICBzZXBhcmF0ZShuYW1lLCBpbnRvPWMoIm9taWNzIiwiZmVhdHVyZSIpLHNlcCA9ICJfIixyZW1vdmUgPSBGKSAKYGBgCgoKYGBge3J9Cihwcm90ZWluX2NlbGxudW1fY29ybmV0IDwtIGNvci5nICU+JSAKICBpbm5lcl9qb2luKG5vZGVfdGFibGUsYnk9Im5hbWUiKSAlPiUgCiAgICBhY3RpdmF0ZShub2RlcykgJT4lICAjIFNldHMgY29udGV4dCB0byBub2RlcyAtPiBzdWJzZXF1ZW50IG9wZXJhdGlvbnMgYXJlIHBlcmZvcm1lZCBvbiBub2RlcwogIG11dGF0ZShkZWcgPSBjZW50cmFsaXR5X2RlZ3JlZSgpKSAlPiUgCiAgZmlsdGVyKCFub2RlX2lzX2lzb2xhdGVkKCkpICU+JSAgIyBSZW1vdmVzIG5vZGVzIHRoYXQgYXJlIGlzb2xhdGVkL2RvIG5vdCBoYXZlIGFueSBmb2xsb3dlciBlZGdlcwojIGNyZWF0ZV9sYXlvdXQobGF5b3V0ID0gImlncmFwaCIsIGFsZ29yaXRobSA9ICJmciIpICU+JSAKICBjcmVhdGVfbGF5b3V0KGxheW91dCA9ICJzdHJlc3MiKSAlPiUgICNmcgogIGdncmFwaCgpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyhjb2xvciA9IHJobyksCiAgICAgICAgICAgICAgICAgICAjICAgIGFscGhhID0gMC45CiAgICAgICAgICAgICAgICAgICApICsgIAogIHNjYWxlX2VkZ2VfY29sb3JfY29udGludW91cyhsb3c9InRoaXN0bGUyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaD0iZGFya3JlZCIpICsKICBnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG9yID0gb21pY3MsCiAgICAgICAgICAgICAgICAgICAgICBzaXplPSBpZmVsc2Uob21pY3M9PSJGQUNTIiwzLDEpKSwKICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gZmVhdHVyZSwKICAgICAgICAgICAgICAgICAgICAgYWxwaGE9IGlmZWxzZShkZWc+MSwxLC41KQogICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsCiAgICAgICAgICAgICAgICAgc2l6ZT0xLjUsCiAgICAgICAgICAgICAgICAgcmVwZWwgPSBULHNob3cubGVnZW5kID0gRgogICAgICAgICAgICAgICAgICAgICApICsKICBzY2FsZV9hbHBoYV9jb250aW51b3VzKHJhbmdlID0gYygwLjUsIDEpKSArCiAgdGhlbWVfdm9pZCgpICsKICAgIGd1aWRlcyhjb2xvcj0gZ3VpZGVfY29sb3JiYXIoYmFyaGVpZ2h0ID0gMSwgYmFyd2lkdGggPSAuMSkpICsKCiAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KCBzaXplPTYpLAogICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSkgCgopCgpgYGAKCgojIFNlc3Npb24gSW5mbwoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgoKIyBGaWd1cmUgUGFuZWxzCmluY2x1ZGVzIGFsc28gc2F2aW5nIGRhdGEgZm9yIHN1cHBsZW1lbnRhcnkKYGBge3IgZXZhbD1GQUxTRX0KI2V2YWw9RkFMU0UKc291cmNlX3JtZCA8LSBmdW5jdGlvbihybWRfZmlsZSl7CiAga25pdHI6OmtuaXQocm1kX2ZpbGUsIG91dHB1dCA9IHRlbXBmaWxlKCkpCn0KCnNvdXJjZV9ybWQoIk1ha2VfbXlfZmlndXJlcGFuZWxzLlJtZCIpCgojIyBtYWtlIG9uZSBQZGYKbGlicmFyeShxcGRmKQpxcGRmOjpwZGZfY29tYmluZSgKICBpbnB1dCA9IGMoIi4uL01hbnVzY3JpcHQvRmlndXJlXzEucGRmIiwgCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV8yLnBkZiIsCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV8zLnBkZiIsIAogICAgICAgICAgICAiLi4vTWFudXNjcmlwdC9GaWd1cmVfNC5wZGYiLCAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzUucGRmIiwgCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV82LnBkZiIsCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV83LnBkZiIpLAogIG91dHB1dCA9ICIuLi9NYW51c2NyaXB0L0xhdXRlbmJhY2hfZXRhbF9tYWluZmlndXJlcy5wZGYiCikKCnFwZGY6OnBkZl9jb21iaW5lKAogIGlucHV0ID0gYygiLi4vTWFudXNjcmlwdC9GaWd1cmVfMV9TMS5wZGYiLCAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzFfUzIucGRmIiwgCiAgICAgICAgICAgICIuLi9NYW51c2NyaXB0L0ZpZ3VyZV8xX1MzLnBkZiIsIAogICAgICAgICAgICAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzJfUzQucGRmIiwKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzJfUzUucGRmIiwgCiAgICAgICAgICAgIAogICAgICAgICAgICAiLi4vTWFudXNjcmlwdC9GaWd1cmVfM19TNi5wZGYiLCAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzNfUzcucGRmIiwgCiAgICAgICAgICAgIAogICAgICAgICAgICAiLi4vTWFudXNjcmlwdC9GaWd1cmVfNF9TOC5wZGYiLAogICAgICAgICAgICAKICAgICAgICAgICAgIi4uL01hbnVzY3JpcHQvRmlndXJlXzVfUzkucGRmIgogICAgICAgICAgICApLAogIG91dHB1dCA9ICIuLi9NYW51c2NyaXB0L0xhdXRlbmJhY2hfZXRhbF9zdXBwbGVtZW50YXJ5ZmlndXJlcy5wZGYiCikKYGBgCgoK