Setup

library(ithi.utils)
load_base_libs()

library(methods)
library(grid)
library(gridExtra)
library(gridBase)

library(ithi.meta)
library(ithi.figures)
library(ithi.utils)
library(ithi.seq)
library(ithi.clones)
library(ithi.supp)
library(ithi.xcr)
ihc_table_path <- snakemake@input$ihc_table
xcr_table_path <- snakemake@input$xcr_table
tcr_diversity_file <- snakemake@input$tcr_diversity
bcr_diversity_file <- snakemake@input$bcr_diversity
nanostring_data_path <- snakemake@input$nanostring_data
nanostring_annotations_path <- snakemake@input$nanostring_annotations

db_path <- snakemake@params$db
annotation_colours <- ithi.figures::get_annotation_colours()

ihc_table <- fread(ihc_table_path)
xcr_table <- read_clonotypes(xcr_table_path, duplicates = FALSE, db_path = db_path)

Read 3.3% of 304822 rows
Read 36.1% of 304822 rows
Read 72.2% of 304822 rows
Read 304822 rows and 18 (of 18) columns from 0.070 GB file in 00:00:06
xcr_diversity <- ithi.supp::get_xcr_diversity(tcr_diversity_file, bcr_diversity_file, 
    db_path, xcr_table)

exprs <- fread(nanostring_data_path)
nanostring_labels <- fread(nanostring_annotations_path)

pathway_matrix <- ithi.expr::create_pathway_matrix(exprs, nanostring_labels, 
    db_path, convert_ids = TRUE, summary_method = "arithmetic_mean")
pathway_df <- pathway_matrix %>% t %>% as.data.frame %>% rownames_to_column(var = "condensed_id")
pathway_df$patient_id <- ithi.meta::map_id(pathway_df$condensed_id, from = "condensed_id", 
    to = "patient_id", db_path)

Analysis

The first point is expected. We commented on this in the manuscript – saying that patients with higher mean CD8+ TIL density also had higher TCR repertoire similarity.

The example given emphasized the wrong point – the point I wanted to highlight was that uniformity in TIL densities/T-cell associated gene expression does not imply uniformity in clonotype composition, highlighting the need to go beyond TIL densities when considering the possible utility of these TIL in clinical applications like adoptive cell therapy. If you’re treating a clonally heterogeneous disease, you better grab the TIL needed for all the clones – especially given our finding that TCR clones appear to track with tumour clones across space. The lesson would be to not be fooled by uniformity in TIL densities across sites – what appears to be uniformity in TIL response on IHC DOES NOT mean you can take TIL from only one site when doing adoptive cell therapy.

That being said, our analysis showing that higher TIL infiltrate => lower TCR variation implies that, for patients with high TIL densities, that last statement isn’t relevant, if patients with high TIL densities are the most promising candidates for this type of therapy.

There aren’t really any striking examples of patients with high TIL density, low TIL density variation, and low TCR similarity. So perhaps this line of analysis isn’t really that important, and should be kept to a side note, as it was presented in the paper, or entirely removed.

What do you guys think?

xcr_table$patient_id <- ithi.meta::factor_id(xcr_table$patient_id %>% as.character, 
    type = "patient_id", db_path)
# xcr_gt2_patients <- xcr_table %>% group_by(patient_id) %>%
# summarise(nsamples=length(unique(condensed_id))) %>% subset(nsamples > 2)

intersect_patients <- Reduce(intersect, list(xcr_table$patient_id, ihc_table$patient_id, 
    pathway_df$patient_id))
xcr_table_intersect <- subset(xcr_table, patient_id %in% intersect_patients)
xcr_table_intersect$patient_id <- factor(xcr_table_intersect$patient_id, levels = intersect(levels(xcr_table_intersect$patient_id), 
    intersect_patients))
ihc_table_intersect <- subset(ihc_table, patient_id %in% intersect_patients)
pathway_df_intersect <- subset(pathway_df, patient_id %in% intersect_patients)

tcr_objects <- plot_xcr_variability_patient(xcr_table_intersect, segment_type = "TRB", 
    filter_tissue = FALSE, id_type = "condensed_id", distance_method = "horn", 
    db_path, force_font = FALSE, resample = TRUE, include_diversity = FALSE, 
    tcr_diversity, bcr_diversity, margins = "minimal", xlabel = "", reorder_values = TRUE)
tcr_var_plot <- tcr_objects$p
tcr_patient_order <- tcr_objects$order

bcr_objects <- plot_xcr_variability_patient(xcr_table_intersect, segment_type = "IGH", 
    filter_tissue = FALSE, id_type = "condensed_id", distance_method = "horn", 
    db_path, force_font = FALSE, resample = TRUE, include_diversity = FALSE, 
    tcr_diversity, bcr_diversity, margins = "minimal", xlabel = "", reorder_values = TRUE)
bcr_var_plot <- bcr_objects$p
bcr_patient_order <- bcr_objects$order


T_cell_features <- c("T_CD8_density", "T_CD4_density", "T-Cell Functions")
B_cell_features <- c("T_CD20_density", "T_Plasma_density", "B-Cell Functions")
id_vars <- c("condensed_id", "patient_id")
T_cell_ihc_features <- intersect(T_cell_features, colnames(ihc_table_intersect))
B_cell_ihc_features <- intersect(B_cell_features, colnames(ihc_table_intersect))
T_cell_expr_features <- intersect(T_cell_features, colnames(pathway_df_intersect))
B_cell_expr_features <- intersect(B_cell_features, colnames(pathway_df_intersect))

ihc_table_intersect_melted <- reshape2::melt(ihc_table_intersect, id.vars = id_vars, 
    measure.vars = c(T_cell_ihc_features, B_cell_ihc_features), variable.name = "tiltype", 
    value.name = "density")
pathway_df_intersect_melted <- reshape2::melt(pathway_df_intersect, id.vars = id_vars, 
    measure.vars = c(T_cell_expr_features, B_cell_expr_features), variable.name = "pathway", 
    value.name = "expression")
pathway_df_intersect_melted$patient_id <- ithi.meta::factor_id(pathway_df_intersect_melted$patient_id, 
    type = "patient_id", db_path)

features_list <- list(T_cell_features, B_cell_features)
names(features_list) <- c("T_cell", "B_cell")

plot_boxes <- function(dat, yvar, ylabel, xlabel = "", log_y = FALSE, order = NULL, 
    center = FALSE) {
    if (!is.null(order)) {
        dat$patient_id <- factor(dat$patient_id, levels = as.character(order))
    }
    if (center) {
        dat <- dat %>% dplyr::group_by(patient_id) %>% mutate_(.dots = setNames(list(lazyeval::interp(quote(x_val - 
            mean(x_val, na.rm = TRUE)), x_val = as.name(yvar))), yvar))
    }
    
    p <- ggplot(dat, aes_string(x = "patient_id", y = yvar)) + stat_boxplot(geom = "errorbar", 
        width = 0.3) + geom_boxplot(aes(fill = patient_id)) + theme_bw() + theme_Publication() + 
        theme_nature() + ylab(ylabel) + guides(fill = FALSE) + xlab(xlabel) + 
        ithi.utils::ggmargins(type = "minimal") + scale_fill_manual(values = annotation_colours$patient_id)
    if (log_y) {
        p <- p + scale_y_continuous(breaks = ithi.utils::log_scale_breaks(), 
            labels = ithi.utils::log_scale_labels())
    }
    return(p)
}

order_boxplots <- FALSE
log_y <- TRUE
center <- FALSE

produce_variation_boxplots <- function(features, ihc_table_intersect_melted, 
    pathway_df_intersect_melted, patient_order = NULL) {
    ihc_feats <- intersect(features, ihc_table_intersect_melted$tiltype)
    
    ihc_plots <- lapply(ihc_feats, function(x) {
        dat <- subset(ihc_table_intersect_melted, tiltype == x)
        p <- plot_boxes(dat, yvar = "density", ylabel = x, xlabel = "", log_y = log_y, 
            order = patient_order, center = center)
        return(p)
    })
    names(ihc_plots) <- ihc_feats
    
    expr_feats <- intersect(features, pathway_df_intersect_melted$pathway)
    expr_plots <- lapply(expr_feats, function(x) {
        dat <- subset(pathway_df_intersect_melted, pathway == x)
        p <- plot_boxes(dat, yvar = "expression", ylabel = x, xlabel = "Patient", 
            order = patient_order, center = center)
        return(p)
    })
    names(expr_plots) <- expr_feats
    
    return(c(ihc_plots, expr_plots))
}
tcr_variation_boxplots <- produce_variation_boxplots(features = T_cell_features, 
    ihc_table_intersect_melted = ihc_table_intersect_melted, pathway_df_intersect_melted = pathway_df_intersect_melted, 
    patient_order = tcr_patient_order)

bcr_variation_boxplots <- produce_variation_boxplots(features = B_cell_features, 
    ihc_table_intersect_melted = ihc_table_intersect_melted, pathway_df_intersect_melted = pathway_df_intersect_melted, 
    patient_order = bcr_patient_order)


T_cell_components <- list(tcr_var_plot, tcr_variation_boxplots$T_CD8_density, 
    tcr_variation_boxplots$T_CD4_density, tcr_variation_boxplots$`T-Cell Functions`)
B_cell_components <- list(bcr_var_plot, bcr_variation_boxplots$T_CD20_density, 
    bcr_variation_boxplots$T_Plasma_density, bcr_variation_boxplots$`B-Cell Functions`)

T_cell_grobs <- lapply(T_cell_components, ggplotGrob)
B_cell_grobs <- lapply(B_cell_components, ggplotGrob)
T_cell_plot <- do.call(gridExtra::rbind.gtable, T_cell_grobs)
B_cell_plot <- do.call(gridExtra::rbind.gtable, B_cell_grobs)
grid.newpage()
grid.draw(T_cell_plot)

grid.newpage()
grid.draw(B_cell_plot)

What you should be looking to compare is the VALUE of the first boxplot in each 4-tuple with the SPREAD of each of the boxplots in the subsequent 3 boxplots. I realize this is confusing – what would be a better way of showing this?

  1. A key example to note would be, for example, patient 15 – high TCR similarity (low variation) while having high variation in T_CD8_density and T_CD4_density. This suggests that, despite having very similar TCR repertoires across the board, the degree of infiltration can vary substantially from site to site.

  2. Another interesting example would be patient 17 – fairly low variation in CD8 and CD4 densities, with relatively high CD8 and CD4 densities, and fairly variable TCR repertoires (low TCR similarity). This would imply that – even in patients that are uniformly TIL-hot, they can harbor vastly different TCR repertoires from site to site. However, I might be squinting a bit too hard at the plot; I would not say this is a particularly strong example. It’s not surprising that this case is rare, because high CD8 TIL density is associated with high TCR similarity.

Perhaps we can change the presentation of this entire section – we can start off by introducing how TCR/BCR diversity correlate to TIL densities, then show these variation plots (or a better version of them), and start by describing the lack of patients falling in (2) (on the other hand, low TCR similarity with similar TIL densities does exist, but only for TIL-cold patients), and from there talk about how CD8+ TIL density is correlated to TCR similarity. That way this information isn’t redundant, and provides a more comprehensive view of intrapatient variability before going into summary statistics.

CAMILA: Would be great to get your comments/thoughts about this intrapatient variation analysis.

LS0tCnRpdGxlOiAiVmFyaWF0aW9uIGFuYWx5c2lzIgotLS0KICAgICAgICAgICAgICAgICAgICAgICAgYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIyMjIyMjIyBTbmFrZW1ha2UgaGVhZGVyICMjIyMjIyMjCmxpYnJhcnkobWV0aG9kcykKU25ha2VtYWtlIDwtIHNldENsYXNzKAogICAgIlNuYWtlbWFrZSIsCiAgICBzbG90cyA9IGMoCiAgICAgICAgaW5wdXQgPSAibGlzdCIsCiAgICAgICAgb3V0cHV0ID0gImxpc3QiLAogICAgICAgIHBhcmFtcyA9ICJsaXN0IiwKICAgICAgICB3aWxkY2FyZHMgPSAibGlzdCIsCiAgICAgICAgdGhyZWFkcyA9ICJudW1lcmljIiwKICAgICAgICBsb2cgPSAibGlzdCIsCiAgICAgICAgcmVzb3VyY2VzID0gImxpc3QiLAogICAgICAgIGNvbmZpZyA9ICJsaXN0IiwKICAgICAgICBydWxlID0gImNoYXJhY3RlciIKICAgICkKKQpzbmFrZW1ha2UgPC0gU25ha2VtYWtlKAogICAgaW5wdXQgPSBsaXN0KCdub3RlYm9va3MvaW1tdW5lX3ZhcmlhdGlvbi5SbWQnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvaWhjX3RhYmxlLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvcG9zdHByb2Nlc3MvSUdIL3Bvc3RmaWx0ZXJfZGl2ZXJzaXR5X3N0YXRzL2RpdmVyc2l0eS5zdHJpY3QucmVzYW1wbGVkLnR4dCcsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL25hbm9zdHJpbmcvcGFuY2FuY2VyX2Fubm90YXRpb25zLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi94Y3JfdGFibGUudHN2JywgJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL21peGNyL21peGNyX3J1bnMvaXRoXzFfMl8zL21peGNyNS9wb3N0cHJvY2Vzcy9UUkIvcG9zdGZpbHRlcl9kaXZlcnNpdHlfc3RhdHMvZGl2ZXJzaXR5LnN0cmljdC5yZXNhbXBsZWQudHh0JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL25hbm9zdHJpbmdfcmVzdWx0cy9pdGhfZnVsbC9xYy9saW1tYV9xdWFudGlsZS9ub3JtYWxpemVkX2V4cHJlc3Npb25fdm9hX2xhYmVsc19maWx0ZXJlZC50c3YnLCAibm90ZWJvb2siID0gJ25vdGVib29rcy9pbW11bmVfdmFyaWF0aW9uLlJtZCcsICJpaGNfdGFibGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2loY190YWJsZS50c3YnLCAiYmNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL0lHSC9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAibmFub3N0cmluZ19hbm5vdGF0aW9ucyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9uYW5vc3RyaW5nL3BhbmNhbmNlcl9hbm5vdGF0aW9ucy50c3YnLCAieGNyX3RhYmxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi94Y3JfdGFibGUudHN2JywgInRjcl9kaXZlcnNpdHkiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL21peGNyL21peGNyX3J1bnMvaXRoXzFfMl8zL21peGNyNS9wb3N0cHJvY2Vzcy9UUkIvcG9zdGZpbHRlcl9kaXZlcnNpdHlfc3RhdHMvZGl2ZXJzaXR5LnN0cmljdC5yZXNhbXBsZWQudHh0JywgIm5hbm9zdHJpbmdfZGF0YSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbmFub3N0cmluZ19yZXN1bHRzL2l0aF9mdWxsL3FjL2xpbW1hX3F1YW50aWxlL25vcm1hbGl6ZWRfZXhwcmVzc2lvbl92b2FfbGFiZWxzX2ZpbHRlcmVkLnRzdicpLAogICAgb3V0cHV0ID0gbGlzdCgnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvcmV2aWV3L25vdGVib29rcy9ydW4yL2ltbXVuZV92YXJpYXRpb24ubmIuaHRtbCcpLAogICAgcGFyYW1zID0gbGlzdCgnaW1tdW5lX3ZhcmlhdGlvbl9hbmFseXNpcycsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycsICJuYW1lIiA9ICdpbW11bmVfdmFyaWF0aW9uX2FuYWx5c2lzJywgImRiIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycpLAogICAgd2lsZGNhcmRzID0gbGlzdCgpLAogICAgdGhyZWFkcyA9IDEsCiAgICBsb2cgPSBsaXN0KCcvc2hhaGxhYi9hbHpoYW5nL2NsdXN0dG1wL3BhcGVycmV2aWV3Mi9ub3RlYm9va3MvaW1tdW5lX3ZhcmlhdGlvbl9hbmFseXNpcy5sb2cnKSwKICAgIHJlc291cmNlcyA9IGxpc3QoKSwKICAgIGNvbmZpZyA9IGxpc3QoImhlX3Jlc3VsdHNfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvaXRoaS9maW5uX3Jlc3VsdHMvaGVfb3V0cHV0X05vdjI5JywgInByZXZhbGVuY2VfdGhyZXNob2xkIiA9IDAuMDEsICJyb29uZXlfbXV0c2lnY3ZfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2V4dGVybmFsL290aGVyX3BhcGVycy9tbWM2Lnhsc3gnLCAibW9sc3VidHlwZXMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL21vbHN1YnR5cGVzLnRzdicsICJrbm93bl9zdWJ0eXBlc19hcnJheSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9hcnJheS9zdWJ0eXBlcy9rbm93bl9zdWJ0eXBlcy50c3YnLCAic252X2NsdXN0ZXJfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXInLCAidGlsX2NsdXN0ZXJzX291dHB1dCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yL3RpbF9jbHVzdGVyc19vdXRwdXQudHh0JywgIml0aF9pY2djX2JjIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9pdGhfaWNnY19tZXJnZWRfYmMudHN2JywgInRpbGNsdXN0ZXJfc3VwZXJ2aXNlZF9pcHluYiIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jldmlldy9pcHkvdGlsY2x1c3Rlcl9zdXBlcnZpc2VkbXVsdGljbGFzcy5pcHluYicsICJjbG9uZV90cmVlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3RyZWVfZGF0YS50c3YnLCAibW1jdG1fZmluYWxfcGF0aWVudF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LXBhdGllbnRfd2l0aC1vdicsICJjbG9sYV9yZXN1bHRfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvY2xvbGEvcnVuNC9jbG9sYV9jb25kZW5zZWRfcmVzdWx0cy9iZXRhL2Nsb2xhX3Jlc3VsdHMudHN2JywgInNvbWF0aWNfY29kaW5nX3Jlc3VsdF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL3NvbWF0aWNfY29kaW5nX3ZhcmlhbnRzJywgIml0aF9zdGF0cyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvaXRoX3N0YXRpc3RpY3MudHN2JywgInRjcl9kaXZlcnNpdHkiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL21peGNyL21peGNyX3J1bnMvaXRoXzFfMl8zL21peGNyNS9wb3N0cHJvY2Vzcy9UUkIvcG9zdGZpbHRlcl9kaXZlcnNpdHlfc3RhdHMvZGl2ZXJzaXR5LnN0cmljdC5yZXNhbXBsZWQudHh0JywgInRvdGFsX3RpbHR5cGVzIiA9IGMoJ1RfQ0Q4X2RlbnNpdHknLCAnVF9DRDRfZGVuc2l0eScsICdUX0NEMjBfZGVuc2l0eScsICdUX1BsYXNtYV9kZW5zaXR5JyksICJpY2djX3NwZWNpbWVuIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9zcGVjaW1lbi50c3YnLCAiYXJyYXlfZXhwcmVzc2lvbl9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL2FycmF5L2dlbmVfZXhwcnNfcm1hX2JhdGNoX2NvcnJlY3RlZC50eHQnLCAidHVtb3VyX3B1cml0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvdHVtb3VyX3B1cml0eS50c3YnLCAiaW1hZ2Vfc3VtbWFyeTIiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9pdGhpL3l1YW5faGVjcl9pbWFnZV9yZXN1bHRzXzIuY3N2JywgIm5vdGVib29rX2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvcmV2aWV3L25vdGVib29rcy9ydW4yJywgImVwaXRvcGVzX3VuaXF1ZV9maWx0ZXJlZCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvZXBpdG9wZXNfdW5pcXVlX2ZpbHRlcmVkLnRzdicsICJ2YXJpYWJpbGl0eV90eXBlIiA9ICdzdGFiaWxpemUnLCAiZGlzdGFuY2VfbWV0aG9kIiA9ICdob3JuJywgInRpbHNfZm9yX3ZhcmlhYmlsaXR5IiA9IGMoJ1RfQ0Q4X2RlbnNpdHknLCAnVF9DRDRfZGVuc2l0eScsICdUX0NEMjBfZGVuc2l0eScsICdUX1BsYXNtYV9kZW5zaXR5JyksICJiZW5jaG1hcmtkaXIiID0gJy9zaGFobGFiL2FsemhhbmcvYmVuY2htYXJrcy9wYXBlcnJldmlldzInLCAidGlsc19mb3JfY2x1c3RlciIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAiYnJlYWtwb2ludF90YWJsZSIgPSAnL3NoYWhsYWIvYW1jcGhlcnNvbi9wcm9qZWN0cy9pdGgzL2l0aDMvbm90ZWJvb2tzL2Jlc3Bva2UvaXRoX2JyZWFrcG9pbnRzLnRzdicsICJjbG9uZV9wcmV2YWxlbmNlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL2Nsb25lX2RhdGEudHN2JywgImltYWdlX3N1bW1hcnkiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9pdGhpL3l1YW5faGVjcl9pbWFnZV9yZXN1bHRzLmNzdicsICJyZW1peHRfY2VsbHVsYXJpdHlfcGxvaWR5IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9yZW1peHRfY2VsbHVsYXJpdHlfcGxvaWR5LnRzdicsICJsb2dkaXIiID0gJy9zaGFobGFiL2FsemhhbmcvY2x1c3R0bXAvcGFwZXJyZXZpZXcyJywgIml0aF9zdGF0X3R5cGVzIiA9IGMoJ2VudHJvcHknLCAncG9zdHByb2Nlc3NlZF9kaXZlcmdlbmNlJywgJ2NvbWJpbmVkX2l0aF9ub3JtYWxpemVkJywgJ3Byb3BvcnRpb25fc3ViY2xvbmFsJyksICJpaGNfdGFibGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2loY190YWJsZS50c3YnLCAiZmlubmhlX3BpcGVsaW5lX3Jlc3VsdHNfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9maW5uaGUvcnVuMScsICJpaGNfZmVhdHVyZXNfb3V0cHV0IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIvaWhjX2ZlYXR1cmVzX291dHB1dC50eHQnLCAic252X3RhYmxlIiA9ICcvc2hhaGxhYi9hbWNwaGVyc29uL3Byb2plY3RzL2l0aDMvaXRoMy9ub3RlYm9va3MvYmVzcG9rZS9pdGhfc252cy50c3YnLCAiaWdwYXJ0aXRpb25fb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9pZ3BhcnRpdGlvbi9ydW4yMicsICJuYW5vc3RyaW5nX2RhdGEiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL25hbm9zdHJpbmdfcmVzdWx0cy9pdGhfZnVsbC9xYy9saW1tYV9xdWFudGlsZS9ub3JtYWxpemVkX2V4cHJlc3Npb25fdm9hX2xhYmVsc19maWx0ZXJlZC50c3YnLCAiYmNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL0lHSC9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAicmVmc2VxX2dlbmVfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL2dlbm9tZS9oZzE5L3JlZnNlcV9nZW5lcy5iZWQnLCAieGNyX3RhYmxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi94Y3JfdGFibGUudHN2JywgIm5hbm9zdHJpbmdfYW5ub3RhdGlvbnMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vbmFub3N0cmluZy9wYW5jYW5jZXJfYW5ub3RhdGlvbnMudHN2JywgImNsb25lX2JyYW5jaF9sZW5ndGhzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvYnJhbmNoX2RhdGEudHN2JywgImljZ2Nfc3VidHlwZXMiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL2ljZ2NfcHJpbWFyeV90dW1vdXJfc3VidHlwZXMudHN2JywgImNvcHludW1iZXJfdGFibGUiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9pdGhpL21hc3Rlcl9jb3B5bnVtYmVyX2ZpbGUudHN2JywgImRiIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycsICJwYXRpZW50c19mb3JfY2xvbmFsIiA9IGMoMSwgMiwgMywgNCwgNywgOSwgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSwgMTYsIDE3KSwgImFsbF90aWx0eXBlcyIgPSBjKCdUX0NEOF9kZW5zaXR5JywgJ1RfQ0Q0X2RlbnNpdHknLCAnVF9DRDIwX2RlbnNpdHknLCAnVF9QbGFzbWFfZGVuc2l0eScsICdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAidGFibGVfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9yZXZpZXcvdGFibGVzL3J1bjInLCAibmVvZWRpdGluZ19vdXRkaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL25lb2VkaXRpbmcvcnVuNicpLAogICAgcnVsZSA9ICdpbW11bmVfdmFyaWF0aW9uX2FuYWx5c2lzJwopCiMjIyMjIyMjIE9yaWdpbmFsIHNjcmlwdCAjIyMjIyMjIyMKCiAgICAgICAgICAgICAgICAgICAgICAgIGBgYAoKCiMjIFNldHVwCgpgYGB7ciBnbG9iYWxfY2h1bmtfb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB0aWR5PVRSVUUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPVRSVUUpICNjYWNoZT1UUlVFCmBgYAoKYGBge3J9CmxpYnJhcnkoaXRoaS51dGlscykKbG9hZF9iYXNlX2xpYnMoKQoKbGlicmFyeShtZXRob2RzKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdyaWRCYXNlKQoKbGlicmFyeShpdGhpLm1ldGEpCmxpYnJhcnkoaXRoaS5maWd1cmVzKQpsaWJyYXJ5KGl0aGkudXRpbHMpCmxpYnJhcnkoaXRoaS5zZXEpCmxpYnJhcnkoaXRoaS5jbG9uZXMpCmxpYnJhcnkoaXRoaS5zdXBwKQpsaWJyYXJ5KGl0aGkueGNyKQpgYGAKCmBgYHtyfQppaGNfdGFibGVfcGF0aCA8LSBzbmFrZW1ha2VAaW5wdXQkaWhjX3RhYmxlCnhjcl90YWJsZV9wYXRoIDwtIHNuYWtlbWFrZUBpbnB1dCR4Y3JfdGFibGUKdGNyX2RpdmVyc2l0eV9maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCR0Y3JfZGl2ZXJzaXR5CmJjcl9kaXZlcnNpdHlfZmlsZSA8LSBzbmFrZW1ha2VAaW5wdXQkYmNyX2RpdmVyc2l0eQpuYW5vc3RyaW5nX2RhdGFfcGF0aCA8LSBzbmFrZW1ha2VAaW5wdXQkbmFub3N0cmluZ19kYXRhCm5hbm9zdHJpbmdfYW5ub3RhdGlvbnNfcGF0aCA8LSBzbmFrZW1ha2VAaW5wdXQkbmFub3N0cmluZ19hbm5vdGF0aW9ucwoKZGJfcGF0aCA8LSBzbmFrZW1ha2VAcGFyYW1zJGRiCmBgYAoKYGBge3J9CmFubm90YXRpb25fY29sb3VycyA8LSBpdGhpLmZpZ3VyZXM6OmdldF9hbm5vdGF0aW9uX2NvbG91cnMoKQoKaWhjX3RhYmxlIDwtIGZyZWFkKGloY190YWJsZV9wYXRoKQp4Y3JfdGFibGUgPC0gcmVhZF9jbG9ub3R5cGVzKHhjcl90YWJsZV9wYXRoLCBkdXBsaWNhdGVzID0gRkFMU0UsIGRiX3BhdGggPSBkYl9wYXRoKQoKeGNyX2RpdmVyc2l0eSA8LSBpdGhpLnN1cHA6OmdldF94Y3JfZGl2ZXJzaXR5KHRjcl9kaXZlcnNpdHlfZmlsZSwgYmNyX2RpdmVyc2l0eV9maWxlLCBkYl9wYXRoLCB4Y3JfdGFibGUpCgpleHBycyA8LSBmcmVhZChuYW5vc3RyaW5nX2RhdGFfcGF0aCkKbmFub3N0cmluZ19sYWJlbHMgPC0gZnJlYWQobmFub3N0cmluZ19hbm5vdGF0aW9uc19wYXRoKQoKcGF0aHdheV9tYXRyaXggPC0gaXRoaS5leHByOjpjcmVhdGVfcGF0aHdheV9tYXRyaXgoZXhwcnMsIG5hbm9zdHJpbmdfbGFiZWxzLCBkYl9wYXRoLCBjb252ZXJ0X2lkcyA9IFRSVUUsIHN1bW1hcnlfbWV0aG9kID0gImFyaXRobWV0aWNfbWVhbiIpCnBhdGh3YXlfZGYgPC0gcGF0aHdheV9tYXRyaXggJT4lIHQgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiY29uZGVuc2VkX2lkIikKcGF0aHdheV9kZiRwYXRpZW50X2lkIDwtIGl0aGkubWV0YTo6bWFwX2lkKHBhdGh3YXlfZGYkY29uZGVuc2VkX2lkLCBmcm9tID0gImNvbmRlbnNlZF9pZCIsIHRvID0gInBhdGllbnRfaWQiLCBkYl9wYXRoKQpgYGAKCiMjIEFuYWx5c2lzCgpUaGUgZmlyc3QgcG9pbnQgaXMgZXhwZWN0ZWQuIFdlIGNvbW1lbnRlZCBvbiB0aGlzIGluIHRoZSBtYW51c2NyaXB0IC0tIHNheWluZyB0aGF0IHBhdGllbnRzIHdpdGggaGlnaGVyIG1lYW4gQ0Q4KyBUSUwgZGVuc2l0eSBhbHNvIGhhZCBoaWdoZXIgVENSIHJlcGVydG9pcmUgc2ltaWxhcml0eS4gCgpUaGUgZXhhbXBsZSBnaXZlbiBlbXBoYXNpemVkIHRoZSB3cm9uZyBwb2ludCAtLSB0aGUgcG9pbnQgSSB3YW50ZWQgdG8gaGlnaGxpZ2h0IHdhcyB0aGF0IHVuaWZvcm1pdHkgaW4gVElMIGRlbnNpdGllcy9ULWNlbGwgYXNzb2NpYXRlZCBnZW5lIGV4cHJlc3Npb24gZG9lcyBub3QgaW1wbHkgdW5pZm9ybWl0eSBpbiBjbG9ub3R5cGUgY29tcG9zaXRpb24sIGhpZ2hsaWdodGluZyB0aGUgbmVlZCB0byBnbyBiZXlvbmQgVElMIGRlbnNpdGllcyB3aGVuIGNvbnNpZGVyaW5nIHRoZSBwb3NzaWJsZSAgdXRpbGl0eSBvZiB0aGVzZSBUSUwgaW4gY2xpbmljYWwgYXBwbGljYXRpb25zIGxpa2UgYWRvcHRpdmUgY2VsbCB0aGVyYXB5LiBJZiB5b3UncmUgdHJlYXRpbmcgYSBjbG9uYWxseSBoZXRlcm9nZW5lb3VzIGRpc2Vhc2UsIHlvdSBiZXR0ZXIgZ3JhYiB0aGUgVElMIG5lZWRlZCBmb3IgYWxsIHRoZSBjbG9uZXMgLS0gZXNwZWNpYWxseSBnaXZlbiBvdXIgZmluZGluZyB0aGF0IFRDUiBjbG9uZXMgYXBwZWFyIHRvIHRyYWNrIHdpdGggdHVtb3VyIGNsb25lcyBhY3Jvc3Mgc3BhY2UuIFRoZSBsZXNzb24gd291bGQgYmUgdG8gbm90IGJlIGZvb2xlZCBieSB1bmlmb3JtaXR5IGluIFRJTCBkZW5zaXRpZXMgYWNyb3NzIHNpdGVzIC0tIHdoYXQgYXBwZWFycyB0byBiZSB1bmlmb3JtaXR5IGluIFRJTCByZXNwb25zZSBvbiBJSEMgRE9FUyBOT1QgbWVhbiB5b3UgY2FuIHRha2UgIFRJTCBmcm9tIG9ubHkgb25lIHNpdGUgd2hlbiBkb2luZyBhZG9wdGl2ZSBjZWxsIHRoZXJhcHkuIAoKVGhhdCBiZWluZyBzYWlkLCBvdXIgYW5hbHlzaXMgc2hvd2luZyB0aGF0IGhpZ2hlciBUSUwgaW5maWx0cmF0ZSA9PiBsb3dlciBUQ1IgdmFyaWF0aW9uIGltcGxpZXMgdGhhdCwgZm9yIHBhdGllbnRzIHdpdGggaGlnaCBUSUwgZGVuc2l0aWVzLCB0aGF0IGxhc3Qgc3RhdGVtZW50IGlzbid0IHJlbGV2YW50LCBpZiBwYXRpZW50cyB3aXRoIGhpZ2ggVElMIGRlbnNpdGllcyBhcmUgdGhlIG1vc3QgcHJvbWlzaW5nIGNhbmRpZGF0ZXMgZm9yIHRoaXMgdHlwZSBvZiB0aGVyYXB5LiAKClRoZXJlIGFyZW4ndCByZWFsbHkgYW55IHN0cmlraW5nIGV4YW1wbGVzIG9mIHBhdGllbnRzIHdpdGggaGlnaCBUSUwgZGVuc2l0eSwgbG93IFRJTCBkZW5zaXR5IHZhcmlhdGlvbiwgYW5kIGxvdyBUQ1Igc2ltaWxhcml0eS4gKipTbyBwZXJoYXBzIHRoaXMgbGluZSBvZiBhbmFseXNpcyBpc24ndCByZWFsbHkgdGhhdCBpbXBvcnRhbnQsIGFuZCBzaG91bGQgYmUga2VwdCB0byBhIHNpZGUgbm90ZSwgYXMgaXQgd2FzIHByZXNlbnRlZCBpbiB0aGUgcGFwZXIsIG9yIGVudGlyZWx5IHJlbW92ZWQuKioKCldoYXQgZG8geW91IGd1eXMgdGhpbms/CgpgYGB7cn0KeGNyX3RhYmxlJHBhdGllbnRfaWQgPC0gaXRoaS5tZXRhOjpmYWN0b3JfaWQoeGNyX3RhYmxlJHBhdGllbnRfaWQgJT4lIGFzLmNoYXJhY3RlciwgdHlwZSA9ICJwYXRpZW50X2lkIiwgZGJfcGF0aCkKI3hjcl9ndDJfcGF0aWVudHMgPC0geGNyX3RhYmxlICU+JSBncm91cF9ieShwYXRpZW50X2lkKSAlPiUgc3VtbWFyaXNlKG5zYW1wbGVzPWxlbmd0aCh1bmlxdWUoY29uZGVuc2VkX2lkKSkpICU+JSBzdWJzZXQobnNhbXBsZXMgPiAyKQoKaW50ZXJzZWN0X3BhdGllbnRzIDwtIFJlZHVjZShpbnRlcnNlY3QsIGxpc3QoeGNyX3RhYmxlJHBhdGllbnRfaWQsIGloY190YWJsZSRwYXRpZW50X2lkLCBwYXRod2F5X2RmJHBhdGllbnRfaWQpKQp4Y3JfdGFibGVfaW50ZXJzZWN0IDwtIHN1YnNldCh4Y3JfdGFibGUsIHBhdGllbnRfaWQgJWluJSBpbnRlcnNlY3RfcGF0aWVudHMpCnhjcl90YWJsZV9pbnRlcnNlY3QkcGF0aWVudF9pZCA8LSBmYWN0b3IoeGNyX3RhYmxlX2ludGVyc2VjdCRwYXRpZW50X2lkLCBsZXZlbHMgPSBpbnRlcnNlY3QobGV2ZWxzKHhjcl90YWJsZV9pbnRlcnNlY3QkcGF0aWVudF9pZCksIGludGVyc2VjdF9wYXRpZW50cykpCmloY190YWJsZV9pbnRlcnNlY3QgPC0gc3Vic2V0KGloY190YWJsZSwgcGF0aWVudF9pZCAlaW4lIGludGVyc2VjdF9wYXRpZW50cykKcGF0aHdheV9kZl9pbnRlcnNlY3QgPC0gc3Vic2V0KHBhdGh3YXlfZGYsIHBhdGllbnRfaWQgJWluJSBpbnRlcnNlY3RfcGF0aWVudHMpCgp0Y3Jfb2JqZWN0cyA8LSBwbG90X3hjcl92YXJpYWJpbGl0eV9wYXRpZW50KHhjcl90YWJsZV9pbnRlcnNlY3QsIHNlZ21lbnRfdHlwZSA9ICJUUkIiLCBmaWx0ZXJfdGlzc3VlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRfdHlwZSA9ICJjb25kZW5zZWRfaWQiLCBkaXN0YW5jZV9tZXRob2QgPSAiaG9ybiIsIGRiX3BhdGgsIGZvcmNlX2ZvbnQgPSBGQUxTRSwgcmVzYW1wbGUgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVfZGl2ZXJzaXR5ID0gRkFMU0UsIHRjcl9kaXZlcnNpdHksIGJjcl9kaXZlcnNpdHksIG1hcmdpbnMgPSAibWluaW1hbCIsIHhsYWJlbCA9ICIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlb3JkZXJfdmFsdWVzID0gVFJVRSkKdGNyX3Zhcl9wbG90IDwtIHRjcl9vYmplY3RzJHAKdGNyX3BhdGllbnRfb3JkZXIgPC0gdGNyX29iamVjdHMkb3JkZXIKCmJjcl9vYmplY3RzIDwtIHBsb3RfeGNyX3ZhcmlhYmlsaXR5X3BhdGllbnQoeGNyX3RhYmxlX2ludGVyc2VjdCwgc2VnbWVudF90eXBlID0gIklHSCIsIGZpbHRlcl90aXNzdWUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZF90eXBlID0gImNvbmRlbnNlZF9pZCIsIGRpc3RhbmNlX21ldGhvZCA9ICJob3JuIiwgZGJfcGF0aCwgZm9yY2VfZm9udCA9IEZBTFNFLCByZXNhbXBsZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZV9kaXZlcnNpdHkgPSBGQUxTRSwgdGNyX2RpdmVyc2l0eSwgYmNyX2RpdmVyc2l0eSwgbWFyZ2lucyA9ICJtaW5pbWFsIiwgeGxhYmVsID0gIiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVvcmRlcl92YWx1ZXMgPSBUUlVFKQpiY3JfdmFyX3Bsb3QgPC0gYmNyX29iamVjdHMkcApiY3JfcGF0aWVudF9vcmRlciA8LSBiY3Jfb2JqZWN0cyRvcmRlcgoKClRfY2VsbF9mZWF0dXJlcyA8LSBjKCJUX0NEOF9kZW5zaXR5IiwgIlRfQ0Q0X2RlbnNpdHkiLAogICAgICAgICAgICAgICAgICAgICAiVC1DZWxsIEZ1bmN0aW9ucyIpCkJfY2VsbF9mZWF0dXJlcyA8LSBjKCJUX0NEMjBfZGVuc2l0eSIsICJUX1BsYXNtYV9kZW5zaXR5IiwKICAgICAgICAgICAgICAgICAgICAgIkItQ2VsbCBGdW5jdGlvbnMiKQppZF92YXJzIDwtIGMoImNvbmRlbnNlZF9pZCIsICJwYXRpZW50X2lkIikKVF9jZWxsX2loY19mZWF0dXJlcyA8LSBpbnRlcnNlY3QoVF9jZWxsX2ZlYXR1cmVzLCBjb2xuYW1lcyhpaGNfdGFibGVfaW50ZXJzZWN0KSkKQl9jZWxsX2loY19mZWF0dXJlcyA8LSBpbnRlcnNlY3QoQl9jZWxsX2ZlYXR1cmVzLCBjb2xuYW1lcyhpaGNfdGFibGVfaW50ZXJzZWN0KSkKVF9jZWxsX2V4cHJfZmVhdHVyZXMgPC0gaW50ZXJzZWN0KFRfY2VsbF9mZWF0dXJlcywgY29sbmFtZXMocGF0aHdheV9kZl9pbnRlcnNlY3QpKQpCX2NlbGxfZXhwcl9mZWF0dXJlcyA8LSBpbnRlcnNlY3QoQl9jZWxsX2ZlYXR1cmVzLCBjb2xuYW1lcyhwYXRod2F5X2RmX2ludGVyc2VjdCkpCgppaGNfdGFibGVfaW50ZXJzZWN0X21lbHRlZCA8LSByZXNoYXBlMjo6bWVsdChpaGNfdGFibGVfaW50ZXJzZWN0LCBpZC52YXJzID0gaWRfdmFycywgbWVhc3VyZS52YXJzID0gYyhUX2NlbGxfaWhjX2ZlYXR1cmVzLCBCX2NlbGxfaWhjX2ZlYXR1cmVzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAidGlsdHlwZSIsIHZhbHVlLm5hbWUgPSAiZGVuc2l0eSIpCnBhdGh3YXlfZGZfaW50ZXJzZWN0X21lbHRlZCA8LSByZXNoYXBlMjo6bWVsdChwYXRod2F5X2RmX2ludGVyc2VjdCwgaWQudmFycyA9IGlkX3ZhcnMsIG1lYXN1cmUudmFycyA9IGMoVF9jZWxsX2V4cHJfZmVhdHVyZXMsIEJfY2VsbF9leHByX2ZlYXR1cmVzKSwgdmFyaWFibGUubmFtZSA9ICJwYXRod2F5IiwgdmFsdWUubmFtZSA9ICJleHByZXNzaW9uIikKcGF0aHdheV9kZl9pbnRlcnNlY3RfbWVsdGVkJHBhdGllbnRfaWQgPC0gaXRoaS5tZXRhOjpmYWN0b3JfaWQocGF0aHdheV9kZl9pbnRlcnNlY3RfbWVsdGVkJHBhdGllbnRfaWQsIHR5cGUgPSAicGF0aWVudF9pZCIsIGRiX3BhdGgpCgpmZWF0dXJlc19saXN0IDwtIGxpc3QoVF9jZWxsX2ZlYXR1cmVzLCBCX2NlbGxfZmVhdHVyZXMpCm5hbWVzKGZlYXR1cmVzX2xpc3QpIDwtIGMoIlRfY2VsbCIsICJCX2NlbGwiKQoKcGxvdF9ib3hlcyA8LSBmdW5jdGlvbihkYXQsIHl2YXIsIHlsYWJlbCwgeGxhYmVsID0gIiIsIGxvZ195ID0gRkFMU0UsIG9yZGVyID0gTlVMTCwgY2VudGVyID0gRkFMU0UpIHsKICBpZiAoIWlzLm51bGwob3JkZXIpKSB7CiAgICBkYXQkcGF0aWVudF9pZCA8LSBmYWN0b3IoZGF0JHBhdGllbnRfaWQsIGxldmVscyA9IGFzLmNoYXJhY3RlcihvcmRlcikpCiAgfQogIGlmIChjZW50ZXIpIHsKICAgIGRhdCA8LSBkYXQgJT4lIGRwbHlyOjpncm91cF9ieShwYXRpZW50X2lkKSAlPiUgbXV0YXRlXyguZG90cyA9IHNldE5hbWVzKGxpc3QobGF6eWV2YWw6OmludGVycChxdW90ZSh4X3ZhbCAtIG1lYW4oeF92YWwsIG5hLnJtPVRSVUUpKSwgeF92YWwgPSBhcy5uYW1lKHl2YXIpKSksIHl2YXIpKQogIH0KICAKICBwIDwtIGdncGxvdChkYXQsIGFlc19zdHJpbmcoeD0icGF0aWVudF9pZCIsIHkgPSB5dmFyKSkgKyBzdGF0X2JveHBsb3QoZ2VvbSA9ICdlcnJvcmJhcicsIHdpZHRoID0gMC4zKSArIGdlb21fYm94cGxvdChhZXMoZmlsbD1wYXRpZW50X2lkKSkgKyB0aGVtZV9idygpICsgdGhlbWVfUHVibGljYXRpb24oKSArIHRoZW1lX25hdHVyZSgpICsgeWxhYih5bGFiZWwpICsgZ3VpZGVzKGZpbGw9RkFMU0UpICsgeGxhYih4bGFiZWwpICsgaXRoaS51dGlsczo6Z2dtYXJnaW5zKHR5cGUgPSAibWluaW1hbCIpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYW5ub3RhdGlvbl9jb2xvdXJzJHBhdGllbnRfaWQpCiAgaWYgKGxvZ195KSB7CiAgICBwIDwtIHAgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gaXRoaS51dGlsczo6bG9nX3NjYWxlX2JyZWFrcygpLCBsYWJlbHMgPSBpdGhpLnV0aWxzOjpsb2dfc2NhbGVfbGFiZWxzKCkpCiAgfQogIHJldHVybihwKQp9CgpvcmRlcl9ib3hwbG90cyA8LSBGQUxTRQpsb2dfeSA8LSBUUlVFCmNlbnRlciA8LSBGQUxTRQoKcHJvZHVjZV92YXJpYXRpb25fYm94cGxvdHMgPC0gZnVuY3Rpb24oZmVhdHVyZXMsIGloY190YWJsZV9pbnRlcnNlY3RfbWVsdGVkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aHdheV9kZl9pbnRlcnNlY3RfbWVsdGVkLCBwYXRpZW50X29yZGVyID0gTlVMTCkgewogIGloY19mZWF0cyA8LSBpbnRlcnNlY3QoZmVhdHVyZXMsIGloY190YWJsZV9pbnRlcnNlY3RfbWVsdGVkJHRpbHR5cGUpCiAgCiAgaWhjX3Bsb3RzIDwtIGxhcHBseShpaGNfZmVhdHMsIGZ1bmN0aW9uKHgpIHsKICAgIGRhdCA8LSBzdWJzZXQoaWhjX3RhYmxlX2ludGVyc2VjdF9tZWx0ZWQsIHRpbHR5cGUgPT0geCkKICAgIHAgPC0gcGxvdF9ib3hlcyhkYXQsIHl2YXIgPSAiZGVuc2l0eSIsIHlsYWJlbCA9IHgsIHhsYWJlbCA9ICIiLCBsb2dfeSA9IGxvZ195LCBvcmRlciA9IHBhdGllbnRfb3JkZXIsIGNlbnRlciA9IGNlbnRlcikKICAgIHJldHVybihwKQogIH0pCiAgbmFtZXMoaWhjX3Bsb3RzKSA8LSBpaGNfZmVhdHMKICAKICBleHByX2ZlYXRzIDwtIGludGVyc2VjdChmZWF0dXJlcywgcGF0aHdheV9kZl9pbnRlcnNlY3RfbWVsdGVkJHBhdGh3YXkpCiAgZXhwcl9wbG90cyA8LSBsYXBwbHkoZXhwcl9mZWF0cywgZnVuY3Rpb24oeCkgewogICAgZGF0IDwtIHN1YnNldChwYXRod2F5X2RmX2ludGVyc2VjdF9tZWx0ZWQsIHBhdGh3YXkgPT0geCkKICAgIHAgPC0gcGxvdF9ib3hlcyhkYXQsIHl2YXIgPSAiZXhwcmVzc2lvbiIsIHlsYWJlbCA9IHgsIHhsYWJlbCA9ICJQYXRpZW50Iiwgb3JkZXIgPSBwYXRpZW50X29yZGVyLCBjZW50ZXIgPSBjZW50ZXIpCiAgICByZXR1cm4ocCkKICB9KQogIG5hbWVzKGV4cHJfcGxvdHMpIDwtIGV4cHJfZmVhdHMKICAKICByZXR1cm4oYyhpaGNfcGxvdHMsIGV4cHJfcGxvdHMpKQp9CmBgYAoKYGBge3J9CnRjcl92YXJpYXRpb25fYm94cGxvdHMgPC0gcHJvZHVjZV92YXJpYXRpb25fYm94cGxvdHMoZmVhdHVyZXMgPSBUX2NlbGxfZmVhdHVyZXMsIGloY190YWJsZV9pbnRlcnNlY3RfbWVsdGVkID0gaWhjX3RhYmxlX2ludGVyc2VjdF9tZWx0ZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGh3YXlfZGZfaW50ZXJzZWN0X21lbHRlZCA9IHBhdGh3YXlfZGZfaW50ZXJzZWN0X21lbHRlZCwgcGF0aWVudF9vcmRlciA9IHRjcl9wYXRpZW50X29yZGVyKQoKYmNyX3ZhcmlhdGlvbl9ib3hwbG90cyA8LSBwcm9kdWNlX3ZhcmlhdGlvbl9ib3hwbG90cyhmZWF0dXJlcyA9IEJfY2VsbF9mZWF0dXJlcywgaWhjX3RhYmxlX2ludGVyc2VjdF9tZWx0ZWQgPSBpaGNfdGFibGVfaW50ZXJzZWN0X21lbHRlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aHdheV9kZl9pbnRlcnNlY3RfbWVsdGVkID0gcGF0aHdheV9kZl9pbnRlcnNlY3RfbWVsdGVkLCBwYXRpZW50X29yZGVyID0gYmNyX3BhdGllbnRfb3JkZXIpCgoKVF9jZWxsX2NvbXBvbmVudHMgPC0gbGlzdCh0Y3JfdmFyX3Bsb3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGNyX3ZhcmlhdGlvbl9ib3hwbG90cyRUX0NEOF9kZW5zaXR5LAogICAgICAgICAgICAgICAgICAgICAgICAgIHRjcl92YXJpYXRpb25fYm94cGxvdHMkVF9DRDRfZGVuc2l0eSwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Y3JfdmFyaWF0aW9uX2JveHBsb3RzJGBULUNlbGwgRnVuY3Rpb25zYAogICAgICAgICAgICAgICAgICAgICAgICAgICkKQl9jZWxsX2NvbXBvbmVudHMgPC0gbGlzdChiY3JfdmFyX3Bsb3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYmNyX3ZhcmlhdGlvbl9ib3hwbG90cyRUX0NEMjBfZGVuc2l0eSwKICAgICAgICAgICAgICAgICAgICAgICAgICBiY3JfdmFyaWF0aW9uX2JveHBsb3RzJFRfUGxhc21hX2RlbnNpdHksCiAgICAgICAgICAgICAgICAgICAgICAgICAgYmNyX3ZhcmlhdGlvbl9ib3hwbG90cyRgQi1DZWxsIEZ1bmN0aW9uc2AKICAgICAgICAgICAgICAgICAgICAgICAgICApCgpUX2NlbGxfZ3JvYnMgPC0gbGFwcGx5KFRfY2VsbF9jb21wb25lbnRzLCBnZ3Bsb3RHcm9iKQpCX2NlbGxfZ3JvYnMgPC0gbGFwcGx5KEJfY2VsbF9jb21wb25lbnRzLCBnZ3Bsb3RHcm9iKQpgYGAKCmBgYHtyfQpUX2NlbGxfcGxvdCA8LSBkby5jYWxsKGdyaWRFeHRyYTo6cmJpbmQuZ3RhYmxlLCBUX2NlbGxfZ3JvYnMpCkJfY2VsbF9wbG90IDwtIGRvLmNhbGwoZ3JpZEV4dHJhOjpyYmluZC5ndGFibGUsIEJfY2VsbF9ncm9icykKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMH0KZ3JpZC5uZXdwYWdlKCkKZ3JpZC5kcmF3KFRfY2VsbF9wbG90KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTB9CmdyaWQubmV3cGFnZSgpCmdyaWQuZHJhdyhCX2NlbGxfcGxvdCkKYGBgCgpXaGF0IHlvdSBzaG91bGQgYmUgbG9va2luZyB0byBjb21wYXJlIGlzIHRoZSBWQUxVRSBvZiB0aGUgZmlyc3QgYm94cGxvdCBpbiBlYWNoIDQtdHVwbGUgd2l0aCB0aGUgU1BSRUFEIG9mIGVhY2ggb2YgdGhlIGJveHBsb3RzIGluIHRoZSBzdWJzZXF1ZW50IDMgYm94cGxvdHMuIEkgcmVhbGl6ZSB0aGlzIGlzIGNvbmZ1c2luZyAtLSB3aGF0IHdvdWxkIGJlIGEgYmV0dGVyIHdheSBvZiBzaG93aW5nIHRoaXM/IAoKKDEpIEEga2V5IGV4YW1wbGUgdG8gbm90ZSB3b3VsZCBiZSwgZm9yIGV4YW1wbGUsIHBhdGllbnQgMTUgLS0gaGlnaCBUQ1Igc2ltaWxhcml0eSAobG93IHZhcmlhdGlvbikgd2hpbGUgaGF2aW5nIGhpZ2ggdmFyaWF0aW9uIGluIFRfQ0Q4X2RlbnNpdHkgYW5kIFRfQ0Q0X2RlbnNpdHkuIFRoaXMgc3VnZ2VzdHMgdGhhdCwgZGVzcGl0ZSBoYXZpbmcgdmVyeSBzaW1pbGFyIFRDUiByZXBlcnRvaXJlcyBhY3Jvc3MgdGhlIGJvYXJkLCB0aGUgZGVncmVlIG9mIGluZmlsdHJhdGlvbiBjYW4gdmFyeSBzdWJzdGFudGlhbGx5IGZyb20gc2l0ZSB0byBzaXRlLgoKKDIpIEFub3RoZXIgaW50ZXJlc3RpbmcgZXhhbXBsZSB3b3VsZCBiZSBwYXRpZW50IDE3IC0tIGZhaXJseSBsb3cgdmFyaWF0aW9uIGluIENEOCBhbmQgQ0Q0IGRlbnNpdGllcywgd2l0aCByZWxhdGl2ZWx5IGhpZ2ggQ0Q4IGFuZCBDRDQgZGVuc2l0aWVzLCBhbmQgZmFpcmx5IHZhcmlhYmxlIFRDUiByZXBlcnRvaXJlcyAobG93IFRDUiBzaW1pbGFyaXR5KS4gVGhpcyB3b3VsZCBpbXBseSB0aGF0IC0tIGV2ZW4gaW4gcGF0aWVudHMgdGhhdCBhcmUgdW5pZm9ybWx5IFRJTC1ob3QsIHRoZXkgY2FuIGhhcmJvciB2YXN0bHkgZGlmZmVyZW50IFRDUiByZXBlcnRvaXJlcyBmcm9tIHNpdGUgdG8gc2l0ZS4gSG93ZXZlciwgSSBtaWdodCBiZSBzcXVpbnRpbmcgYSBiaXQgdG9vIGhhcmQgYXQgdGhlIHBsb3Q7IEkgd291bGQgbm90IHNheSB0aGlzIGlzIGEgcGFydGljdWxhcmx5IHN0cm9uZyBleGFtcGxlLiBJdCdzIG5vdCBzdXJwcmlzaW5nIHRoYXQgdGhpcyBjYXNlIGlzIHJhcmUsIGJlY2F1c2UgaGlnaCBDRDggVElMIGRlbnNpdHkgaXMgYXNzb2NpYXRlZCB3aXRoIGhpZ2ggVENSIHNpbWlsYXJpdHkuIAoKUGVyaGFwcyB3ZSBjYW4gY2hhbmdlIHRoZSBwcmVzZW50YXRpb24gb2YgdGhpcyBlbnRpcmUgc2VjdGlvbiAtLSB3ZSBjYW4gc3RhcnQgb2ZmIGJ5IGludHJvZHVjaW5nIGhvdyBUQ1IvQkNSIGRpdmVyc2l0eSBjb3JyZWxhdGUgdG8gVElMIGRlbnNpdGllcywgdGhlbiBzaG93IHRoZXNlIHZhcmlhdGlvbiBwbG90cyAob3IgYSBiZXR0ZXIgdmVyc2lvbiBvZiB0aGVtKSwgYW5kIHN0YXJ0IGJ5IGRlc2NyaWJpbmcgdGhlIGxhY2sgb2YgcGF0aWVudHMgZmFsbGluZyBpbiAoMikgKG9uIHRoZSBvdGhlciBoYW5kLCBsb3cgVENSIHNpbWlsYXJpdHkgd2l0aCBzaW1pbGFyIFRJTCBkZW5zaXRpZXMgZG9lcyBleGlzdCwgYnV0IG9ubHkgZm9yIFRJTC1jb2xkIHBhdGllbnRzKSwgYW5kIGZyb20gdGhlcmUgdGFsayBhYm91dCBob3cgQ0Q4KyBUSUwgZGVuc2l0eSBpcyBjb3JyZWxhdGVkIHRvIFRDUiBzaW1pbGFyaXR5LiBUaGF0IHdheSB0aGlzIGluZm9ybWF0aW9uIGlzbid0IHJlZHVuZGFudCwgYW5kIHByb3ZpZGVzIGEgbW9yZSBjb21wcmVoZW5zaXZlIHZpZXcgb2YgaW50cmFwYXRpZW50IHZhcmlhYmlsaXR5IGJlZm9yZSBnb2luZyBpbnRvIHN1bW1hcnkgc3RhdGlzdGljcy4gCgoKKipDQU1JTEEqKjogV291bGQgYmUgZ3JlYXQgdG8gZ2V0IHlvdXIgY29tbWVudHMvdGhvdWdodHMgYWJvdXQgdGhpcyBpbnRyYXBhdGllbnQgdmFyaWF0aW9uIGFuYWx5c2lzLiAK