library(ithi.utils)
load_base_libs()

library(ithi.meta)
library(ithi.xcr)

Colour palettes

pal_patient <- select_palette("patient")

Parameters

db_path <- snakemake@params$db

xcr_table_path <- snakemake@input$xcr_table
prevalence_option <- snakemake@params$prevalence_option
distance_method <- snakemake@params$xcr_distance_method
tcr_diversity_file <- snakemake@input$tcr_diversity
bcr_diversity_file <- snakemake@input$bcr_diversity

Metadata

db <- src_sqlite(db_path, create = FALSE)
samples <- collect(tbl(db, "samples"))
duplicates <- collect(tbl(db, "duplicates"))
xcrseq <- collect(tbl(db, "xcrseq"))

TCR/BCR

xcr_table <- read_clonotypes(xcr_table_path, duplicates = TRUE, db_path)

Read 19.7% of 304822 rows
Read 52.5% of 304822 rows
Read 88.6% of 304822 rows
Read 304822 rows and 18 (of 18) columns from 0.070 GB file in 00:00:05
# xcr_table <- subset(xcr_table, count >= 200)

technical_duplicates <- unique(subset(xcrseq, voa_unique != voa)$voa)

duplicate_sites <- subset(duplicates, duplicate == 1)
duplicate_sites <- merge(samples, duplicate_sites, by = "voa")
duplicate_categories <- subset(duplicate_sites, select = c(patient_id, site_id))

duplicates_mapped <- merge(duplicate_categories, samples, by = c("patient_id", 
    "site_id"))
duplicates_mapped <- merge(duplicates_mapped, xcrseq, by = c("voa"))
mapped_duplicate_categories <- duplicates_mapped %>% group_by(patient_id, site_id) %>% 
    summarise(num_voa = length(unique(voa)))
mapped_categories <- subset(mapped_duplicate_categories, num_voa > 1, select = c("patient_id", 
    "site_id"))

biological_duplicates <- unique(merge(duplicates_mapped, mapped_categories, 
    by = c("patient_id", "site_id"))$voa)
tcr_segment_type <- "TRB"
bcr_segment_type <- "IGH"

id_type <- "voa_unique"

Technical duplicates

xcr_table_tdups <- subset(xcr_table, voa %in% technical_duplicates)
tcr_tdups <- subset(xcr_table_tdups, type == tcr_segment_type)
tcr_cross_table <- cross_tabulate(tcr_tdups, id_type = id_type)

bcr_tdups <- subset(xcr_table_tdups, type == bcr_segment_type)
bcr_cross_table <- cross_tabulate(bcr_tdups, id_type = id_type)

cross_tdups <- list(tcr = tcr_cross_table, bcr = bcr_cross_table)
distance_matrices <- lapply(cross_tdups, function(cross_table) {
    distmat <- compute_immune_distance_matrix(cross_table, method = distance_method)
    mat <- as.matrix(distmat)
    return(mat)
})
sims_raw <- lapply(distance_matrices, function(mat) {
    sims <- average_intrapatient_similarity(mat, filter_tissue = FALSE, id_type = id_type, 
        db_path = db_path, raw = TRUE, group = "voa", table = "xcrseq")
    sims <- setNames(subset(sims, select = -c(tissue1, tissue2, patient2)), 
        c("sample1", "sample2", "dist", "group"))
    sims$patient_id <- map_id(sims$group, from = "voa", to = "patient_id", db_path = db_path, 
        table = "samples")
    sims$condensed_id <- map_id(sims$group, from = "voa", to = "condensed_id", 
        db_path = db_path, table = "samples")
    project1 <- map_id(sims$sample1, from = "voa_unique", to = "project_id", 
        db_path = db_path, table = "xcrseq")
    project2 <- map_id(sims$sample2, from = "voa_unique", to = "project_id", 
        db_path = db_path, table = "xcrseq")
    sims$comparison_type <- c("different", "identical")[as.numeric(project1 == 
        project2) + 1]
    sims_summary <- sims %>% group_by(condensed_id, patient_id, comparison_type) %>% 
        summarise(mean_sim = 1 - mean(dist))
    return(sims_summary)
})
ignore <- lapply(list("tcr", "bcr"), function(segment) {
    dat <- sims_raw[[segment]]
    dat$patient_id <- factor(dat$patient_id)
    dat$comparison_type <- factor(dat$comparison_type)
    
    p <- ggplot(dat, aes(x = patient_id, y = mean_sim)) + geom_boxplot(aes(fill = comparison_type)) + 
        geom_jitter(position = position_jitter(width = 0.2, height = 0)) + scale_fill_manual(values = get_colour_palette(dat$comparison_type)) + 
        theme_bw() + theme_Publication() + xlab("Patient") + ylab("Pairwise repertoire similarity")
    print(p)
})

We might have good reason to suspect that duplicates conducted at different times (i.e. the original TCR/BCR-seq experiment years ago vs. the one now) might not give the same results. The RIN values for the old samples that we re-ran were quite low (3-5, compared to the usual >7). Indeed, the BCR data shows that duplicates from the same run are more similar to each other than those from different runs.

However, one case is alarming – patient 21 in the TCR data. I made an ID mapping error and missed most samples from patient 21 in the first round of processing. However, the refactoring and database construction stimulated by the newest run allowed me to recover these samples. Something fishy definitely seems to be going on here. Subsetting to clonotypes with >= 50, 200 reads did not help, indicating that the issue isn’t likely to be caused by low-level contamination. It may still be caused by high-level contamination – this is worth investigating as patient 21 has a very low total clonotype count.

Next steps: Check RIN values from the original run for patient 21’s samples. Answer: They are on the low side for IX3248 (median = 5.2), but there are several patients around the 5.4-5.7 range. So I’m tempted to say that isn’t the cause of the issue.

TODO: Also evaluate variation in diversity values.

Biological duplicates

Another class of duplicates we tested were parts of samples coming from the same tumour sample. That’s a bit confusing – what it means is that each tumour sample was split into 2 fresh frozen and 1 FFPE aliquot, and for some cases we subjected both fresh frozen aliquots to TCR/BCR-seq. I loosely refer to these cases as ‘biological duplicates’.

id_type <- "voa"

xcr_table_bdups <- subset(xcr_table, voa_unique %in% biological_duplicates)
tcr_bdups <- subset(xcr_table_bdups, type == tcr_segment_type)
tcr_cross_table <- cross_tabulate(tcr_bdups, id_type = id_type)

bcr_bdups <- subset(xcr_table_bdups, type == bcr_segment_type)
bcr_cross_table <- cross_tabulate(bcr_bdups, id_type = id_type)

cross_bdups <- list(tcr = tcr_cross_table, bcr = bcr_cross_table)
distance_matrices <- lapply(cross_bdups, function(cross_table) {
    distmat <- compute_immune_distance_matrix(cross_table, method = distance_method)
    mat <- as.matrix(distmat)
    return(mat)
})
sims_raw <- lapply(distance_matrices, function(mat) {
    sims <- average_intrapatient_similarity(mat, filter_tissue = FALSE, id_type = id_type, 
        db_path = db_path, raw = TRUE, group = "condensed_id", table = "samples")
    sims <- setNames(subset(sims, select = -c(tissue1, tissue2, patient2)), 
        c("sample1", "sample2", "dist", "condensed_id"))
    sims$patient_id <- map_id(sims$condensed_id, from = "condensed_id", to = "patient_id", 
        db_path = db_path, table = "samples")
    project1 <- map_id(sims$sample1, from = "voa_unique", to = "project_id", 
        db_path = db_path, table = "xcrseq")
    project2 <- map_id(sims$sample2, from = "voa_unique", to = "project_id", 
        db_path = db_path, table = "xcrseq")
    sims$comparison_type <- c("different", "identical")[as.numeric(project1 == 
        project2) + 1]
    sims_summary <- sims %>% group_by(condensed_id, patient_id, comparison_type) %>% 
        summarise(mean_sim = 1 - mean(dist))
    return(sims_summary)
})
ignore <- lapply(list("tcr", "bcr"), function(segment) {
    dat <- sims_raw[[segment]]
    dat$patient_id <- factor(dat$patient_id)
    dat$comparison_type <- factor(dat$comparison_type)
    
    p <- ggplot(dat, aes(x = patient_id, y = mean_sim)) + geom_boxplot(aes(fill = comparison_type)) + 
        geom_jitter(position = position_jitter(width = 0.2, height = 0)) + scale_fill_manual(values = get_colour_palette(dat$comparison_type)) + 
        theme_bw() + theme_Publication() + xlab("Patient") + ylab("Pairwise repertoire similarity")
    print(p)
})

A little surprising is how low the repertoire similarity is between biological duplicates – from aliquots that are taken from the same tumour sample! Consistent with our findings that high T-cell abundance = high levels of intrapatient similarity, patient 15 stands out as a beacon of consistency.

LS0tCnRpdGxlOiAiWENSIHJlcGxpY2F0ZSBRQyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogdHJ1ZQpwYXJhbXM6CiAgcm1kOiAicmVwbGljYXRlcy5SbWQiCi0tLQogICAgICAgICAgICAgICAgICAgICAgICBgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMjIyMjIyMjIFNuYWtlbWFrZSBoZWFkZXIgIyMjIyMjIyMKbGlicmFyeShtZXRob2RzKQpTbmFrZW1ha2UgPC0gc2V0Q2xhc3MoCiAgICAiU25ha2VtYWtlIiwKICAgIHNsb3RzID0gYygKICAgICAgICBpbnB1dCA9ICJsaXN0IiwKICAgICAgICBvdXRwdXQgPSAibGlzdCIsCiAgICAgICAgcGFyYW1zID0gImxpc3QiLAogICAgICAgIHdpbGRjYXJkcyA9ICJsaXN0IiwKICAgICAgICB0aHJlYWRzID0gIm51bWVyaWMiLAogICAgICAgIGxvZyA9ICJsaXN0IiwKICAgICAgICByZXNvdXJjZXMgPSAibGlzdCIsCiAgICAgICAgY29uZmlnID0gImxpc3QiLAogICAgICAgIHJ1bGUgPSAiY2hhcmFjdGVyIgogICAgKQopCnNuYWtlbWFrZSA8LSBTbmFrZW1ha2UoCiAgICBpbnB1dCA9IGxpc3QoJ1JtZC9yZXBsaWNhdGVzLlJtZCcsICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvcG9zdHByb2Nlc3MvVFJCL3Bvc3RmaWx0ZXJfZGl2ZXJzaXR5X3N0YXRzL2RpdmVyc2l0eS5zdHJpY3QucmVzYW1wbGVkLnR4dCcsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi94Y3JfdGFibGUudHN2JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9hbmFseXNpcy9SbWQvX3NpdGUueW1sJywgJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL21peGNyL21peGNyX3J1bnMvaXRoXzFfMl8zL21peGNyNS9wb3N0cHJvY2Vzcy9JR0gvcG9zdGZpbHRlcl9kaXZlcnNpdHlfc3RhdHMvZGl2ZXJzaXR5LnN0cmljdC5yZXNhbXBsZWQudHh0JywgIm5vdGVib29rIiA9ICdSbWQvcmVwbGljYXRlcy5SbWQnLCAidGNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL1RSQi9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAiYmNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL0lHSC9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAic2l0ZV9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvYW5hbHlzaXMvUm1kL19zaXRlLnltbCcsICJ4Y3JfdGFibGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL3hjcl90YWJsZS50c3YnKSwKICAgIG91dHB1dCA9IGxpc3QoJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3dlYi94Y3JfcWMubmIuaHRtbCcpLAogICAgcGFyYW1zID0gbGlzdCgnaXRoaS1hbmFseXNpcy14Y3ItcmVwbGljYXRlLXFjJywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9tZXRhZGF0YS9kYi9pbW11bmVfcHJvamVjdC5zcWxpdGUzJywgJ2Nsb25lcycsICdob3JuJywgIm5hbWUiID0gJ2l0aGktYW5hbHlzaXMteGNyLXJlcGxpY2F0ZS1xYycsICJkYiIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL21ldGFkYXRhL2RiL2ltbXVuZV9wcm9qZWN0LnNxbGl0ZTMnLCAicHJldmFsZW5jZV9vcHRpb24iID0gJ2Nsb25lcycsICJ4Y3JfZGlzdGFuY2VfbWV0aG9kIiA9ICdob3JuJyksCiAgICB3aWxkY2FyZHMgPSBsaXN0KCksCiAgICB0aHJlYWRzID0gMSwKICAgIGxvZyA9IGxpc3QoJy9zaGFobGFiL2FsemhhbmcvY2x1c3R0bXAvcGFwZXJhbmFseXNpczIveGNyX3FjLmxvZycpLAogICAgcmVzb3VyY2VzID0gbGlzdCgpLAogICAgY29uZmlnID0gbGlzdCgibW9sc3VidHlwZV90aWx0eXBlcyIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAieGNyX2Rpc3RhbmNlX21ldGhvZCIgPSAnaG9ybicsICJ0Y3JfY2xvbm90eXBlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L2Nsb25vdHlwZXMvVFJCX2Nsb25vdHlwZXNfZmlsdGVyZWQudHh0JywgInNwYXRpYWxfcmVzdWx0X2RpcnMiID0gbGlzdCgic3Ryb21hbCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvc3BhdHNpbS9pdGg1L2FiYycsICJlcGl0aGVsaWFsIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9zcGF0c2ltL2l0aDMvYWJjJyksICJpaGNfcnVuMiIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaWhjL2NkNzljZDEzOGNkNjgvdmFsaWRhdGVkX3N0YXRzX3dlaWdodGVkLnJkYXRhJywgIm5lb2VkaXRpbmdfb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9uZW9lZGl0aW5nL3J1bjQnLCAibW1jdG1fc2FtcGxlX3Jlc3VsdF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LXNhbXBsZS9vdXRwdXQnLCAiYmNyX2Nsb25vdHlwZXMiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL21peGNyL21peGNyX3J1bnMvaXRoXzFfMl8zL21peGNyNS9jbG9ub3R5cGVzL0lHSF9jbG9ub3R5cGVzX2ZpbHRlcmVkLnR4dCcsICJwaGVub3R5cGVfdGhyZXNob2xkIiA9IDAuODUsICJ4Y3JtYXBzY2FwZV9maWxlcyIgPSBjKCcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIveGNybWFwc2NhcGUvMS5zdmcnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yL3hjcm1hcHNjYXBlLzIuc3ZnJywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL2ludGVybWVkaWF0ZXMvcnVuMi94Y3JtYXBzY2FwZS8zLnN2ZycsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIveGNybWFwc2NhcGUvNC5zdmcnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yL3hjcm1hcHNjYXBlLzcuc3ZnJywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL2ludGVybWVkaWF0ZXMvcnVuMi94Y3JtYXBzY2FwZS85LnN2ZycsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIveGNybWFwc2NhcGUvMTAuc3ZnJywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL2ludGVybWVkaWF0ZXMvcnVuMi94Y3JtYXBzY2FwZS8xMS5zdmcnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yL3hjcm1hcHNjYXBlLzEyLnN2ZycsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIveGNybWFwc2NhcGUvMTMuc3ZnJywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL2ludGVybWVkaWF0ZXMvcnVuMi94Y3JtYXBzY2FwZS8xNC5zdmcnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yL3hjcm1hcHNjYXBlLzE1LnN2ZycsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIveGNybWFwc2NhcGUvMTYuc3ZnJywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL2ludGVybWVkaWF0ZXMvcnVuMi94Y3JtYXBzY2FwZS8xNy5zdmcnKSwgImtub3duX3N1YnR5cGVzX21lcmdlZCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9rbm93bl9zdWJ0eXBlc19tZXJnZWQudHN2JywgImV4YW1wbGVfbXNhX3Bsb3QiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL2lncGFydGl0aW9uL3J1bjEzL29sZC9hbGlnbm1lbnRfcGxvdHMvbXNhL2l0aDJfMi9jbHVzdDkvaW5kZWxfcmV2ZXJzZWQuaHRtbCcsICJpbW10eXBlcl9sZW5ndGhzIiA9ICcxMSAxMiAxMyAxNCAxNSAxNiAxNyAxOCcsICJpdGhfcHJvamVjdF9yZXN1bHRzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL2l0aDMvZGF0YS9yZXN1bHRzJywgInhjcm1hcHNjYXBlX25vdGVib29rIiA9ICdSbWQveGNybWFwc2NhcGUuUm1kJywgImloY194Y3Jfc3RhdHNfbm90ZWJvb2siID0gJ1JtZC9paGNfeGNyX3N0YXRzLlJtZCcsICJjbG9uYWxfc2FtcGxlcnMiID0gYygnSE1DJywgJ05VVFMnKSwgImZpZ3VyZV9nYWxsZXJ5X25vdGVib29rIiA9ICdSbWQvZmlndXJlcy5SbWQnLCAiYmVuY2htYXJrZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2JlbmNobWFya3MvcGFwZXJhbmFseXNpczInLCAia25vd25fc3VidHlwZV9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL2FycmF5L3N1YnR5cGVzL2tub3duX3N1YnR5cGVzLnRzdicsICJtdXRzaWdfdGlsdHlwZXMiID0gYygnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknLCAnVF9DRDhfZGVuc2l0eScsICdUX0NENF9kZW5zaXR5JywgJ1RfQ0QyMF9kZW5zaXR5JywgJ1RfUGxhc21hX2RlbnNpdHknKSwgInN1YnR5cGVfbWFya2VyX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vbmFub3N0cmluZy9zdWJ0eXBlX21hcmtlcnMudHN2JywgInNpdGVfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL2FuYWx5c2lzL1JtZC9fc2l0ZS55bWwnLCAiaXRoX3N0YXRpc3RpY3Nfbm90ZWJvb2siID0gJ1JtZC9pdGhfc3RhdGlzdGljcy5SbWQnLCAidGFibGVfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMicsICJ2X2RpY3Rpb25hcnkiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9zdWJwcm9qZWN0cy9pbW10eXBlci9tZXRhZGF0YS9pbWd0L0hvbW9fc2FwaWVuc19UUkJWLmZhc3RhJywgIm5hbm9zdHJpbmdfYW5ub3RhdGlvbnMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vbmFub3N0cmluZy9wYW5jYW5jZXJfYW5ub3RhdGlvbnMudHN2JywgIndhbmdfZmJpX3N0YXR1cyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0MvbmcuMzg0OS1TMTIudHh0JywgImpfZGljdGlvbmFyeSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3N1YnByb2plY3RzL2ltbXR5cGVyL21ldGFkYXRhL2ltZ3QvSG9tb19zYXBpZW5zX1RSQkouZmFzdGEnLCAibW1jdG1fb3ZfY29tYmluZWRfcmVzdWx0X2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9jb21iaW5lZF9vdl9tbWN0bS9vdXRwdXQnLCAibW1jdG1fcGF0aWVudF9hbmNlc3RyYWxfZGVzY2VuZGFudF9yZXN1bHRfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9tbWN0bV9yZXN1bHRzL2l0aF9ieS1wYXRpZW50LWFuY2VzdHJ5L291dHB1dCcsICJsb2dkaXIiID0gJy9zaGFobGFiL2FsemhhbmcvY2x1c3R0bXAvcGFwZXJhbmFseXNpczInLCAiZGVmYXVsdF9zYW1wbGVyIiA9ICdITUMnLCAiaW50ZXJtZWRpYXRlX2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yJywgInRjcl9kaXZlcnNpdHkiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL21peGNyL21peGNyX3J1bnMvaXRoXzFfMl8zL21peGNyNS9wb3N0cHJvY2Vzcy9UUkIvcG9zdGZpbHRlcl9kaXZlcnNpdHlfc3RhdHMvZGl2ZXJzaXR5LnN0cmljdC5yZXNhbXBsZWQudHh0JywgImNsb25hbF9maWd1cmVfdGVtcGxhdGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9hbmFseXNpcy90ZW1wbGF0ZXMvY2xvbmFsX2ZpZ3VyZS5zdmcnLCAiZHJpdmVyX21hcCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3N1YnByb2plY3RzL2RyaXZlcnMvZGF0YS9nZW5lX2xpc3RfbWFwcGVkLmJlZCcsICJuYW5vc3RyaW5nX2RhdGEiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL25hbm9zdHJpbmdfcmVzdWx0cy9pdGhfZnVsbC9xYy9saW1tYV9xdWFudGlsZS9ub3JtYWxpemVkX2V4cHJlc3Npb25fdm9hX2xhYmVsc19maWx0ZXJlZC50c3YnLCAiaW1tdW5lX3ZhcmlhYmlsaXR5X25vdGVib29rIiA9ICdSbWQvaW1tdW5lX3ZhcmlhYmlsaXR5LlJtZCcsICJtdmNsdXN0X3RpbHR5cGVzIiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JyksICJjbG9uZV9wcmV2YWxlbmNlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2l0aC9jb21wbGV0ZS9jbG9uZV9kYXRhLnRzdicsICJtYXN0ZXJfdmFyaWFudF9maWxlIiA9ICcvc2hhaGxhYi9hbWNwaGVyc29uL3Byb2plY3RzL2l0aDMvaXRoMy9ub3RlYm9va3MvYmVzcG9rZS9pdGhfc252cy50c3YnLCAicGF0aWVudHNfZm9yX2Nsb25hbCIgPSBjKDEsIDIsIDMsIDQsIDcsIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTUsIDE2LCAxNyksICJ4Y3JfcWNfbm90ZWJvb2siID0gJ1JtZC9yZXBsaWNhdGVzLlJtZCcsICJzcGF0aWFsX25vdGVib29rIiA9ICdSbWQvc3BhdGlhbF9hbmFseXNpcy5SbWQnLCAiaWNnY19ub3JtYWxpemVkX3JlYWRzX21hdHJpeCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0MvT1ZBVV9leHByX21hdHJpeC50c3YnLCAiaWNnY19jbGluaWNhbCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0MvZG9ub3IuT1YtQVUudHN2JywgIm1hcHNjYXBlX25vdGVib29rIiA9ICdSbWQvbWFwc2NhcGUuUm1kJywgIm1tY3RtX3NhbXBsZV9zaWdwbG90IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9tbWN0bV9yZXN1bHRzL2l0aF9ieS1zYW1wbGUvcGxvdHMvaXRoLWJ5LXNhbXBsZV9zbnYtc3Zfc2lnc19tdWx0aXBhbmVsLnBkZicsICJpdGhfdGlsX25vdGVib29rIiA9ICdSbWQvaXRoX3RpbF9kZW5zaXRpZXMuUm1kJywgImNsb25lX3RyZWVfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL3RyZWVfZGF0YS50c3YnLCAiaXRoX3N0YXRfdHlwZXMiID0gYygnZW50cm9weScsICdwb3N0cHJvY2Vzc2VkX2RpdmVyZ2VuY2UnLCAnY29tYmluZWRfaXRoX25vcm1hbGl6ZWQnLCAncHJvcG9ydGlvbl9zdWJjbG9uYWwnKSwgIm12Y2x1c3RfbmNsdXN0IiA9IDMsICJpaGNfeGNyX3RpbHR5cGVzIiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JywgJ1RfQ0Q4X2RlbnNpdHknLCAnVF9DRDRfZGVuc2l0eScsICdUX0NEMjBfZGVuc2l0eScsICdUX1BsYXNtYV9kZW5zaXR5JyksICJtbWN0bV9maW5hbF9wYXRpZW50X2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9pdGhfYnktcGF0aWVudF93aXRoLW92JywgInRpbHNfZm9yX3ZhcmlhYmlsaXR5IiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JyksICJiY3JwaHlsb190aWx0eXBlcyIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScsICdUX0NEOF9kZW5zaXR5JywgJ1RfQ0Q0X2RlbnNpdHknLCAnVF9DRDIwX2RlbnNpdHknLCAnVF9QbGFzbWFfZGVuc2l0eScpLCAiaW5kZXhfbm90ZWJvb2siID0gJ1JtZC9pbmRleC5SbWQnLCAidmFyaWFiaWxpdHlfdHlwZSIgPSAnc3RhYmlsaXplJywgImNsb25lX2JyYW5jaF9sZW5ndGhfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL2JyYW5jaF9kYXRhLnRzdicsICJpZ3BhcnRpdGlvbl9vdXRkaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL2lncGFydGl0aW9uL3J1bjIyJywgInhjcl9tYXBwaW5nX25vdGVib29rIiA9ICdSbWQveGNyX21hcHBpbmcuUm1kJywgImJjcnBoeWxvX2NvcnJlbGF0aW9uc19ub3RlYm9vayIgPSAnUm1kL2Jjcl9waHlsb19jb3JyZWxhdGlvbnMuUm1kJywgInhjcm1hcHNjYXBlX3Rjcl9wYXRpZW50X29yZGVyIiA9IGMoMTUsIDEsIDMsIDQsIDIsIDE3LCA3LCAxNCwgOSwgMTAsIDEyLCAxMywgMTEsIDE2KSwgInRpbF9jbGFzc2lmaWVyX25vdGVib29rIiA9ICdSbWQvdGlsX2NsYXNzaWZpZXIuUm1kJywgImJjcnBoeWxvX2V4YW1wbGVzX25vdGVib29rIiA9ICdSbWQvYmNyX3BoeWxvX2V4YW1wbGVzLlJtZCcsICJQTkdfREVOU0lUWSIgPSAzMDAsICJtYXN0ZXJfYnJlYWtwb2ludF9maWxlIiA9ICcvc2hhaGxhYi9hbWNwaGVyc29uL3Byb2plY3RzL2l0aDMvaXRoMy9ub3RlYm9va3MvYmVzcG9rZS9pdGhfYnJlYWtwb2ludHMudHN2JywgIm1tY3RtX2ZpbmFsX3BhdGllbnRfc2lncGxvdCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9pdGhfYnktcGF0aWVudF93aXRoLW92L3Bsb3RzL2l0aC1ieS1wYXRpZW50X3Nudi1zdl9zaWdzX211bHRpcGFuZWwucGRmJywgIm1tY3RtX3BhdGllbnRfYWRfc2lncGxvdCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9pdGhfYnktcGF0aWVudC1hbmNlc3RyeS9wbG90cy9pdGgtYnktcGF0aWVudC1hbmNlc3RyeV9zbnYtc3Zfc2lnc19tdWx0aXBhbmVsLnBkZicsICJpdGhfc3RhdHNfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL2Nsb25hbF9tZWFzdXJlcy50c3YnLCAiaWhjX3J1bjEiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2loYy9jZDhjZDNjZDIwL3ZhbGlkYXRlZF9zdGF0c193ZWlnaHRlZF9uZXcucmRhdGEnLCAibnNjYXR0ZXJzIiA9IDYsICJtdWx0aXZpZXdjbHVzdGVyaW5nX25vdGVib29rIiA9ICdSbWQvbXVsdGl2aWV3Y2x1c3RlcmluZy5SbWQnLCAic21vb3RoX3R5cGUiID0gJ2xvZXNzJywgImNsYXNzaWZpZXJfdHlwZSIgPSAna25uJywgImljZ2Nfc3BlY2ltZW5fZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0Mvc3BlY2ltZW4udHN2JywgIm1tY3RtX2FuY2VzdHJhbF9kZXNjZW5kYW50X3Jlc3VsdF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LWFuY2VzdHJ5LXNhbXBsZS9vdXRwdXQnLCAibm90ZWJvb2tfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy93ZWInLCAiaW1tdHlwZXJfbW9kZWxzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9pbW10eXBlcl9yZXN1bHRzL2tsYXJlbmJlZWsvYWFfdmovZ3JhZGJvb3N0JywgImRiIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycsICJtdXRhdGlvbl9zaWduYXR1cmVfbm90ZWJvb2siID0gJ1JtZC9tdXRhdGlvbl9zaWduYXR1cmVzLlJtZCcsICJ0Y2dhX2NsaW5pY2FsIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9zeW5hcHNlX2NsaW5BbGxfZGF0YS50c3YnLCAidGlsc19mb3JfY2x1c3RlciIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAicHJvcG9ydGlvbl9zdWJjbG9uYWxfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL29sZF9wcm9wb3J0aW9uX3N1YmNsb25hbC50c3YnLCAic2FkX25vdGVib29rIiA9ICdSbWQvc3BlY2llc19hYnVuZGFuY2VfZGlzdHJpYnV0aW9ucy5SbWQnLCAiYmNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL0lHSC9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAibmNsdXN0cyIgPSAzLCAiZHJpdmVyX2FuYWx5c2lzX25vdGVib29rIiA9ICdSbWQvZHJpdmVyX2FuYWx5c2lzLlJtZCcsICJ4Y3JfY2xvbmVzX25vdGVib29rIiA9ICdSbWQveGNyX2Nsb25lc19hbmFseXNpcy5SbWQnLCAidGNnYV9vdl9hbm5vdGF0aW9ucyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL1RDR0EvdGNnYV9vdl9hbm5vdGF0aW9uX3N1cDEzLnR4dCcsICJ0Y2dhX2V4cHJfbWF0cml4IiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9leHByX21hdHJpeF9ub3JtYWxpemVfc3RhbmRhcmRpemVfbm9kdXBsaWNhdGVzLnRzdicsICJleGFtcGxlX2Fubm90YXRpb25zIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9pZ3BhcnRpdGlvbi9ydW4xMy9maW5hbF9wYXJ0aXRpb25zL2l0aDJfMi9jbHVzdDkvYW5ub3RhdGlvbnNfZmxhZ2dlZC50c3YnLCAibmVvYW50aWdlbl9lZGl0aW5nX25vdGVib29rIiA9ICdSbWQvaW1tdW5vZWRpdGluZy5SbWQnLCAiaWNnY19leHByX21lbHRlZCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0MvT1ZBVV9leHByX21lbHRlZC50c3YnLCAibmFub3N0cmluZ19zaWduYXR1cmVfbm90ZWJvb2siID0gJ1JtZC9uYW5vc3RyaW5nX3NpZ25hdHVyZXMuUm1kJywgIlBOR19RVUFMSVRZIiA9IDMwMCwgIm1tY3RtX3NhbXBsZV9hZF9zaWdwbG90IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9tbWN0bV9yZXN1bHRzL2l0aF9ieS1hbmNlc3RyeS1zYW1wbGUvcGxvdHMvaXRoLWJ5LWFuY2VzdHJhbC1zYW1wbGVfc252LXN2X3NpZ3NfbXVsdGlwYW5lbC5wZGYnLCAicHJldmFsZW5jZV90aHJlc2hvbGQiID0gMC4wMSwgImljZ2NfbW9sZWN1bGFyX3N1YnR5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9pY2djX3ByaW1hcnlfdHVtb3VyX3N1YnR5cGVzLnRzdicsICJtb2xzdWJ0eXBlX25vdGVib29rIiA9ICdSbWQvbW9sZWN1bGFyX3N1YnR5cGVzLlJtZCcsICJsaWJyYXJ5X3NpemVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvbGlicmFyeV9zaXplcy50c3YnLCAibW1jdG1fb3ZfY29tYmluZWRfc2lncGxvdCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9jb21iaW5lZF9vdl9tbWN0bS9wbG90cy9vdl9zbnYtc3Zfc2lnc19tdWx0aXBhbmVsLnBkZicpLAogICAgcnVsZSA9ICd4Y3JfcmVwbGljYXRlX3FjJwopCiMjIyMjIyMjIE9yaWdpbmFsIHNjcmlwdCAjIyMjIyMjIyMKCiAgICAgICAgICAgICAgICAgICAgICAgIGBgYAoKCmBgYHtyIGdsb2JhbF9jaHVua19vcHRpb25zLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHRpZHk9VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSkKYGBgCgoKYGBge3J9CmxpYnJhcnkoaXRoaS51dGlscykKbG9hZF9iYXNlX2xpYnMoKQoKbGlicmFyeShpdGhpLm1ldGEpCmxpYnJhcnkoaXRoaS54Y3IpCmBgYAoKIyMgQ29sb3VyIHBhbGV0dGVzCgpgYGB7cn0KcGFsX3BhdGllbnQgPC0gc2VsZWN0X3BhbGV0dGUoInBhdGllbnQiKQpgYGAKCiMjIFBhcmFtZXRlcnMKCmBgYHtyfQpkYl9wYXRoIDwtIHNuYWtlbWFrZUBwYXJhbXMkZGIKCnhjcl90YWJsZV9wYXRoIDwtIHNuYWtlbWFrZUBpbnB1dCR4Y3JfdGFibGUKcHJldmFsZW5jZV9vcHRpb24gPC0gc25ha2VtYWtlQHBhcmFtcyRwcmV2YWxlbmNlX29wdGlvbgpkaXN0YW5jZV9tZXRob2QgPC0gc25ha2VtYWtlQHBhcmFtcyR4Y3JfZGlzdGFuY2VfbWV0aG9kCnRjcl9kaXZlcnNpdHlfZmlsZSA8LSBzbmFrZW1ha2VAaW5wdXQkdGNyX2RpdmVyc2l0eQpiY3JfZGl2ZXJzaXR5X2ZpbGUgPC0gc25ha2VtYWtlQGlucHV0JGJjcl9kaXZlcnNpdHkKYGBgCgojIyBNZXRhZGF0YQoKYGBge3J9CmRiIDwtIHNyY19zcWxpdGUoZGJfcGF0aCwgY3JlYXRlPUZBTFNFKQpzYW1wbGVzIDwtIGNvbGxlY3QodGJsKGRiLCAic2FtcGxlcyIpKQpkdXBsaWNhdGVzIDwtIGNvbGxlY3QodGJsKGRiLCAiZHVwbGljYXRlcyIpKQp4Y3JzZXEgPC0gY29sbGVjdCh0YmwoZGIsICJ4Y3JzZXEiKSkKYGBgCgojIyBUQ1IvQkNSCgpgYGB7cn0KeGNyX3RhYmxlIDwtIHJlYWRfY2xvbm90eXBlcyh4Y3JfdGFibGVfcGF0aCwgZHVwbGljYXRlcz1UUlVFLCBkYl9wYXRoKQojeGNyX3RhYmxlIDwtIHN1YnNldCh4Y3JfdGFibGUsIGNvdW50ID49IDIwMCkKCnRlY2huaWNhbF9kdXBsaWNhdGVzIDwtIHVuaXF1ZShzdWJzZXQoeGNyc2VxLCB2b2FfdW5pcXVlICE9IHZvYSkkdm9hKQoKZHVwbGljYXRlX3NpdGVzIDwtIHN1YnNldChkdXBsaWNhdGVzLCBkdXBsaWNhdGUgPT0gMSkKZHVwbGljYXRlX3NpdGVzIDwtIG1lcmdlKHNhbXBsZXMsIGR1cGxpY2F0ZV9zaXRlcywgYnk9InZvYSIpCmR1cGxpY2F0ZV9jYXRlZ29yaWVzIDwtIHN1YnNldChkdXBsaWNhdGVfc2l0ZXMsIHNlbGVjdD1jKHBhdGllbnRfaWQsIHNpdGVfaWQpKQoKZHVwbGljYXRlc19tYXBwZWQgPC0gbWVyZ2UoZHVwbGljYXRlX2NhdGVnb3JpZXMsIHNhbXBsZXMsIGJ5PWMoInBhdGllbnRfaWQiLCAic2l0ZV9pZCIpKQpkdXBsaWNhdGVzX21hcHBlZCA8LSBtZXJnZShkdXBsaWNhdGVzX21hcHBlZCwgeGNyc2VxLCBieT1jKCJ2b2EiKSkKbWFwcGVkX2R1cGxpY2F0ZV9jYXRlZ29yaWVzIDwtIGR1cGxpY2F0ZXNfbWFwcGVkICU+JSBncm91cF9ieShwYXRpZW50X2lkLCBzaXRlX2lkKSAlPiUKICBzdW1tYXJpc2UobnVtX3ZvYT1sZW5ndGgodW5pcXVlKHZvYSkpKQptYXBwZWRfY2F0ZWdvcmllcyA8LSBzdWJzZXQobWFwcGVkX2R1cGxpY2F0ZV9jYXRlZ29yaWVzLCBudW1fdm9hID4gMSwgc2VsZWN0PWMoInBhdGllbnRfaWQiLCAic2l0ZV9pZCIpKQoKYmlvbG9naWNhbF9kdXBsaWNhdGVzIDwtIHVuaXF1ZShtZXJnZShkdXBsaWNhdGVzX21hcHBlZCwgbWFwcGVkX2NhdGVnb3JpZXMsIGJ5PWMoInBhdGllbnRfaWQiLCAic2l0ZV9pZCIpKSR2b2EpCmBgYAoKYGBgYHtyfQp0Y3Jfc2VnbWVudF90eXBlIDwtICJUUkIiCmJjcl9zZWdtZW50X3R5cGUgPC0gIklHSCIKCmlkX3R5cGUgPC0gInZvYV91bmlxdWUiCmBgYAoKIyMjIFRlY2huaWNhbCBkdXBsaWNhdGVzCgpgYGB7cn0KeGNyX3RhYmxlX3RkdXBzIDwtIHN1YnNldCh4Y3JfdGFibGUsIHZvYSAlaW4lIHRlY2huaWNhbF9kdXBsaWNhdGVzKQpgYGAKCmBgYHtyfQp0Y3JfdGR1cHMgPC0gc3Vic2V0KHhjcl90YWJsZV90ZHVwcywgdHlwZSA9PSB0Y3Jfc2VnbWVudF90eXBlKQp0Y3JfY3Jvc3NfdGFibGUgPC0gY3Jvc3NfdGFidWxhdGUodGNyX3RkdXBzLCBpZF90eXBlID0gaWRfdHlwZSkKCmJjcl90ZHVwcyA8LSBzdWJzZXQoeGNyX3RhYmxlX3RkdXBzLCB0eXBlID09IGJjcl9zZWdtZW50X3R5cGUpCmJjcl9jcm9zc190YWJsZSA8LSBjcm9zc190YWJ1bGF0ZShiY3JfdGR1cHMsIGlkX3R5cGUgPSBpZF90eXBlKQoKY3Jvc3NfdGR1cHMgPC0gbGlzdCh0Y3I9dGNyX2Nyb3NzX3RhYmxlLCBiY3I9YmNyX2Nyb3NzX3RhYmxlKQpgYGAKCmBgYHtyfQpkaXN0YW5jZV9tYXRyaWNlcyA8LSBsYXBwbHkoY3Jvc3NfdGR1cHMsIGZ1bmN0aW9uKGNyb3NzX3RhYmxlKSB7CiAgZGlzdG1hdCA8LSBjb21wdXRlX2ltbXVuZV9kaXN0YW5jZV9tYXRyaXgoY3Jvc3NfdGFibGUsIG1ldGhvZCA9IGRpc3RhbmNlX21ldGhvZCkKICBtYXQgPC0gYXMubWF0cml4KGRpc3RtYXQpCiAgcmV0dXJuKG1hdCkKfSkKYGBgCgoKYGBge3J9CnNpbXNfcmF3IDwtIGxhcHBseShkaXN0YW5jZV9tYXRyaWNlcywgZnVuY3Rpb24obWF0KSB7CiAgc2ltcyA8LSBhdmVyYWdlX2ludHJhcGF0aWVudF9zaW1pbGFyaXR5KG1hdCwgZmlsdGVyX3Rpc3N1ZSA9IEZBTFNFLCBpZF90eXBlID0gaWRfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiX3BhdGggPSBkYl9wYXRoLCByYXcgPSBUUlVFLCBncm91cCA9ICJ2b2EiLCB0YWJsZSA9ICJ4Y3JzZXEiKQogIHNpbXMgPC0gc2V0TmFtZXMoc3Vic2V0KHNpbXMsIHNlbGVjdD0tYyh0aXNzdWUxLCB0aXNzdWUyLCBwYXRpZW50MikpLCBjKCJzYW1wbGUxIiwgInNhbXBsZTIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkaXN0IiwgImdyb3VwIikpCiAgc2ltcyRwYXRpZW50X2lkIDwtIG1hcF9pZChzaW1zJGdyb3VwLCBmcm9tID0gInZvYSIsIHRvPSJwYXRpZW50X2lkIiwgZGJfcGF0aCA9IGRiX3BhdGgsIHRhYmxlID0gInNhbXBsZXMiKQogIHNpbXMkY29uZGVuc2VkX2lkIDwtIG1hcF9pZChzaW1zJGdyb3VwLCBmcm9tPSJ2b2EiLCB0bz0iY29uZGVuc2VkX2lkIiwgZGJfcGF0aD1kYl9wYXRoLCB0YWJsZT0ic2FtcGxlcyIpCiAgcHJvamVjdDEgPC0gbWFwX2lkKHNpbXMkc2FtcGxlMSwgZnJvbT0idm9hX3VuaXF1ZSIsIHRvPSJwcm9qZWN0X2lkIiwgZGJfcGF0aD1kYl9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRhYmxlPSJ4Y3JzZXEiKQogIHByb2plY3QyIDwtIG1hcF9pZChzaW1zJHNhbXBsZTIsIGZyb209InZvYV91bmlxdWUiLCB0bz0icHJvamVjdF9pZCIsIGRiX3BhdGg9ZGJfcGF0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICB0YWJsZT0ieGNyc2VxIikKICBzaW1zJGNvbXBhcmlzb25fdHlwZSA8LSBjKCJkaWZmZXJlbnQiLCAiaWRlbnRpY2FsIilbYXMubnVtZXJpYyhwcm9qZWN0MSA9PSBwcm9qZWN0MikrMV0KICBzaW1zX3N1bW1hcnkgPC0gc2ltcyAlPiUgZ3JvdXBfYnkoY29uZGVuc2VkX2lkLCBwYXRpZW50X2lkLCBjb21wYXJpc29uX3R5cGUpICU+JSBzdW1tYXJpc2UobWVhbl9zaW09MS1tZWFuKGRpc3QpKQogIHJldHVybihzaW1zX3N1bW1hcnkpCn0pCmBgYAoKYGBge3J9Cmlnbm9yZSA8LSBsYXBwbHkobGlzdCgidGNyIiwgImJjciIpLCBmdW5jdGlvbihzZWdtZW50KSB7CiAgZGF0IDwtIHNpbXNfcmF3W1tzZWdtZW50XV0KICBkYXQkcGF0aWVudF9pZCA8LSBmYWN0b3IoZGF0JHBhdGllbnRfaWQpCiAgZGF0JGNvbXBhcmlzb25fdHlwZSA8LSBmYWN0b3IoZGF0JGNvbXBhcmlzb25fdHlwZSkKICAKICBwIDwtIGdncGxvdChkYXQsIGFlcyh4PXBhdGllbnRfaWQsIHk9bWVhbl9zaW0pKSArIGdlb21fYm94cGxvdChhZXMoZmlsbD1jb21wYXJpc29uX3R5cGUpKSArIGdlb21faml0dGVyKHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcih3aWR0aD0wLjIsIGhlaWdodD0wKSkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBnZXRfY29sb3VyX3BhbGV0dGUoZGF0JGNvbXBhcmlzb25fdHlwZSkpICsgdGhlbWVfYncoKSArIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyB4bGFiKCJQYXRpZW50IikgKyB5bGFiKCJQYWlyd2lzZSByZXBlcnRvaXJlIHNpbWlsYXJpdHkiKQogIHByaW50KHApCn0pCmBgYAoKCldlIG1pZ2h0IGhhdmUgZ29vZCByZWFzb24gdG8gc3VzcGVjdCB0aGF0IGR1cGxpY2F0ZXMgY29uZHVjdGVkIGF0IGRpZmZlcmVudCB0aW1lcyAoaS5lLiB0aGUgb3JpZ2luYWwgVENSL0JDUi1zZXEgZXhwZXJpbWVudCB5ZWFycyBhZ28gdnMuIHRoZSBvbmUgbm93KSBtaWdodCBub3QgZ2l2ZSB0aGUgc2FtZSByZXN1bHRzLiBUaGUgUklOIHZhbHVlcyBmb3IgdGhlIG9sZCBzYW1wbGVzIHRoYXQgd2UgcmUtcmFuIHdlcmUgcXVpdGUgbG93ICgzLTUsIGNvbXBhcmVkIHRvIHRoZSB1c3VhbCA+NykuIEluZGVlZCwgdGhlIEJDUiBkYXRhIHNob3dzIHRoYXQgZHVwbGljYXRlcyBmcm9tIHRoZSBzYW1lIHJ1biBhcmUgbW9yZSBzaW1pbGFyIHRvIGVhY2ggb3RoZXIgdGhhbiB0aG9zZSBmcm9tIGRpZmZlcmVudCBydW5zLiAKCkhvd2V2ZXIsIG9uZSBjYXNlIGlzIGFsYXJtaW5nIC0tIHBhdGllbnQgMjEgaW4gdGhlIFRDUiBkYXRhLiBJIG1hZGUgYW4gSUQgbWFwcGluZyBlcnJvciBhbmQgbWlzc2VkIG1vc3Qgc2FtcGxlcyBmcm9tIHBhdGllbnQgMjEgaW4gdGhlIGZpcnN0IHJvdW5kIG9mIHByb2Nlc3NpbmcuIEhvd2V2ZXIsIHRoZSByZWZhY3RvcmluZyBhbmQgZGF0YWJhc2UgY29uc3RydWN0aW9uIHN0aW11bGF0ZWQgYnkgdGhlIG5ld2VzdCBydW4gYWxsb3dlZCBtZSB0byByZWNvdmVyIHRoZXNlIHNhbXBsZXMuIFNvbWV0aGluZyBmaXNoeSBkZWZpbml0ZWx5IHNlZW1zIHRvIGJlIGdvaW5nIG9uIGhlcmUuIFN1YnNldHRpbmcgdG8gY2xvbm90eXBlcyB3aXRoID49IDUwLCAyMDAgcmVhZHMgZGlkIG5vdCBoZWxwLCBpbmRpY2F0aW5nIHRoYXQgdGhlIGlzc3VlIGlzbid0IGxpa2VseSB0byBiZSBjYXVzZWQgYnkgbG93LWxldmVsIGNvbnRhbWluYXRpb24uIEl0IG1heSBzdGlsbCBiZSBjYXVzZWQgYnkgaGlnaC1sZXZlbCBjb250YW1pbmF0aW9uIC0tIHRoaXMgaXMgKndvcnRoIGludmVzdGlnYXRpbmcqIGFzIHBhdGllbnQgMjEgaGFzIGEgdmVyeSBsb3cgdG90YWwgY2xvbm90eXBlIGNvdW50LiAKCk5leHQgc3RlcHM6IENoZWNrIFJJTiB2YWx1ZXMgZnJvbSB0aGUgb3JpZ2luYWwgcnVuIGZvciBwYXRpZW50IDIxJ3Mgc2FtcGxlcy4gCkFuc3dlcjogVGhleSBhcmUgb24gdGhlIGxvdyBzaWRlIGZvciBJWDMyNDggKG1lZGlhbiA9IDUuMiksIGJ1dCB0aGVyZSBhcmUgc2V2ZXJhbCBwYXRpZW50cyBhcm91bmQgdGhlIDUuNC01LjcgcmFuZ2UuIFNvIEknbSB0ZW1wdGVkIHRvIHNheSB0aGF0IGlzbid0IHRoZSBjYXVzZSBvZiB0aGUgaXNzdWUuIAoKClRPRE86IEFsc28gZXZhbHVhdGUgdmFyaWF0aW9uIGluIGRpdmVyc2l0eSB2YWx1ZXMuIAoKIyMgQmlvbG9naWNhbCBkdXBsaWNhdGVzCgpBbm90aGVyIGNsYXNzIG9mIGR1cGxpY2F0ZXMgd2UgdGVzdGVkIHdlcmUgcGFydHMgb2Ygc2FtcGxlcyBjb21pbmcgZnJvbSB0aGUgc2FtZSB0dW1vdXIgc2FtcGxlLiBUaGF0J3MgYSBiaXQgY29uZnVzaW5nIC0tIHdoYXQgaXQgbWVhbnMgaXMgdGhhdCBlYWNoIHR1bW91ciBzYW1wbGUgd2FzIHNwbGl0IGludG8gMiBmcmVzaCBmcm96ZW4gYW5kIDEgRkZQRSBhbGlxdW90LCBhbmQgZm9yIHNvbWUgY2FzZXMgd2Ugc3ViamVjdGVkIGJvdGggZnJlc2ggZnJvemVuIGFsaXF1b3RzIHRvIFRDUi9CQ1Itc2VxLiBJIGxvb3NlbHkgcmVmZXIgdG8gdGhlc2UgY2FzZXMgYXMgJ2Jpb2xvZ2ljYWwgZHVwbGljYXRlcycuIAoKYGBge3J9CmlkX3R5cGUgPC0gInZvYSIKCnhjcl90YWJsZV9iZHVwcyA8LSBzdWJzZXQoeGNyX3RhYmxlLCB2b2FfdW5pcXVlICVpbiUgYmlvbG9naWNhbF9kdXBsaWNhdGVzKQpgYGAKCmBgYHtyfQp0Y3JfYmR1cHMgPC0gc3Vic2V0KHhjcl90YWJsZV9iZHVwcywgdHlwZSA9PSB0Y3Jfc2VnbWVudF90eXBlKQp0Y3JfY3Jvc3NfdGFibGUgPC0gY3Jvc3NfdGFidWxhdGUodGNyX2JkdXBzLCBpZF90eXBlID0gaWRfdHlwZSkKCmJjcl9iZHVwcyA8LSBzdWJzZXQoeGNyX3RhYmxlX2JkdXBzLCB0eXBlID09IGJjcl9zZWdtZW50X3R5cGUpCmJjcl9jcm9zc190YWJsZSA8LSBjcm9zc190YWJ1bGF0ZShiY3JfYmR1cHMsIGlkX3R5cGUgPSBpZF90eXBlKQoKY3Jvc3NfYmR1cHMgPC0gbGlzdCh0Y3I9dGNyX2Nyb3NzX3RhYmxlLCBiY3I9YmNyX2Nyb3NzX3RhYmxlKQpgYGAKCmBgYHtyfQpkaXN0YW5jZV9tYXRyaWNlcyA8LSBsYXBwbHkoY3Jvc3NfYmR1cHMsIGZ1bmN0aW9uKGNyb3NzX3RhYmxlKSB7CiAgZGlzdG1hdCA8LSBjb21wdXRlX2ltbXVuZV9kaXN0YW5jZV9tYXRyaXgoY3Jvc3NfdGFibGUsIG1ldGhvZCA9IGRpc3RhbmNlX21ldGhvZCkKICBtYXQgPC0gYXMubWF0cml4KGRpc3RtYXQpCiAgcmV0dXJuKG1hdCkKfSkKYGBgCgoKYGBge3J9CnNpbXNfcmF3IDwtIGxhcHBseShkaXN0YW5jZV9tYXRyaWNlcywgZnVuY3Rpb24obWF0KSB7CiAgc2ltcyA8LSBhdmVyYWdlX2ludHJhcGF0aWVudF9zaW1pbGFyaXR5KG1hdCwgZmlsdGVyX3Rpc3N1ZSA9IEZBTFNFLCBpZF90eXBlID0gaWRfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiX3BhdGggPSBkYl9wYXRoLCByYXcgPSBUUlVFLCBncm91cCA9ICJjb25kZW5zZWRfaWQiLCB0YWJsZSA9ICJzYW1wbGVzIikKICBzaW1zIDwtIHNldE5hbWVzKHN1YnNldChzaW1zLCBzZWxlY3Q9LWModGlzc3VlMSwgdGlzc3VlMiwgcGF0aWVudDIpKSwgYygic2FtcGxlMSIsICJzYW1wbGUyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGlzdCIsICJjb25kZW5zZWRfaWQiKSkKICBzaW1zJHBhdGllbnRfaWQgPC0gbWFwX2lkKHNpbXMkY29uZGVuc2VkX2lkLCBmcm9tID0gImNvbmRlbnNlZF9pZCIsIHRvPSJwYXRpZW50X2lkIiwgZGJfcGF0aCA9IGRiX3BhdGgsIHRhYmxlID0gInNhbXBsZXMiKQogIHByb2plY3QxIDwtIG1hcF9pZChzaW1zJHNhbXBsZTEsIGZyb209InZvYV91bmlxdWUiLCB0bz0icHJvamVjdF9pZCIsIGRiX3BhdGg9ZGJfcGF0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICB0YWJsZT0ieGNyc2VxIikKICBwcm9qZWN0MiA8LSBtYXBfaWQoc2ltcyRzYW1wbGUyLCBmcm9tPSJ2b2FfdW5pcXVlIiwgdG89InByb2plY3RfaWQiLCBkYl9wYXRoPWRiX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGFibGU9InhjcnNlcSIpCiAgc2ltcyRjb21wYXJpc29uX3R5cGUgPC0gYygiZGlmZmVyZW50IiwgImlkZW50aWNhbCIpW2FzLm51bWVyaWMocHJvamVjdDEgPT0gcHJvamVjdDIpKzFdCiAgc2ltc19zdW1tYXJ5IDwtIHNpbXMgJT4lIGdyb3VwX2J5KGNvbmRlbnNlZF9pZCwgcGF0aWVudF9pZCwgY29tcGFyaXNvbl90eXBlKSAlPiUgc3VtbWFyaXNlKG1lYW5fc2ltPTEtbWVhbihkaXN0KSkKICByZXR1cm4oc2ltc19zdW1tYXJ5KQp9KQpgYGAKCmBgYHtyfQppZ25vcmUgPC0gbGFwcGx5KGxpc3QoInRjciIsICJiY3IiKSwgZnVuY3Rpb24oc2VnbWVudCkgewogIGRhdCA8LSBzaW1zX3Jhd1tbc2VnbWVudF1dCiAgZGF0JHBhdGllbnRfaWQgPC0gZmFjdG9yKGRhdCRwYXRpZW50X2lkKQogIGRhdCRjb21wYXJpc29uX3R5cGUgPC0gZmFjdG9yKGRhdCRjb21wYXJpc29uX3R5cGUpCiAgCiAgcCA8LSBnZ3Bsb3QoZGF0LCBhZXMoeD1wYXRpZW50X2lkLCB5PW1lYW5fc2ltKSkgKyBnZW9tX2JveHBsb3QoYWVzKGZpbGw9Y29tcGFyaXNvbl90eXBlKSkgKyBnZW9tX2ppdHRlcihwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXIod2lkdGg9MC4yLCBoZWlnaHQ9MCkpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZ2V0X2NvbG91cl9wYWxldHRlKGRhdCRjb21wYXJpc29uX3R5cGUpKSArIHRoZW1lX2J3KCkgKyB0aGVtZV9QdWJsaWNhdGlvbigpICsgeGxhYigiUGF0aWVudCIpICsgeWxhYigiUGFpcndpc2UgcmVwZXJ0b2lyZSBzaW1pbGFyaXR5IikKICBwcmludChwKQp9KQpgYGAKCkEgbGl0dGxlIHN1cnByaXNpbmcgaXMgaG93IGxvdyB0aGUgcmVwZXJ0b2lyZSBzaW1pbGFyaXR5IGlzIGJldHdlZW4gYmlvbG9naWNhbCBkdXBsaWNhdGVzIC0tIGZyb20gYWxpcXVvdHMgdGhhdCBhcmUgdGFrZW4gZnJvbSB0aGUgc2FtZSB0dW1vdXIgc2FtcGxlISBDb25zaXN0ZW50IHdpdGggb3VyIGZpbmRpbmdzIHRoYXQgaGlnaCBULWNlbGwgYWJ1bmRhbmNlID0gaGlnaCBsZXZlbHMgb2YgaW50cmFwYXRpZW50IHNpbWlsYXJpdHksIHBhdGllbnQgMTUgc3RhbmRzIG91dCBhcyBhIGJlYWNvbiBvZiBjb25zaXN0ZW5jeS4g