1 Aims

  • Create a list of mutated MHCI T-cell epitopes those appear in the COVEO database

2 Summary

  • There are 653 epitopes in the original downloaded epitope list. There are 190 out of 653 epitopes those were published more than a single paper. 184 out of 190 epitopes derived from reference sequence (this was used in this report, later the extra 6 mutated epitopes will be included too) see
  • Position of analyzed T cell epitopes on Spike reference sequence see
  • Barcode was assigned to each samples. A given barcode is basically a mutation pattern (amino acide level) of S protein. There are 346976 barcodes in the database. There are only 1972 barcodes that appeared more than 100 samples in the database (only these are included the analysis). 1784108 samples are assigned to these different 1972 barcodes.
  • The selected epitopes and barcodes were matched. A table was created that contains the 935 mutated T cell epitopes see. Downloadable table: “/v/projects/geno2pheno-kpapp/kpapp/t_cell_epitop/data/mutated_epitopes.tsv”

3 Background

  • T cell epitopes were downloaded (https://www.iedb.org/) by David: (“/v/projects/geno2pheno-kpapp/dnieuw/MHCI-Spike-epitopes_metadata.tsv”)

  • The COVEO database will be searched for these epitopes and check the presences of their mutated version

4 Analysis

library(tidyverse)
library(openxlsx)
library(DBI)
config <- config::get()
con <- dbConnect(
  drv = RPostgreSQL::PostgreSQL(),
  dbname = config$dbname,
  host = config$host,
  port = config$port,
  user = config$user,
  password = config$password,
  option = config$option
)
selected_schema <- str_remove(config$option, pattern = "-c search_path=")

4.1 T cell epitope table

The table below is the original downloaded table:

f <- "/v/projects/geno2pheno-kpapp/dnieuw/MHCI-Spike-epitopes.tsv"
epitope_raw_ref <- read_tsv(f, show_col_types = FALSE)[, c(1,5,6)]
names(epitope_raw_ref) <- c("id", "references", "assays")
epitope_raw_ref$id <- as.character(epitope_raw_ref$id)

f <- "/v/projects/geno2pheno-kpapp/dnieuw/MHCI-Spike-epitopes_metadata.tsv"
epitope_raw <- read_tsv(f, show_col_types = FALSE)[1:17]
names(epitope_raw) <- c("iedb_iri", "object_type", "name", "modified_residue", 
                    "modifications", "start", "end", "iri", "synonyms",
                    "source_molecule", "source_molecule_iri", "molecule_parent",
                    "molecule_parent_iri", "source_organism",
                    "source_organism_iri", "species", "species_iri")
epitope_raw <- epitope_raw %>%
  separate(col = iedb_iri, into = c(NA, NA, NA, NA, "id"),
           sep = "/", remove = FALSE) %>%
  inner_join(epitope_raw_ref, by = "id") %>%
  select(id, name, start, end, references, assays, everything())
  
epitope_raw
  • Table above shows that there are 653 epitopes in the raw epitope table

Need to concentrate only those epitopes those were present in more than 1 presentation

epitope <- epitope_raw %>%
  filter(references>1)
epitope
  • There are 190 out of 653 epitopes those were published more than a single paper
epitope%>%
  filter(is.na(start))
  • There is a single epitope (1593848) where the start and end position is missing. Based on David’s alignment (“/v/projects/geno2pheno-kpapp/dnieuw/MHCI-Spike-epitopes_aligned.faa”), the position of this epitope is similar to https://www.iedb.org/epitope/1309147 epitope. There difference is a single mutation at amino acide level. So this epitope does not derive from reference sequence but the start-end position will be included the table:
epitope[epitope$id=="1593848", "start"] <- 269
epitope[epitope$id=="1593848", "end"] <- 277

Need to check if epitope sequences derived from the reference sequence.

The reference sequence is here: https://www.ncbi.nlm.nih.gov/nuccore/MN908947 Spike protein (QHD43416.1) is coded in the reference sequence position: 21563-25384

Database will be searched for the reference Spike protein sequence:

select * from datahub_0.translated_aa_ref_sequence(21563, 25384)
  • Note: the “datahub_0.barcodes_with_mutation_positions({start}, {end})” SQL function translate the reference nucleotide sequence into protein sequence (the parameters are the start and end positions of reference nucleotide sequence)
spike_seq <- str_c(spike_seq$aa_symbol, collapse = "")
spike_seq
[1] "MFVFLVLLPLVSSQCVNLTTRTQLPPAYTNSFTRGVYYPDKVFRSSVLHSTQDLFLPFFSNVTWFHAIHVSGTNGTKRFDNPVLPFNDGVYFASTEKSNIIRGWIFGTTLDSKTQSLLIVNNATNVVIKVCEFQFCNDPFLGVYYHKNNKSWMESEFRVYSSANNCTFEYVSQPFLMDLEGKQGNFKNLREFVFKNIDGYFKIYSKHTPINLVRDLPQGFSALEPLVDLPIGINITRFQTLLALHRSYLTPGDSSSGWTAGAAAYYVGYLQPRTFLLKYNENGTITDAVDCALDPLSETKCTLKSFTVEKGIYQTSNFRVQPTESIVRFPNITNLCPFGEVFNATRFASVYAWNRKRISNCVADYSVLYNSASFSTFKCYGVSPTKLNDLCFTNVYADSFVIRGDEVRQIAPGQTGKIADYNYKLPDDFTGCVIAWNSNNLDSKVGGNYNYLYRLFRKSNLKPFERDISTEIYQAGSTPCNGVEGFNCYFPLQSYGFQPTNGVGYQPYRVVVLSFELLHAPATVCGPKKSTNLVKNKCVNFNFNGLTGTGVLTESNKKFLPFQQFGRDIADTTDAVRDPQTLEILDITPCSFGGVSVITPGTNTSNQVAVLYQDVNCTEVPVAIHADQLTPTWRVYSTGSNVFQTRAGCLIGAEHVNNSYECDIPIGAGICASYQTQTNSPRRARSVASQSIIAYTMSLGAENSVAYSNNSIAIPTNFTISVTTEILPVSMTKTSVDCTMYICGDSTECSNLLLQYGSFCTQLNRALTGIAVEQDKNTQEVFAQVKQIYKTPPIKDFGGFNFSQILPDPSKPSKRSFIEDLLFNKVTLADAGFIKQYGDCLGDIAARDLICAQKFNGLTVLPPLLTDEMIAQYTSALLAGTITSGWTFGAGAALQIPFAMQMAYRFNGIGVTQNVLYENQKLIANQFNSAIGKIQDSLSSTASALGKLQDVVNQNAQALNTLVKQLSSNFGAISSVLNDILSRLDKVEAEVQIDRLITGRLQSLQTYVTQQLIRAAEIRASANLAATKMSECVLGQSKRVDFCGKGYHLMSFPQSAPHGVVFLHVTYVPAQEKNFTTAPAICHDGKAHFPREGVFVSNGTHWFVTQRNFYEPQIITTDNTFVSGNCDVVIGIVNNTVYDPLQPELDSFKEELDKYFKNHTSPDVDLGDISGINASVVNIQKEIDRLNEVAKNLNESLIDLQELGKYEQYIKWPWYIWLGFIAGLIAIVMVTIMLCCMTSCCSCLKGCCSCGSCCKFDEDDSEPVLKGVKLHYT"

Check if the name column of the epitope table contains really the reference sequence.

for (i in 1:nrow(epitope)) {
  ref <- str_sub(spike_seq,
                 start = epitope[i, 'start'],
                 end = epitope[i, 'end'])
  if (epitope[i, 'name'] == ref) epitope[i, 'match_with_ref'] <- TRUE else epitope[i, 'match_with_ref'] <- FALSE
}

Lets see the result of the comparison

table(epitope$match_with_ref)

FALSE  TRUE 
    6   184 

There are 6 epitopes where the name column does not match with the reference.

These are the epitopes those do not match with reference sequence:

epitope[epitope$match_with_ref==FALSE,]
  • These epitopes above are important one, but now for simplicity I will exclude them, later these epitopes will be checked.

4.1.1 Table of T cell epitopes included the analysis

The table below contains the epitopes those derived from reference sequence:

epitope_selected <- epitope %>%
  filter(match_with_ref) 
epitope_selected

4.1.2 Position of epitopes on reference spike sequence

x <- epitope_selected %>%
  select(id, start, end) %>%
  mutate(start = as.numeric(start),
         end = as.numeric(end)) %>%
  arrange(start)
x$y <- 1:nrow(x)
x <- x %>%
  pivot_longer(cols = start:end, values_to = "x")
ggplot(data = x, aes(x = x, y = y, fill = id)) +
  geom_line(alpha = 0.4) +
  labs(title = "Distribution of T-cell epitopes on spike protein",
       x = "Amino acide position",
       y = "") +
  theme_minimal() +
  theme(aspect.ratio=2/6)

  • Each short horizontal line represent a T cell epitope

4.2 Barcode table

Barcode was assigned to each samples. A given barcode is basically a mutation pattern (amino acide level) of S protein.

How many different S protein exist now in the database?

SELECT count(*)
FROM barcode
  • There are 346976 barcodes in the database.

I will use only those barcodes that were assigned to more than 100 samples:

WITH barcode_dist AS (
     SELECT barcode_id, count(*) AS sample_number_in_bacode
          FROM aa_mutation_new AS a
          GROUP BY a.barcode_id
)

SELECT sample_number_in_bacode, count(*) AS number_of_barcode
     FROM barcode_dist
     GROUP BY sample_number_in_bacode
     ORDER BY number_of_barcode DESC
barcode_hist %>%
  filter(sample_number_in_bacode > 100) %>%
  summarise(`Number of barcodes` = sum(number_of_barcode))

There are 1972 barcodes that appeared more than 100 samples in the database.

barcode_hist %>%
  filter(sample_number_in_bacode > 100) %>%
  summarise(`Number of samples belongs to the selected barcodes` = sum(sample_number_in_bacode))
  • Around 1.8 million samples will be included into this analysis

List of barcodes that will be included this analysis:

WITH barcode_dist AS (
     SELECT barcode_id, count(*) AS sample_number_in_bacode
          FROM aa_mutation_new AS a
          GROUP BY a.barcode_id
)

SELECT barcode_id, sample_number_in_bacode, aa_mutation
     FROM barcode_dist
     LEFT JOIN barcode ON barcode.id=barcode_dist.barcode_id
     WHERE barcode_dist.sample_number_in_bacode > 100

Head of the table:

head(barcodes)

4.3 Match barcodes with T cell epitopes

mutation <- barcodes %>%
  mutate(mut = aa_mutation) %>%
  mutate(mut = str_remove(mut, pattern = "\\{"),
         mut = str_remove(mut, pattern = "\\}"),
         mut = str_remove_all(mut, pattern = "p\\.")) %>%
  mutate(n = (str_count(mut, pattern = ",") + 1))

max_mut <- max(mutation$n)
ids <- str_c("x", 1:max_mut)

mutation<- mutation%>%
  separate(mut, into = ids, sep = ",", fill  = "right") %>%
  pivot_longer(cols = all_of(ids), values_to = "mut",
               names_to = "mut_pos_in_barcode") %>%
  drop_na(mut) %>%
  mutate(pos = as.numeric(str_sub(mut, start = 4, end = -4)))

head(mutation)
  • Table above shows the positions of mutations in the selected barcodes.

Select those epitopes where start-end position includes any of the mutation positions above.

mutation_all <- tibble(barcode_id = integer(),
                       sample_number_in_bacode = numeric(),
                       aa_mutation = character(),
                       n = numeric(),
                       mut_pos_in_barcode = character(),
                       mut = character(),
                       pos = numeric(),
                       start = numeric(),
                       end = numeric(),
                       iedb_id= character())

for (i in row.names(epitope_selected)) {
  x <- mutation %>%
    mutate(start = as.numeric(epitope_selected[i, "start"]),
           end = as.numeric(epitope_selected[i, "end"]),
           iedb_id = as.character(epitope_selected[i, "id"])) %>%
    mutate(is_mutation_present = ifelse((pos >= start & pos <= end), TRUE, FALSE)) %>%
    filter(is_mutation_present) %>%
    select(-is_mutation_present)
  mutation_all <- mutation_all %>%
    add_row(x)
}
mutation_fin <- mutation_all_mod %>%
  select(barcode_id, iedb_id, mut) %>%
  group_by(barcode_id, iedb_id) %>%
  summarize(mutation_list = str_c(mut, collapse = ",")) %>%
  inner_join(x, by = c("barcode_id", "iedb_id")) %>%
  mutate(mutation_list = str_replace_all(mutation_list, pattern = 'Ala', replacement = 'A'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Arg', replacement = 'R'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Asn', replacement = 'N'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Asp', replacement = 'D'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Cys', replacement = 'C'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Gln', replacement = 'Q'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Glu', replacement = 'E'),
         mutation_list = str_replace_all(mutation_list, pattern = 'His', replacement = 'H'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Ile', replacement = 'I'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Leu', replacement = 'L'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Lys', replacement = 'K'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Met', replacement = 'M'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Phe', replacement = 'F'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Pro', replacement = 'P'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Ser', replacement = 'S'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Thr', replacement = 'T'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Trp', replacement = 'W'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Tyr', replacement = 'Y'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Val', replacement = 'V'),
         mutation_list = str_replace_all(mutation_list, pattern = 'Gly', replacement = 'G')
         )
`summarise()` has grouped output by 'barcode_id'. You can override using the `.groups` argument.

There are 38155 mutated epitopes in the table above, but many of them appear in more than one times (if the same mutated epitope appears in more than one barcode, then it it will be present more than one row)

4.3.1 Mutated epitope table

mutated_epitope_table <- mutation_fin %>%
  ungroup() %>%
  select(iedb_id, ref_epitope, mut_epitope) %>%
  distinct()
mutated_epitope_table  
  • The table above contains 935 mutated epitopes. This is the final list, these need to be checked if their binding affinity changes as a result of mutation
write_tsv(mutated_epitope_table, file = "/v/projects/geno2pheno-kpapp/kpapp/t_cell_epitop/data/mutated_epitopes.tsv")
write_tsv(mutation_fin, file = "/v/projects/geno2pheno-kpapp/kpapp/t_cell_epitop/data/mutated_epitopes_barcodes.tsv")
write_tsv(mutation_all, file = "/v/projects/geno2pheno-kpapp/kpapp/t_cell_epitop/data/mutated_epitopes_barcodes_all.tsv")
LS0tCnRpdGxlOiAiTUhDSSBULWNlbGwgZXBpdG9wZXMgZnJvbSBTcGlrZSBwcm90ZWluIgphdXRob3I6ICJLcmlzenRpYW4gUGFwcCIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgY29sbGFwc2VkOiBmYWxzZQogICAgZmlnX2NhcHRpb246IHllcwogICAgZmlnX2hlaWdodDogNAogICAgZmlnX3dpZHRoOiA1CiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBzYW5kc3RvbmUKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgojIEFpbXMKCiogQ3JlYXRlIGEgbGlzdCBvZiBtdXRhdGVkIE1IQ0kgVC1jZWxsIGVwaXRvcGVzIHRob3NlIGFwcGVhciBpbiB0aGUgQ09WRU8gZGF0YWJhc2UKCiMgU3VtbWFyeQoKKiBUaGVyZSBhcmUgNjUzIGVwaXRvcGVzIGluIHRoZSBvcmlnaW5hbCBkb3dubG9hZGVkIGVwaXRvcGUgbGlzdC4gVGhlcmUgYXJlIDE5MCBvdXQgb2YgNjUzIGVwaXRvcGVzIHRob3NlIHdlcmUgcHVibGlzaGVkIG1vcmUgdGhhbiBhIHNpbmdsZSBwYXBlci4gMTg0IG91dCBvZiAxOTAgZXBpdG9wZXMgZGVyaXZlZCBmcm9tIHJlZmVyZW5jZSBzZXF1ZW5jZSAodGhpcyB3YXMgdXNlZCBpbiB0aGlzIHJlcG9ydCwgbGF0ZXIgdGhlIGV4dHJhIDYgbXV0YXRlZCBlcGl0b3BlcyB3aWxsIGJlIGluY2x1ZGVkIHRvbykgW3NlZV0oI2ExKQoqIFBvc2l0aW9uIG9mIGFuYWx5emVkIFQgY2VsbCBlcGl0b3BlcyBvbiBTcGlrZSByZWZlcmVuY2Ugc2VxdWVuY2UgW3NlZV0oI2EyKQoqIEJhcmNvZGUgd2FzIGFzc2lnbmVkIHRvIGVhY2ggc2FtcGxlcy4gQSBnaXZlbiBiYXJjb2RlIGlzIGJhc2ljYWxseSBhIG11dGF0aW9uIHBhdHRlcm4gKGFtaW5vIGFjaWRlIGxldmVsKSBvZiBTIHByb3RlaW4uIFRoZXJlIGFyZSAzNDY5NzYgYmFyY29kZXMgaW4gdGhlIGRhdGFiYXNlLiBUaGVyZSBhcmUgb25seSAxOTcyIGJhcmNvZGVzIHRoYXQgYXBwZWFyZWQgbW9yZSB0aGFuIDEwMCBzYW1wbGVzIGluIHRoZSBkYXRhYmFzZSAob25seSB0aGVzZSBhcmUgaW5jbHVkZWQgdGhlIGFuYWx5c2lzKS4gMTc4NDEwOCBzYW1wbGVzIGFyZSBhc3NpZ25lZCB0byB0aGVzZSBkaWZmZXJlbnQgMTk3MiBiYXJjb2Rlcy4KKiBUaGUgc2VsZWN0ZWQgZXBpdG9wZXMgYW5kIGJhcmNvZGVzIHdlcmUgbWF0Y2hlZC4gQSB0YWJsZSB3YXMgY3JlYXRlZCB0aGF0IGNvbnRhaW5zIHRoZSA5MzUgbXV0YXRlZCBUIGNlbGwgZXBpdG9wZXMgW3NlZV0oI2EzKS4gRG93bmxvYWRhYmxlIHRhYmxlOiAiL3YvcHJvamVjdHMvZ2VubzJwaGVuby1rcGFwcC9rcGFwcC90X2NlbGxfZXBpdG9wL2RhdGEvbXV0YXRlZF9lcGl0b3Blcy50c3YiCgojIEJhY2tncm91bmQKCiogVCBjZWxsIGVwaXRvcGVzIHdlcmUgZG93bmxvYWRlZCAoaHR0cHM6Ly93d3cuaWVkYi5vcmcvKSBieSBEYXZpZDogICgiL3YvcHJvamVjdHMvZ2VubzJwaGVuby1rcGFwcC9kbmlldXcvTUhDSS1TcGlrZS1lcGl0b3Blc19tZXRhZGF0YS50c3YiKQoKKiBUaGUgQ09WRU8gZGF0YWJhc2Ugd2lsbCBiZSBzZWFyY2hlZCBmb3IgdGhlc2UgZXBpdG9wZXMgYW5kIGNoZWNrIHRoZSBwcmVzZW5jZXMgb2YgdGhlaXIgbXV0YXRlZCB2ZXJzaW9uCgojIEFuYWx5c2lzCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkob3Blbnhsc3gpCmxpYnJhcnkoREJJKQpgYGAKCmBgYHtyfQpjb25maWcgPC0gY29uZmlnOjpnZXQoKQpjb24gPC0gZGJDb25uZWN0KAogIGRydiA9IFJQb3N0Z3JlU1FMOjpQb3N0Z3JlU1FMKCksCiAgZGJuYW1lID0gY29uZmlnJGRibmFtZSwKICBob3N0ID0gY29uZmlnJGhvc3QsCiAgcG9ydCA9IGNvbmZpZyRwb3J0LAogIHVzZXIgPSBjb25maWckdXNlciwKICBwYXNzd29yZCA9IGNvbmZpZyRwYXNzd29yZCwKICBvcHRpb24gPSBjb25maWckb3B0aW9uCikKc2VsZWN0ZWRfc2NoZW1hIDwtIHN0cl9yZW1vdmUoY29uZmlnJG9wdGlvbiwgcGF0dGVybiA9ICItYyBzZWFyY2hfcGF0aD0iKQpgYGAKCiMjIFQgY2VsbCBlcGl0b3BlIHRhYmxlCgpUaGUgdGFibGUgYmVsb3cgaXMgdGhlIG9yaWdpbmFsIGRvd25sb2FkZWQgdGFibGU6CgpgYGB7cn0KZiA8LSAiL3YvcHJvamVjdHMvZ2VubzJwaGVuby1rcGFwcC9kbmlldXcvTUhDSS1TcGlrZS1lcGl0b3Blcy50c3YiCmVwaXRvcGVfcmF3X3JlZiA8LSByZWFkX3RzdihmLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKVssIGMoMSw1LDYpXQpuYW1lcyhlcGl0b3BlX3Jhd19yZWYpIDwtIGMoImlkIiwgInJlZmVyZW5jZXMiLCAiYXNzYXlzIikKZXBpdG9wZV9yYXdfcmVmJGlkIDwtIGFzLmNoYXJhY3RlcihlcGl0b3BlX3Jhd19yZWYkaWQpCgpmIDwtICIvdi9wcm9qZWN0cy9nZW5vMnBoZW5vLWtwYXBwL2RuaWV1dy9NSENJLVNwaWtlLWVwaXRvcGVzX21ldGFkYXRhLnRzdiIKZXBpdG9wZV9yYXcgPC0gcmVhZF90c3YoZiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSlbMToxN10KbmFtZXMoZXBpdG9wZV9yYXcpIDwtIGMoImllZGJfaXJpIiwgIm9iamVjdF90eXBlIiwgIm5hbWUiLCAibW9kaWZpZWRfcmVzaWR1ZSIsIAogICAgICAgICAgICAgICAgICAgICJtb2RpZmljYXRpb25zIiwgInN0YXJ0IiwgImVuZCIsICJpcmkiLCAic3lub255bXMiLAogICAgICAgICAgICAgICAgICAgICJzb3VyY2VfbW9sZWN1bGUiLCAic291cmNlX21vbGVjdWxlX2lyaSIsICJtb2xlY3VsZV9wYXJlbnQiLAogICAgICAgICAgICAgICAgICAgICJtb2xlY3VsZV9wYXJlbnRfaXJpIiwgInNvdXJjZV9vcmdhbmlzbSIsCiAgICAgICAgICAgICAgICAgICAgInNvdXJjZV9vcmdhbmlzbV9pcmkiLCAic3BlY2llcyIsICJzcGVjaWVzX2lyaSIpCmVwaXRvcGVfcmF3IDwtIGVwaXRvcGVfcmF3ICU+JQogIHNlcGFyYXRlKGNvbCA9IGllZGJfaXJpLCBpbnRvID0gYyhOQSwgTkEsIE5BLCBOQSwgImlkIiksCiAgICAgICAgICAgc2VwID0gIi8iLCByZW1vdmUgPSBGQUxTRSkgJT4lCiAgaW5uZXJfam9pbihlcGl0b3BlX3Jhd19yZWYsIGJ5ID0gImlkIikgJT4lCiAgc2VsZWN0KGlkLCBuYW1lLCBzdGFydCwgZW5kLCByZWZlcmVuY2VzLCBhc3NheXMsIGV2ZXJ5dGhpbmcoKSkKICAKZXBpdG9wZV9yYXcKYGBgCiogVGFibGUgYWJvdmUgc2hvd3MgdGhhdCB0aGVyZSBhcmUgNjUzIGVwaXRvcGVzIGluIHRoZSByYXcgZXBpdG9wZSB0YWJsZQoKTmVlZCB0byBjb25jZW50cmF0ZSBvbmx5IHRob3NlIGVwaXRvcGVzIHRob3NlIHdlcmUgcHJlc2VudCBpbiBtb3JlIHRoYW4gMSBwcmVzZW50YXRpb24KCmBgYHtyfQplcGl0b3BlIDwtIGVwaXRvcGVfcmF3ICU+JQogIGZpbHRlcihyZWZlcmVuY2VzPjEpCmVwaXRvcGUKYGBgCiogVGhlcmUgYXJlIDE5MCBvdXQgb2YgNjUzIGVwaXRvcGVzIHRob3NlIHdlcmUgcHVibGlzaGVkIG1vcmUgdGhhbiBhIHNpbmdsZSBwYXBlcgoKYGBge3J9CmVwaXRvcGUlPiUKICBmaWx0ZXIoaXMubmEoc3RhcnQpKQpgYGAKKiBUaGVyZSBpcyBhIHNpbmdsZSBlcGl0b3BlIChgMTU5Mzg0OGApIHdoZXJlIHRoZSBzdGFydCBhbmQgZW5kIHBvc2l0aW9uIGlzIG1pc3NpbmcuIEJhc2VkIG9uIERhdmlkJ3MgYWxpZ25tZW50ICgiL3YvcHJvamVjdHMvZ2VubzJwaGVuby1rcGFwcC9kbmlldXcvTUhDSS1TcGlrZS1lcGl0b3Blc19hbGlnbmVkLmZhYSIpLCB0aGUgcG9zaXRpb24gb2YgdGhpcyBlcGl0b3BlIGlzIHNpbWlsYXIgdG8gaHR0cHM6Ly93d3cuaWVkYi5vcmcvZXBpdG9wZS8xMzA5MTQ3IGVwaXRvcGUuIFRoZXJlIGRpZmZlcmVuY2UgaXMgYSBzaW5nbGUgbXV0YXRpb24gYXQgYW1pbm8gYWNpZGUgbGV2ZWwuIFNvIHRoaXMgZXBpdG9wZSBkb2VzIG5vdCBkZXJpdmUgZnJvbSByZWZlcmVuY2Ugc2VxdWVuY2UgYnV0IHRoZSBzdGFydC1lbmQgcG9zaXRpb24gd2lsbCBiZSBpbmNsdWRlZCB0aGUgdGFibGU6CgoKYGBge3J9CmVwaXRvcGVbZXBpdG9wZSRpZD09IjE1OTM4NDgiLCAic3RhcnQiXSA8LSAyNjkKZXBpdG9wZVtlcGl0b3BlJGlkPT0iMTU5Mzg0OCIsICJlbmQiXSA8LSAyNzcKYGBgCgpOZWVkIHRvIGNoZWNrIGlmIGVwaXRvcGUgc2VxdWVuY2VzIGRlcml2ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIHNlcXVlbmNlLgoKVGhlIHJlZmVyZW5jZSBzZXF1ZW5jZSBpcyBoZXJlOiBodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L251Y2NvcmUvTU45MDg5NDcKU3Bpa2UgcHJvdGVpbiAoUUhENDM0MTYuMSkgaXMgY29kZWQgaW4gdGhlIHJlZmVyZW5jZSBzZXF1ZW5jZSBwb3NpdGlvbjogMjE1NjMtMjUzODQKCkRhdGFiYXNlIHdpbGwgYmUgc2VhcmNoZWQgZm9yIHRoZSByZWZlcmVuY2UgU3Bpa2UgcHJvdGVpbiBzZXF1ZW5jZToKCmBgYHtzcWwgY29ubmVjdGlvbj1jb24sIG91dHB1dC52YXI9c3Bpa2Vfc2VxfQpzZWxlY3QgKiBmcm9tIGRhdGFodWJfMC50cmFuc2xhdGVkX2FhX3JlZl9zZXF1ZW5jZSgyMTU2MywgMjUzODQpCmBgYAoKKiBOb3RlOiB0aGUgImRhdGFodWJfMC5iYXJjb2Rlc193aXRoX211dGF0aW9uX3Bvc2l0aW9ucyh7c3RhcnR9LCB7ZW5kfSkiIFNRTCBmdW5jdGlvbiB0cmFuc2xhdGUgdGhlIHJlZmVyZW5jZSBudWNsZW90aWRlIHNlcXVlbmNlIGludG8gcHJvdGVpbiBzZXF1ZW5jZSAodGhlIHBhcmFtZXRlcnMgYXJlIHRoZSBzdGFydCBhbmQgZW5kIHBvc2l0aW9ucyBvZiByZWZlcmVuY2UgbnVjbGVvdGlkZSBzZXF1ZW5jZSkKCmBgYHtyfQpzcGlrZV9zZXEgPC0gc3RyX2Moc3Bpa2Vfc2VxJGFhX3N5bWJvbCwgY29sbGFwc2UgPSAiIikKc3Bpa2Vfc2VxCmBgYAoKQ2hlY2sgaWYgdGhlIGBuYW1lYCBjb2x1bW4gb2YgdGhlIGVwaXRvcGUgdGFibGUgY29udGFpbnMgcmVhbGx5IHRoZSByZWZlcmVuY2Ugc2VxdWVuY2UuIAoKYGBge3J9CmZvciAoaSBpbiAxOm5yb3coZXBpdG9wZSkpIHsKICByZWYgPC0gc3RyX3N1YihzcGlrZV9zZXEsCiAgICAgICAgICAgICAgICAgc3RhcnQgPSBlcGl0b3BlW2ksICdzdGFydCddLAogICAgICAgICAgICAgICAgIGVuZCA9IGVwaXRvcGVbaSwgJ2VuZCddKQogIGlmIChlcGl0b3BlW2ksICduYW1lJ10gPT0gcmVmKSBlcGl0b3BlW2ksICdtYXRjaF93aXRoX3JlZiddIDwtIFRSVUUgZWxzZSBlcGl0b3BlW2ksICdtYXRjaF93aXRoX3JlZiddIDwtIEZBTFNFCn0KYGBgCgpMZXRzIHNlZSB0aGUgcmVzdWx0IG9mIHRoZSBjb21wYXJpc29uCgpgYGB7cn0KdGFibGUoZXBpdG9wZSRtYXRjaF93aXRoX3JlZikKYGBgClRoZXJlIGFyZSA2IGVwaXRvcGVzIHdoZXJlIHRoZSBgbmFtZWAgY29sdW1uIGRvZXMgbm90IG1hdGNoIHdpdGggdGhlIHJlZmVyZW5jZS4gCgpUaGVzZSBhcmUgdGhlIGVwaXRvcGVzIHRob3NlIGRvIG5vdCBtYXRjaCB3aXRoIHJlZmVyZW5jZSBzZXF1ZW5jZToKCmBgYHtyfQplcGl0b3BlW2VwaXRvcGUkbWF0Y2hfd2l0aF9yZWY9PUZBTFNFLF0KYGBgCgoqIFRoZXNlIGVwaXRvcGVzIGFib3ZlIGFyZSBpbXBvcnRhbnQgb25lLCBidXQgbm93IGZvciBzaW1wbGljaXR5IEkgd2lsbCBleGNsdWRlIHRoZW0sIGxhdGVyIHRoZXNlIGVwaXRvcGVzIHdpbGwgYmUgY2hlY2tlZC4KCiMjIyBUYWJsZSBvZiBUIGNlbGwgZXBpdG9wZXMgaW5jbHVkZWQgdGhlIGFuYWx5c2lzIHsjYTF9CgpUaGUgdGFibGUgYmVsb3cgY29udGFpbnMgdGhlIGVwaXRvcGVzIHRob3NlIGRlcml2ZWQgZnJvbSByZWZlcmVuY2Ugc2VxdWVuY2U6CgpgYGB7cn0KZXBpdG9wZV9zZWxlY3RlZCA8LSBlcGl0b3BlICU+JQogIGZpbHRlcihtYXRjaF93aXRoX3JlZikgCmVwaXRvcGVfc2VsZWN0ZWQKYGBgCiMjIyBQb3NpdGlvbiBvZiBlcGl0b3BlcyBvbiByZWZlcmVuY2Ugc3Bpa2Ugc2VxdWVuY2UgeyNhMn0KCgpgYGB7cn0KeCA8LSBlcGl0b3BlX3NlbGVjdGVkICU+JQogIHNlbGVjdChpZCwgc3RhcnQsIGVuZCkgJT4lCiAgbXV0YXRlKHN0YXJ0ID0gYXMubnVtZXJpYyhzdGFydCksCiAgICAgICAgIGVuZCA9IGFzLm51bWVyaWMoZW5kKSkgJT4lCiAgYXJyYW5nZShzdGFydCkKeCR5IDwtIDE6bnJvdyh4KQp4IDwtIHggJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydDplbmQsIHZhbHVlc190byA9ICJ4IikKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSB4LCBhZXMoeCA9IHgsIHkgPSB5LCBmaWxsID0gaWQpKSArCiAgZ2VvbV9saW5lKGFscGhhID0gMC40KSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgVC1jZWxsIGVwaXRvcGVzIG9uIHNwaWtlIHByb3RlaW4iLAogICAgICAgeCA9ICJBbWlubyBhY2lkZSBwb3NpdGlvbiIsCiAgICAgICB5ID0gIiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGFzcGVjdC5yYXRpbz0yLzYpCmBgYAoqIEVhY2ggc2hvcnQgaG9yaXpvbnRhbCBsaW5lIHJlcHJlc2VudCBhIFQgY2VsbCBlcGl0b3BlCgojIyBCYXJjb2RlIHRhYmxlCgpCYXJjb2RlIHdhcyBhc3NpZ25lZCB0byBlYWNoIHNhbXBsZXMuIEEgZ2l2ZW4gYmFyY29kZSBpcyBiYXNpY2FsbHkgYSBtdXRhdGlvbiBwYXR0ZXJuIChhbWlubyBhY2lkZSBsZXZlbCkgb2YgUyBwcm90ZWluLgoKSG93IG1hbnkgZGlmZmVyZW50IFMgcHJvdGVpbiBleGlzdCBub3cgaW4gdGhlIGRhdGFiYXNlPwoKYGBge3NxbCBjb25uZWN0aW9uPWNvbn0KU0VMRUNUIGNvdW50KCopCkZST00gYmFyY29kZQpgYGAKCgoqIFRoZXJlIGFyZSAzNDY5NzYgYmFyY29kZXMgaW4gdGhlIGRhdGFiYXNlLgoKSSB3aWxsIHVzZSBvbmx5IHRob3NlIGJhcmNvZGVzIHRoYXQgd2VyZSBhc3NpZ25lZCB0byBtb3JlIHRoYW4gMTAwIHNhbXBsZXM6CgpgYGB7c3FsIGNvbm5lY3Rpb249Y29uLCBvdXRwdXQudmFyID0gImJhcmNvZGVfaGlzdCJ9CldJVEggYmFyY29kZV9kaXN0IEFTICgKICAgICBTRUxFQ1QgYmFyY29kZV9pZCwgY291bnQoKikgQVMgc2FtcGxlX251bWJlcl9pbl9iYWNvZGUKICAgICAgICAgIEZST00gYWFfbXV0YXRpb25fbmV3IEFTIGEKICAgICAgICAgIEdST1VQIEJZIGEuYmFyY29kZV9pZAopCgpTRUxFQ1Qgc2FtcGxlX251bWJlcl9pbl9iYWNvZGUsIGNvdW50KCopIEFTIG51bWJlcl9vZl9iYXJjb2RlCiAgICAgRlJPTSBiYXJjb2RlX2Rpc3QKICAgICBHUk9VUCBCWSBzYW1wbGVfbnVtYmVyX2luX2JhY29kZQogICAgIE9SREVSIEJZIG51bWJlcl9vZl9iYXJjb2RlIERFU0MKYGBgCgpgYGB7cn0KYmFyY29kZV9oaXN0ICU+JQogIGZpbHRlcihzYW1wbGVfbnVtYmVyX2luX2JhY29kZSA+IDEwMCkgJT4lCiAgc3VtbWFyaXNlKGBOdW1iZXIgb2YgYmFyY29kZXNgID0gc3VtKG51bWJlcl9vZl9iYXJjb2RlKSkKYGBgCgpUaGVyZSBhcmUgMTk3MiBiYXJjb2RlcyB0aGF0IGFwcGVhcmVkIG1vcmUgdGhhbiAxMDAgc2FtcGxlcyBpbiB0aGUgZGF0YWJhc2UuIAoKCmBgYHtyfQpiYXJjb2RlX2hpc3QgJT4lCiAgZmlsdGVyKHNhbXBsZV9udW1iZXJfaW5fYmFjb2RlID4gMTAwKSAlPiUKICBzdW1tYXJpc2UoYE51bWJlciBvZiBzYW1wbGVzIGJlbG9uZ3MgdG8gdGhlIHNlbGVjdGVkIGJhcmNvZGVzYCA9IHN1bShzYW1wbGVfbnVtYmVyX2luX2JhY29kZSkpCmBgYAoqIEFyb3VuZCAxLjggbWlsbGlvbiBzYW1wbGVzIHdpbGwgYmUgaW5jbHVkZWQgaW50byB0aGlzIGFuYWx5c2lzCgpMaXN0IG9mIGJhcmNvZGVzIHRoYXQgd2lsbCBiZSBpbmNsdWRlZCB0aGlzIGFuYWx5c2lzOgoKYGBge3NxbCBjb25uZWN0aW9uPWNvbiwgb3V0cHV0LnZhciA9ICJiYXJjb2RlcyJ9CldJVEggYmFyY29kZV9kaXN0IEFTICgKICAgICBTRUxFQ1QgYmFyY29kZV9pZCwgY291bnQoKikgQVMgc2FtcGxlX251bWJlcl9pbl9iYWNvZGUKICAgICAgICAgIEZST00gYWFfbXV0YXRpb25fbmV3IEFTIGEKICAgICAgICAgIEdST1VQIEJZIGEuYmFyY29kZV9pZAopCgpTRUxFQ1QgYmFyY29kZV9pZCwgc2FtcGxlX251bWJlcl9pbl9iYWNvZGUsIGFhX211dGF0aW9uCiAgICAgRlJPTSBiYXJjb2RlX2Rpc3QKICAgICBMRUZUIEpPSU4gYmFyY29kZSBPTiBiYXJjb2RlLmlkPWJhcmNvZGVfZGlzdC5iYXJjb2RlX2lkCiAgICAgV0hFUkUgYmFyY29kZV9kaXN0LnNhbXBsZV9udW1iZXJfaW5fYmFjb2RlID4gMTAwCmBgYAoKSGVhZCBvZiB0aGUgdGFibGU6CmBgYHtyfQpoZWFkKGJhcmNvZGVzKQpgYGAKCiMjIE1hdGNoIGJhcmNvZGVzIHdpdGggVCBjZWxsIGVwaXRvcGVzCgpgYGB7cn0KbXV0YXRpb24gPC0gYmFyY29kZXMgJT4lCiAgbXV0YXRlKG11dCA9IGFhX211dGF0aW9uKSAlPiUKICBtdXRhdGUobXV0ID0gc3RyX3JlbW92ZShtdXQsIHBhdHRlcm4gPSAiXFx7IiksCiAgICAgICAgIG11dCA9IHN0cl9yZW1vdmUobXV0LCBwYXR0ZXJuID0gIlxcfSIpLAogICAgICAgICBtdXQgPSBzdHJfcmVtb3ZlX2FsbChtdXQsIHBhdHRlcm4gPSAicFxcLiIpKSAlPiUKICBtdXRhdGUobiA9IChzdHJfY291bnQobXV0LCBwYXR0ZXJuID0gIiwiKSArIDEpKQoKbWF4X211dCA8LSBtYXgobXV0YXRpb24kbikKaWRzIDwtIHN0cl9jKCJ4IiwgMTptYXhfbXV0KQoKbXV0YXRpb248LSBtdXRhdGlvbiU+JQogIHNlcGFyYXRlKG11dCwgaW50byA9IGlkcywgc2VwID0gIiwiLCBmaWxsICA9ICJyaWdodCIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYWxsX29mKGlkcyksIHZhbHVlc190byA9ICJtdXQiLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJtdXRfcG9zX2luX2JhcmNvZGUiKSAlPiUKICBkcm9wX25hKG11dCkgJT4lCiAgbXV0YXRlKHBvcyA9IGFzLm51bWVyaWMoc3RyX3N1YihtdXQsIHN0YXJ0ID0gNCwgZW5kID0gLTQpKSkKCmhlYWQobXV0YXRpb24pCmBgYAoKKiBUYWJsZSBhYm92ZSBzaG93cyB0aGUgcG9zaXRpb25zIG9mIG11dGF0aW9ucyBpbiB0aGUgc2VsZWN0ZWQgYmFyY29kZXMuCgpTZWxlY3QgdGhvc2UgZXBpdG9wZXMgd2hlcmUgc3RhcnQtZW5kIHBvc2l0aW9uIGluY2x1ZGVzIGFueSBvZiB0aGUgbXV0YXRpb24gcG9zaXRpb25zIGFib3ZlLgoKYGBge3J9Cm11dGF0aW9uX2FsbCA8LSB0aWJibGUoYmFyY29kZV9pZCA9IGludGVnZXIoKSwKICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfbnVtYmVyX2luX2JhY29kZSA9IG51bWVyaWMoKSwKICAgICAgICAgICAgICAgICAgICAgICBhYV9tdXRhdGlvbiA9IGNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICAgICAgIG4gPSBudW1lcmljKCksCiAgICAgICAgICAgICAgICAgICAgICAgbXV0X3Bvc19pbl9iYXJjb2RlID0gY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgICAgICAgbXV0ID0gY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgICAgICAgcG9zID0gbnVtZXJpYygpLAogICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gbnVtZXJpYygpLAogICAgICAgICAgICAgICAgICAgICAgIGVuZCA9IG51bWVyaWMoKSwKICAgICAgICAgICAgICAgICAgICAgICBpZWRiX2lkPSBjaGFyYWN0ZXIoKSkKCmZvciAoaSBpbiByb3cubmFtZXMoZXBpdG9wZV9zZWxlY3RlZCkpIHsKICB4IDwtIG11dGF0aW9uICU+JQogICAgbXV0YXRlKHN0YXJ0ID0gYXMubnVtZXJpYyhlcGl0b3BlX3NlbGVjdGVkW2ksICJzdGFydCJdKSwKICAgICAgICAgICBlbmQgPSBhcy5udW1lcmljKGVwaXRvcGVfc2VsZWN0ZWRbaSwgImVuZCJdKSwKICAgICAgICAgICBpZWRiX2lkID0gYXMuY2hhcmFjdGVyKGVwaXRvcGVfc2VsZWN0ZWRbaSwgImlkIl0pKSAlPiUKICAgIG11dGF0ZShpc19tdXRhdGlvbl9wcmVzZW50ID0gaWZlbHNlKChwb3MgPj0gc3RhcnQgJiBwb3MgPD0gZW5kKSwgVFJVRSwgRkFMU0UpKSAlPiUKICAgIGZpbHRlcihpc19tdXRhdGlvbl9wcmVzZW50KSAlPiUKICAgIHNlbGVjdCgtaXNfbXV0YXRpb25fcHJlc2VudCkKICBtdXRhdGlvbl9hbGwgPC0gbXV0YXRpb25fYWxsICU+JQogICAgYWRkX3Jvdyh4KQp9CmBgYAoKYGBge3J9Cm11dGF0aW9uX2FsbF9tb2QgPC0gbXV0YXRpb25fYWxsICU+JQogIG11dGF0ZShyZWZfZXBpdG9wZSA9IHN0cl9zdWIoc3Bpa2Vfc2VxLCBzdGFydCA9IHN0YXJ0LCBlbmQgPSBlbmQpKSAlPiUKICBzZWxlY3QoLW11dF9wb3NfaW5fYmFyY29kZSkgJT4lCiAgc2VsZWN0KC1wb3MpCgp4IDwtIG11dGF0aW9uX2FsbF9tb2QgJT4lCiAgc2VsZWN0KC1tdXQpICU+JQogIHNlbGVjdCgtbikgJT4lCiAgZGlzdGluY3QoKQoKbXV0YXRpb25fZmluIDwtIG11dGF0aW9uX2FsbF9tb2QgJT4lCiAgc2VsZWN0KGJhcmNvZGVfaWQsIGllZGJfaWQsIG11dCkgJT4lCiAgZ3JvdXBfYnkoYmFyY29kZV9pZCwgaWVkYl9pZCkgJT4lCiAgc3VtbWFyaXplKG11dGF0aW9uX2xpc3QgPSBzdHJfYyhtdXQsIGNvbGxhcHNlID0gIiwiKSkgJT4lCiAgaW5uZXJfam9pbih4LCBieSA9IGMoImJhcmNvZGVfaWQiLCAiaWVkYl9pZCIpKSAlPiUKICBtdXRhdGUobXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0FsYScsIHJlcGxhY2VtZW50ID0gJ0EnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0FyZycsIHJlcGxhY2VtZW50ID0gJ1InKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0FzbicsIHJlcGxhY2VtZW50ID0gJ04nKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0FzcCcsIHJlcGxhY2VtZW50ID0gJ0QnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0N5cycsIHJlcGxhY2VtZW50ID0gJ0MnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0dsbicsIHJlcGxhY2VtZW50ID0gJ1EnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0dsdScsIHJlcGxhY2VtZW50ID0gJ0UnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0hpcycsIHJlcGxhY2VtZW50ID0gJ0gnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0lsZScsIHJlcGxhY2VtZW50ID0gJ0knKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0xldScsIHJlcGxhY2VtZW50ID0gJ0wnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0x5cycsIHJlcGxhY2VtZW50ID0gJ0snKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ01ldCcsIHJlcGxhY2VtZW50ID0gJ00nKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ1BoZScsIHJlcGxhY2VtZW50ID0gJ0YnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ1BybycsIHJlcGxhY2VtZW50ID0gJ1AnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ1NlcicsIHJlcGxhY2VtZW50ID0gJ1MnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ1RocicsIHJlcGxhY2VtZW50ID0gJ1QnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ1RycCcsIHJlcGxhY2VtZW50ID0gJ1cnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ1R5cicsIHJlcGxhY2VtZW50ID0gJ1knKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ1ZhbCcsIHJlcGxhY2VtZW50ID0gJ1YnKSwKICAgICAgICAgbXV0YXRpb25fbGlzdCA9IHN0cl9yZXBsYWNlX2FsbChtdXRhdGlvbl9saXN0LCBwYXR0ZXJuID0gJ0dseScsIHJlcGxhY2VtZW50ID0gJ0cnKQogICAgICAgICApCmBgYAoKCmBgYHtyfQpmb3IgKGkgaW4gcm93Lm5hbWVzKG11dGF0aW9uX2ZpbikpewogIG11dF9saXN0IDwtIHVubGlzdChzdHJzcGxpdChhcy5jaGFyYWN0ZXIobXV0YXRpb25fZmluW2ksICJtdXRhdGlvbl9saXN0Il0pLCAiLCIpKQogIG11dGF0aW9uX2ZpbltpLCAibXV0X2VwaXRvcGUiXSA8LSBtdXRhdGlvbl9maW5baSwgInJlZl9lcGl0b3BlIl0KICBmb3IgKGogaW4gbXV0X2xpc3QpIHsKICAgIHJlcGxhY2VtZW50X3BvcyA8LSBhcy5udW1lcmljKHN0cl9zdWIoaiwgc3RhcnQgPSAyLCBlbmQgPSAtMikpIC0gYXMubnVtZXJpYyhtdXRhdGlvbl9maW5baSwgInN0YXJ0Il0pICsxCiAgICByZXBsYWNlbWVudF9BQSA8LSBzdHJfc3ViKGosIHN0YXJ0ID0gLTEsIGVuZCA9IC0xKQogICAgbXV0YXRpb25fZmluW2ksICJtdXRfZXBpdG9wZSJdIDwtIHN0cl9jKHN0cl9zdWIobXV0YXRpb25fZmluW2ksICJtdXRfZXBpdG9wZSJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kID0gKHJlcGxhY2VtZW50X3BvcyAtIDEpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudF9BQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfc3ViKG11dGF0aW9uX2ZpbltpLCAibXV0X2VwaXRvcGUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gKHJlcGxhY2VtZW50X3BvcyArIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kID0gLTEpKQogIH0KfQpoZWFkKG11dGF0aW9uX2ZpbikKYGBgCgpUaGVyZSBhcmUgMzgxNTUgbXV0YXRlZCBlcGl0b3BlcyBpbiB0aGUgdGFibGUgYWJvdmUsIGJ1dCBtYW55IG9mIHRoZW0gYXBwZWFyIGluIG1vcmUgdGhhbiBvbmUgdGltZXMgKGlmIHRoZSBzYW1lIG11dGF0ZWQgZXBpdG9wZSBhcHBlYXJzIGluIG1vcmUgdGhhbiBvbmUgYmFyY29kZSwgdGhlbiBpdCBpdCB3aWxsIGJlIHByZXNlbnQgbW9yZSB0aGFuIG9uZSByb3cpIAoKIyMjIE11dGF0ZWQgZXBpdG9wZSB0YWJsZSB7I2EzfQoKYGBge3J9Cm11dGF0ZWRfZXBpdG9wZV90YWJsZSA8LSBtdXRhdGlvbl9maW4gJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChpZWRiX2lkLCByZWZfZXBpdG9wZSwgbXV0X2VwaXRvcGUpICU+JQogIGRpc3RpbmN0KCkKbXV0YXRlZF9lcGl0b3BlX3RhYmxlICAKYGBgCiogVGhlIHRhYmxlIGFib3ZlIGNvbnRhaW5zIDkzNSBtdXRhdGVkIGVwaXRvcGVzLiBUaGlzIGlzIHRoZSBmaW5hbCBsaXN0LCB0aGVzZSBuZWVkIHRvIGJlIGNoZWNrZWQgaWYgdGhlaXIgYmluZGluZyBhZmZpbml0eSBjaGFuZ2VzIGFzIGEgcmVzdWx0IG9mIG11dGF0aW9uCgoKYGBge3J9CndyaXRlX3RzdihtdXRhdGVkX2VwaXRvcGVfdGFibGUsIGZpbGUgPSAiL3YvcHJvamVjdHMvZ2VubzJwaGVuby1rcGFwcC9rcGFwcC90X2NlbGxfZXBpdG9wL2RhdGEvbXV0YXRlZF9lcGl0b3Blcy50c3YiKQpgYGAKCmBgYHtyfQp3cml0ZV90c3YobXV0YXRpb25fZmluLCBmaWxlID0gIi92L3Byb2plY3RzL2dlbm8ycGhlbm8ta3BhcHAva3BhcHAvdF9jZWxsX2VwaXRvcC9kYXRhL211dGF0ZWRfZXBpdG9wZXNfYmFyY29kZXMudHN2IikKYGBgCgpgYGB7cn0Kd3JpdGVfdHN2KG11dGF0aW9uX2FsbCwgZmlsZSA9ICIvdi9wcm9qZWN0cy9nZW5vMnBoZW5vLWtwYXBwL2twYXBwL3RfY2VsbF9lcGl0b3AvZGF0YS9tdXRhdGVkX2VwaXRvcGVzX2JhcmNvZGVzX2FsbC50c3YiKQpgYGAKCgoKCgoKCg==