ALL IMPORTED FILES MUST BE IN THE SAME DIRECTORY AS THIS SCRIPT

Load tidyverse package

library(tidyverse)

Import raw vcf data from “masterfile” and exclude variants with GnomAD non-cancer AF > 0.005

masterfile <- read.delim("masterfile_181009_exomes_with_missing_regions_gnomad2.1_rare_variants_loftee_GnomAD3_canonical_refseq_or_LRG_consequence_4-6.tsv", header=TRUE, row.names=NULL, na.strings = ".", stringsAsFactors=FALSE) %>% 
  dplyr::rename("Sample"="X.Sample") 
  
masterfile_rare_non_cancer <- filter(masterfile, GnomAD_v2.1_non_cancer_AF_nfe<=0.005)

Exclude non-epithelial, uterine-only and BRCA +ve samples + non-NFE samples

sample_ethnicities <- read.delim("exomes_pca_with_gnomad_info.tsv", stringsAsFactors=FALSE)
NFE_samples <- filter(sample_ethnicities, GnomAD_class%in%"European")

ViP_Complete_Cohort <- read.delim("ViP_LoF_Complete_Cohort.txt", stringsAsFactors=FALSE)
ViP_Complete_Cohort_list_NFE <- filter(ViP_Complete_Cohort,Exome.ID%in%c(NFE_samples$Sample))

masterfile_eoc <- filter(masterfile_rare_non_cancer,Sample%in%c(ViP_Complete_Cohort_list_NFE$Exome.ID)) %>% 
  filter(Sample%in%(NFE_samples$Sample)) %>%
  filter(GnomAD_v2.1_non_cancer_AF_nfe<=0.005)

rm(masterfile)

Append patient path data

ViP_OvCa_Path_Data <- read.delim("ViP_OvCa_Path_Data.txt", header=TRUE, row.names=NULL, stringsAsFactors=FALSE) %>% 
  dplyr::rename("Sample"=Exome.ID)
masterfile_eoc_withPath <- left_join(masterfile_eoc,ViP_OvCa_Path_Data,by="Sample",copy=FALSE)

rm(ViP_OvCa_Path_Data)
rm(masterfile_eoc)

Exclude low-quality variants and GnomAD RF/InbreedingCoeff-flagged variants

masterfile_eoc_goodQ <- filter(masterfile_eoc_withPath, (QUAL>=30)&
                                 (Identified!="FilteredInAll")&
                                 (Sample.PMCDP>=10)&
                                 (Sample.PMCFREQ>=0.25)) %>% 
                                 filter((!str_detect(GnomAD_v2.1_FILTER_exome,"InbreedingCoeff")&
                                           !str_detect(GnomAD_v2.1_FILTER_exome,"RF"))|
                                       is.na(GnomAD_v2.1_FILTER_exome)) %>% 
  filter((!str_detect(GnomAD_v2.1_FILTER_genome,"InbreedingCoeff")&
            !str_detect(GnomAD_v2.1_FILTER_genome,"RF"))|
           is.na(GnomAD_v2.1_FILTER_genome))

rm(masterfile_eoc_withPath)

Exclude other mutation +ve samples (MLH1/MSH2/MSH6/PMS2, TP53, RAD51C/D, BRIP1)

ViP_Discovery_Cohort <- read.delim("ViP_LoF_Discovery_Cohort.txt", stringsAsFactors=FALSE)
ViP_Discovery_Cohort_list <- ViP_Discovery_Cohort[,1]

masterfile_eoc_goodQ2 <- filter(masterfile_eoc_goodQ,Sample%in%c(ViP_Discovery_Cohort_list))

Exclude HIGH and MODERATE impact variants

masterfile_eoc_goodQ2_LOW <- filter(masterfile_eoc_goodQ2, IMPACT%in%"LOW")

rm(masterfile_eoc_goodQ2)

Exclude non-synonymous variants

masterfile_eoc_goodQ2_LOW_synonymous_NoLOFTEE <- filter(masterfile_eoc_goodQ2_LOW,Consequence%in%c("synonymous_variant","synonymous_variant,NMD_transcript_variant")) %>% 
  filter(!LoF%in%c("HC","LC"))

rm(masterfile_eoc_goodQ2_LOW)

Separate Ensembl canonical and RefSeq canonical variants

masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical <- filter(masterfile_eoc_goodQ2_LOW_synonymous_NoLOFTEE,CANONICAL%in%"YES") 

Sample variant counts and AFs

variants_heterozygous <- masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical %>% 
  select(HGVSc,Sample.GT) %>% 
  group_by(HGVSc,Sample.GT) %>% 
  summarise(n()) %>% 
  filter((Sample.GT%in%c("'0/1","'1/0"))) %>% 
  rename(alleles = "n()") %>% 
  group_by(HGVSc) %>% 
  summarise(sum(alleles))
variants_homozygous <- masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical %>% 
  select(HGVSc,Sample.GT) %>% 
  group_by(HGVSc,Sample.GT) %>% 
  summarise(n()) %>% 
  filter((Sample.GT!="'0/1")&(Sample.GT!="'1/0")) %>% 
  mutate(alleles = `n()`*2) %>% 
  select(-`n()`) %>% 
  group_by(HGVSc) %>% 
  summarise(sum(alleles))
variants <- full_join(variants_heterozygous,variants_homozygous,by="HGVSc",copy=FALSE,suffix=c(".x",".y")) %>%
  mutate_all(funs(replace(., is.na(.), 0))) %>% 
  mutate(Total_Allele_Count=`sum(alleles).x`+`sum(alleles).y`) %>% 
  mutate(Sample_AF=Total_Allele_Count/(n_distinct(masterfile_eoc_goodQ2_LOW_synonymous_NoLOFTEE$Sample)*2))
masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_2 <- left_join(masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical,variants[,c(1,4:5)],by="HGVSc",copy=FALSE)

Exclude variants with sample AF >0.01

masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01 <- filter(masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_2,Sample_AF < 0.01)

Output list of genes and variants with sample AF >0.01

masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_genesandvariants0.01 <- filter(masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_2,Sample_AF > 0.01)
masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_genesandvariants0.01[,c(2:6,25:54)] %>% 
  distinct(.keep_all = FALSE) %>% 
  write_excel_csv(path="masterfile_eoc_goodQ_0.001_LOW_synonymous_NoLOFTEE_ENSTcanonical_genesandvariants0.01.csv",na=".",append=FALSE,col_names=TRUE)

Sample gene counts and frequencies

genes_oneVarAllele <- masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01 %>% select(Gene,Sample.GT) %>% 
  select(Gene,Sample.GT) %>% 
  group_by(Gene,Sample.GT) %>% 
  summarise(n()) %>% 
  filter((Sample.GT%in%c("'0/1","'1/0"))) %>% 
  rename(gene_Var = "n()") %>% 
  group_by(Gene) %>% 
  summarise(sum(gene_Var))
genes_twoVarAllele <- masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01 %>% select(Gene,Sample.GT) %>% 
  select(Gene,Sample.GT) %>% 
  group_by(Gene,Sample.GT) %>% 
  summarise(n()) %>% 
  filter((Sample.GT!="'0/1")&(Sample.GT!="'1/0")) %>% 
  mutate(gene_Var = `n()`*2) %>% 
  select(-`n()`) %>% 
  group_by(Gene) %>% 
  summarise(sum(gene_Var))
genes <- full_join(genes_oneVarAllele,genes_twoVarAllele,by="Gene",copy=FALSE,suffix=c(".x",".y")) %>% 
  mutate_all(funs(replace(., is.na(.), 0))) %>% 
  mutate(Total_Gene_Count=`sum(gene_Var).x`+`sum(gene_Var).y`) %>% 
  mutate(Sample_Gene_Freq=Total_Gene_Count/(n_distinct(masterfile_eoc_goodQ2_LOW_synonymous_NoLOFTEE$Sample)*2))
masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_2 <- left_join(masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01, genes[,c(1,4:5)],by="Gene",copy=FALSE)

Add GnomAD gene-level data

ensembl_biotypes <- read.delim("ensembl_biotypes.tsv", stringsAsFactors=FALSE) %>% 
  select(ensembl_transcript_id,transcript_biotype) %>% 
  dplyr::rename("Feature"="ensembl_transcript_id","BIOTYPE"="transcript_biotype")

all_features_exons_only_fraction_covered_agilent_v6_base_figures <- read.delim("~/all_features_exons_only_fraction_covered_agilent_v6_150bp_extended.tsv")

gnomad_coverage_coding_features <- read.delim("~/gnomad_coverage_coding_features.tsv") %>% 
  mutate("total_10x_non_cancer_count"=((exome_10x)*56885)+((genome_10x)*7718)) %>% 
  mutate("total_10x_non_cancer_NFE_count"=((exome_10x)*51377)+((genome_10x)*7718))
gnomad_coverage_coding_features$total_10x_non_cancer_count=round(gnomad_coverage_coding_features$total_10x_non_cancer_count)
gnomad_coverage_coding_features$total_10x_non_cancer_NFE_count=round(gnomad_coverage_coding_features$total_10x_non_cancer_NFE_count)

GnomAD_stats_synonymous_VEP_NO_RF <- read.delim("agilent_v6_gnomad_v2.1.1_genestats_canonical_SYN_noLOFTEE.tsv", header=TRUE, row.names=NULL, stringsAsFactors=FALSE) %>% 
  left_join(ensembl_biotypes,by="Feature",copy=FALSE) %>% 
  filter(BIOTYPE%in%c("protein_coding")) %>% 
  distinct(.keep_all = FALSE) %>% 
  left_join(all_features_exons_only_fraction_covered_agilent_v6_base_figures[,c(1,4)],by="Feature",copy=FALSE) %>% 
  left_join(gnomad_coverage_coding_features[,c(1,6,7)],by="Feature",copy=FALSE)
  
masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_withGnomADstats <- left_join(masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_2, GnomAD_stats_synonymous_VEP_NO_RF[,c(2,20:25,27:29)],by="Feature",copy=FALSE)
masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_withGnomADstats2 <- mutate_at(masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_withGnomADstats,vars(starts_with("FILTER_")),funs(replace(., is.na(.), 0))) %>% 
  mutate_if(grepl("popmax$", names(.)),funs(ifelse(. == "NA", 0, as.numeric(.)))) %>% 
  mutate_at(vars(ends_with("popmax")),funs(replace(., is.na(.), 0)))

Create data frames with Agilent SureSelect whole exome genes (all ENST, protein-coding only and non-protein-coding)

GnomAD_stats_AgilentSSv6_list <-  read.delim("agilent_v6_gnomad_v2.1.1_genestats_canonical_SYN_noLOFTEE.tsv", header=TRUE, row.names=NULL, stringsAsFactors=FALSE) %>% 
  filter(CANONICAL=="YES") %>% 
  distinct(.keep_all = FALSE) %>% 
  select(SYMBOL:ENSP)

GnomAD_stats_AgilentSSv6_SYN_NO_LOFTEE_VEP_ENSTcanonical_protein_coding <- filter(GnomAD_stats_synonymous_VEP_NO_RF,Feature%in%c(GnomAD_stats_AgilentSSv6_list$Feature)) %>% 
  dplyr::rename("Gene"="ENSG") %>% 
  filter(BIOTYPE%in%c("protein_coding")) %>% 
  distinct(.keep_all = FALSE)

allGenes_AgilentSSv6_list_protein_coding_only <- tibble("SYMBOL"=GnomAD_stats_AgilentSSv6_SYN_NO_LOFTEE_VEP_ENSTcanonical_protein_coding$SYMBOL,"Gene"=GnomAD_stats_AgilentSSv6_SYN_NO_LOFTEE_VEP_ENSTcanonical_protein_coding$Gene,"Feature"=GnomAD_stats_AgilentSSv6_SYN_NO_LOFTEE_VEP_ENSTcanonical_protein_coding$Feature) %>% 
  distinct(.keep_all=TRUE) %>% 
  arrange(SYMBOL)

allGenes_masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_biotype_list <- tibble("SYMBOL"=masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_withGnomADstats2$SYMBOL,"Gene"=masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_withGnomADstats2$Gene,"BIOTYPE"=masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_withGnomADstats2$BIOTYPE) %>% 
  distinct(.keep_all=TRUE) %>% 
  filter(BIOTYPE%in%c("protein_coding")) %>% 
  arrange(SYMBOL)

comparison_sampleAF0.01_biotype_allGenes <- masterfile_eoc_goodQ_0.005_LOW_synonymous_NoLOFTEE_ENSTcanonical_sampleAF0.01_withGnomADstats2 %>% 
  mutate(Total_Case_Bases=(n_distinct(masterfile_eoc_goodQ2_LOW_synonymous_NoLOFTEE$Sample)*2*Total_Bases_Covered)) %>% 
  filter(BIOTYPE%in%c("protein_coding")) %>% 
  select(SYMBOL,Gene,Total_Gene_Count,Total_Case_Bases) %>% 
  distinct(SYMBOL,Gene,Total_Gene_Count,Total_Case_Bases) 
comparison_sampleAF0.01_biotype_allGenes2 <- bind_rows(comparison_sampleAF0.01_biotype_allGenes, anti_join(allGenes_AgilentSSv6_list_protein_coding_only,comparison_sampleAF0.01_biotype_allGenes,by="Gene")) %>% 
  mutate_at(vars("Total_Gene_Count"),funs(replace(., is.na(.), 0)))
comparison_sampleAF0.01_biotype_allGenes3 <- right_join(
  comparison_sampleAF0.01_biotype_allGenes2,
  GnomAD_stats_AgilentSSv6_SYN_NO_LOFTEE_VEP_ENSTcanonical_protein_coding,
  by="Gene",copy=FALSE) %>% 
  mutate_at(vars("Total_Case_Bases"),funs(replace(., is.na(.), n_distinct(masterfile_eoc_goodQ2_LOW_synonymous_NoLOFTEE$Sample)*2*Total_Bases_Covered))) %>% 
  select("SYMBOL.x","Gene","Total_Gene_Count","Total_Case_Bases","FILTER_RF_SYN_NO_LOFTEE_AC_0.005","FILTER_RF_SYN_NO_LOFTEE_AC_0.005_NFE","Total_Bases_Covered","total_10x_non_cancer_count","total_10x_non_cancer_NFE_count") %>% 
  dplyr::rename("SYMBOL"="SYMBOL.x") %>% 
  mutate("Total_GnomAD_Bases"=total_10x_non_cancer_count*2*Total_Bases_Covered) %>% 
  mutate("Total_GnomAD_NFE_Bases"=total_10x_non_cancer_NFE_count*2*Total_Bases_Covered) %>% 
  filter(Total_Bases_Covered!=0) %>% 
  distinct(.keep_all=TRUE)

Calculate total LoF variants in sample vs total LoF variants in GnomAD non-cancer NFE and use for chi-squared test

oddsratio <- function (a, b = NULL, c = NULL, d = NULL, conf.level = 0.95, 
    p.calc.by.independence = TRUE) 
{
    if (is.matrix(a)) {
        if ((dim(a)[1] != 2L) | (dim(a)[2] != 2L)) {
            stop("Input matrix must be a 2x2 table.")
        }
        .a <- a[1, 1]
        .b <- a[1, 2]
        .c <- a[2, 1]
        .d <- a[2, 2]
        .data.name <- deparse(substitute(a))
    }
    else {
        .a <- a
        .b <- b
        .c <- c
        .d <- d
        .data.name <- paste(deparse(substitute(a)), deparse(substitute(b)), 
            deparse(substitute(c)), deparse(substitute(d)))
    }
    .MAT <- matrix(c(.a, .b, M1 <- .a + .b, .c, .d, M0 <- .c + 
        .d, N1 <- .a + .c, N0 <- .b + .d, Total <- .a + .b + 
        .c + .d), 3, 3)
    colnames(.MAT) <- c("Sample", "GnomAD", "Total") #("Disease", "Nondisease", "Total")
    rownames(.MAT) <- c("Syn", "No Syn", "Total") #("Exposed", "Nonexposed", "Total")
    class(.MAT) <- "table"
    print(.MAT)
    ESTIMATE <- (.a /.b)/(.c/.d)
    norm.pp <- qnorm(1 - (1 - conf.level)/2)
    if (p.calc.by.independence) {
        p.v <- 2 * (1 - pnorm(abs((.a - N1 * M1/Total)/sqrt(N1 * 
            N0 * M1 * M0/Total/Total/(Total - 1)))))
    }
    else {
        p.v <- 2 * (1 - pnorm(log(ifelse(ESTIMATE > 1, ESTIMATE, 
            1/ESTIMATE))/sqrt(1/.a + 1/.b + 1/.c + 1/.d)))
    }
    ORL <- ESTIMATE * exp(-norm.pp * sqrt(1/.a + 1/.b + 1/.c + 
        1/.d))
    ORU <- ESTIMATE * exp(norm.pp * sqrt(1/.a + 1/.b + 1/.c + 
        1/.d)) %>% signif(digits=7)
    CINT <- paste(signif(ORL,digits = 7),signif(ORU,digits = 7),sep="~")
    attr(CINT, "conf.level") <- conf.level
    RVAL <- list(p.value = p.v, conf.int = CINT, estimate = ESTIMATE, 
        method = "Odds ratio estimate and its significance probability", 
        data.name = .data.name)
    class(RVAL) <- "htest"
    return(RVAL)
}

a <- sum(comparison_sampleAF0.01_biotype_allGenes3$Total_Gene_Count) %>% as.numeric()
b <- n_distinct(masterfile_eoc_goodQ2_LOW_synonymous_NoLOFTEE$Sample)*2*33218304 %>% as.numeric()
b1 <- b-a %>% as.numeric()
c <- sum(comparison_sampleAF0.01_biotype_allGenes3$FILTER_RF_SYN_NO_LOFTEE_AC_0.005) %>% as.numeric()
d <- (30651075*2*118479)+(32482680*2*15708) %>% as.numeric()
d1 <- d-c %>% as.numeric()
e <- sum(comparison_sampleAF0.01_biotype_allGenes3$FILTER_RF_SYN_NO_LOFTEE_AC_0.005_NFE) %>% as.numeric()
f <- (30651075*2*51377)+(32482680*2*7718) %>% as.numeric()
f1 <- f-e %>% as.numeric()

chiX2_0.005_biotype <- matrix(c(a,b1,c,d1),nrow=2,byrow=TRUE)
chiX2_0.005_NFE_biotype <- matrix(c(a,b1,e,f1),nrow=2,byrow=TRUE)

sink(file="masterfile_eoc_SYN_NO_LOFTEE_comparison_chiX2_results.txt",append=FALSE)

chisq.test(chiX2_0.005_biotype,correct=FALSE)
oddsratio(chiX2_0.005_biotype)
chisq.test(chiX2_0.005_NFE_biotype,correct=FALSE)
oddsratio(chiX2_0.005_NFE_biotype)

sink()
LS0tCnRpdGxlOiAiVGhlc2lzIFN5bm9ueW1vdXMgVmFyaWFudHMgQW5hbHlzaXMgU2NyaXB0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpBTEwgSU1QT1JURUQgRklMRVMgTVVTVCBCRSBJTiBUSEUgU0FNRSBESVJFQ1RPUlkgQVMgVEhJUyBTQ1JJUFQKCkxvYWQgdGlkeXZlcnNlIHBhY2thZ2UKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCkltcG9ydCByYXcgdmNmIGRhdGEgZnJvbSAibWFzdGVyZmlsZSIgYW5kIGV4Y2x1ZGUgdmFyaWFudHMgd2l0aCBHbm9tQUQgbm9uLWNhbmNlciBBRiA+IDAuMDA1CmBgYHtyfQptYXN0ZXJmaWxlIDwtIHJlYWQuZGVsaW0oIm1hc3RlcmZpbGVfMTgxMDA5X2V4b21lc193aXRoX21pc3NpbmdfcmVnaW9uc19nbm9tYWQyLjFfcmFyZV92YXJpYW50c19sb2Z0ZWVfR25vbUFEM19jYW5vbmljYWxfcmVmc2VxX29yX0xSR19jb25zZXF1ZW5jZV80LTYudHN2IiwgaGVhZGVyPVRSVUUsIHJvdy5uYW1lcz1OVUxMLCBuYS5zdHJpbmdzID0gIi4iLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSAlPiUgCiAgZHBseXI6OnJlbmFtZSgiU2FtcGxlIj0iWC5TYW1wbGUiKSAKICAKbWFzdGVyZmlsZV9yYXJlX25vbl9jYW5jZXIgPC0gZmlsdGVyKG1hc3RlcmZpbGUsIEdub21BRF92Mi4xX25vbl9jYW5jZXJfQUZfbmZlPD0wLjAwNSkKYGBgCgpFeGNsdWRlIG5vbi1lcGl0aGVsaWFsLCB1dGVyaW5lLW9ubHkgYW5kIEJSQ0EgK3ZlIHNhbXBsZXMgKyBub24tTkZFIHNhbXBsZXMKYGBge3J9CnNhbXBsZV9ldGhuaWNpdGllcyA8LSByZWFkLmRlbGltKCJleG9tZXNfcGNhX3dpdGhfZ25vbWFkX2luZm8udHN2Iiwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKTkZFX3NhbXBsZXMgPC0gZmlsdGVyKHNhbXBsZV9ldGhuaWNpdGllcywgR25vbUFEX2NsYXNzJWluJSJFdXJvcGVhbiIpCgpWaVBfQ29tcGxldGVfQ29ob3J0IDwtIHJlYWQuZGVsaW0oIlZpUF9Mb0ZfQ29tcGxldGVfQ29ob3J0LnR4dCIsIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpClZpUF9Db21wbGV0ZV9Db2hvcnRfbGlzdF9ORkUgPC0gZmlsdGVyKFZpUF9Db21wbGV0ZV9Db2hvcnQsRXhvbWUuSUQlaW4lYyhORkVfc2FtcGxlcyRTYW1wbGUpKQoKbWFzdGVyZmlsZV9lb2MgPC0gZmlsdGVyKG1hc3RlcmZpbGVfcmFyZV9ub25fY2FuY2VyLFNhbXBsZSVpbiVjKFZpUF9Db21wbGV0ZV9Db2hvcnRfbGlzdF9ORkUkRXhvbWUuSUQpKSAlPiUgCiAgZmlsdGVyKFNhbXBsZSVpbiUoTkZFX3NhbXBsZXMkU2FtcGxlKSkgJT4lCiAgZmlsdGVyKEdub21BRF92Mi4xX25vbl9jYW5jZXJfQUZfbmZlPD0wLjAwNSkKCnJtKG1hc3RlcmZpbGUpCmBgYAoKQXBwZW5kIHBhdGllbnQgcGF0aCBkYXRhCmBgYHtyfQpWaVBfT3ZDYV9QYXRoX0RhdGEgPC0gcmVhZC5kZWxpbSgiVmlQX092Q2FfUGF0aF9EYXRhLnR4dCIsIGhlYWRlcj1UUlVFLCByb3cubmFtZXM9TlVMTCwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoIlNhbXBsZSI9RXhvbWUuSUQpCm1hc3RlcmZpbGVfZW9jX3dpdGhQYXRoIDwtIGxlZnRfam9pbihtYXN0ZXJmaWxlX2VvYyxWaVBfT3ZDYV9QYXRoX0RhdGEsYnk9IlNhbXBsZSIsY29weT1GQUxTRSkKCnJtKFZpUF9PdkNhX1BhdGhfRGF0YSkKcm0obWFzdGVyZmlsZV9lb2MpCmBgYAoKRXhjbHVkZSBsb3ctcXVhbGl0eSB2YXJpYW50cyBhbmQgR25vbUFEIFJGL0luYnJlZWRpbmdDb2VmZi1mbGFnZ2VkIHZhcmlhbnRzCmBgYHtyfQptYXN0ZXJmaWxlX2VvY19nb29kUSA8LSBmaWx0ZXIobWFzdGVyZmlsZV9lb2Nfd2l0aFBhdGgsIChRVUFMPj0zMCkmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChJZGVudGlmaWVkIT0iRmlsdGVyZWRJbkFsbCIpJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU2FtcGxlLlBNQ0RQPj0xMCkmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTYW1wbGUuUE1DRlJFUT49MC4yNSkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKCghc3RyX2RldGVjdChHbm9tQURfdjIuMV9GSUxURVJfZXhvbWUsIkluYnJlZWRpbmdDb2VmZiIpJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoR25vbUFEX3YyLjFfRklMVEVSX2V4b21lLCJSRiIpKXwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoR25vbUFEX3YyLjFfRklMVEVSX2V4b21lKSkgJT4lIAogIGZpbHRlcigoIXN0cl9kZXRlY3QoR25vbUFEX3YyLjFfRklMVEVSX2dlbm9tZSwiSW5icmVlZGluZ0NvZWZmIikmCiAgICAgICAgICAgICFzdHJfZGV0ZWN0KEdub21BRF92Mi4xX0ZJTFRFUl9nZW5vbWUsIlJGIikpfAogICAgICAgICAgIGlzLm5hKEdub21BRF92Mi4xX0ZJTFRFUl9nZW5vbWUpKQoKcm0obWFzdGVyZmlsZV9lb2Nfd2l0aFBhdGgpCmBgYAoKRXhjbHVkZSBvdGhlciBtdXRhdGlvbiArdmUgc2FtcGxlcyAoTUxIMS9NU0gyL01TSDYvUE1TMiwgVFA1MywgUkFENTFDL0QsIEJSSVAxKQpgYGB7cn0KVmlQX0Rpc2NvdmVyeV9Db2hvcnQgPC0gcmVhZC5kZWxpbSgiVmlQX0xvRl9EaXNjb3ZlcnlfQ29ob3J0LnR4dCIsIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpClZpUF9EaXNjb3ZlcnlfQ29ob3J0X2xpc3QgPC0gVmlQX0Rpc2NvdmVyeV9Db2hvcnRbLDFdCgptYXN0ZXJmaWxlX2VvY19nb29kUTIgPC0gZmlsdGVyKG1hc3RlcmZpbGVfZW9jX2dvb2RRLFNhbXBsZSVpbiVjKFZpUF9EaXNjb3ZlcnlfQ29ob3J0X2xpc3QpKQpgYGAKCkV4Y2x1ZGUgSElHSCBhbmQgTU9ERVJBVEUgaW1wYWN0IHZhcmlhbnRzCmBgYHtyfQptYXN0ZXJmaWxlX2VvY19nb29kUTJfTE9XIDwtIGZpbHRlcihtYXN0ZXJmaWxlX2VvY19nb29kUTIsIElNUEFDVCVpbiUiTE9XIikKCnJtKG1hc3RlcmZpbGVfZW9jX2dvb2RRMikKYGBgCgpFeGNsdWRlIG5vbi1zeW5vbnltb3VzIHZhcmlhbnRzCmBgYHtyfQptYXN0ZXJmaWxlX2VvY19nb29kUTJfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUUgPC0gZmlsdGVyKG1hc3RlcmZpbGVfZW9jX2dvb2RRMl9MT1csQ29uc2VxdWVuY2UlaW4lYygic3lub255bW91c192YXJpYW50Iiwic3lub255bW91c192YXJpYW50LE5NRF90cmFuc2NyaXB0X3ZhcmlhbnQiKSkgJT4lIAogIGZpbHRlcighTG9GJWluJWMoIkhDIiwiTEMiKSkKCnJtKG1hc3RlcmZpbGVfZW9jX2dvb2RRMl9MT1cpCmBgYAoKU2VwYXJhdGUgRW5zZW1ibCBjYW5vbmljYWwgYW5kIFJlZlNlcSBjYW5vbmljYWwgdmFyaWFudHMKYGBge3J9Cm1hc3RlcmZpbGVfZW9jX2dvb2RRXzAuMDA1X0xPV19zeW5vbnltb3VzX05vTE9GVEVFX0VOU1RjYW5vbmljYWwgPC0gZmlsdGVyKG1hc3RlcmZpbGVfZW9jX2dvb2RRMl9MT1dfc3lub255bW91c19Ob0xPRlRFRSxDQU5PTklDQUwlaW4lIllFUyIpIApgYGAKClNhbXBsZSB2YXJpYW50IGNvdW50cyBhbmQgQUZzCmBgYHtyfQp2YXJpYW50c19oZXRlcm96eWdvdXMgPC0gbWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbCAlPiUgCiAgc2VsZWN0KEhHVlNjLFNhbXBsZS5HVCkgJT4lIAogIGdyb3VwX2J5KEhHVlNjLFNhbXBsZS5HVCkgJT4lIAogIHN1bW1hcmlzZShuKCkpICU+JSAKICBmaWx0ZXIoKFNhbXBsZS5HVCVpbiVjKCInMC8xIiwiJzEvMCIpKSkgJT4lIAogIHJlbmFtZShhbGxlbGVzID0gIm4oKSIpICU+JSAKICBncm91cF9ieShIR1ZTYykgJT4lIAogIHN1bW1hcmlzZShzdW0oYWxsZWxlcykpCnZhcmlhbnRzX2hvbW96eWdvdXMgPC0gbWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbCAlPiUgCiAgc2VsZWN0KEhHVlNjLFNhbXBsZS5HVCkgJT4lIAogIGdyb3VwX2J5KEhHVlNjLFNhbXBsZS5HVCkgJT4lIAogIHN1bW1hcmlzZShuKCkpICU+JSAKICBmaWx0ZXIoKFNhbXBsZS5HVCE9IicwLzEiKSYoU2FtcGxlLkdUIT0iJzEvMCIpKSAlPiUgCiAgbXV0YXRlKGFsbGVsZXMgPSBgbigpYCoyKSAlPiUgCiAgc2VsZWN0KC1gbigpYCkgJT4lIAogIGdyb3VwX2J5KEhHVlNjKSAlPiUgCiAgc3VtbWFyaXNlKHN1bShhbGxlbGVzKSkKdmFyaWFudHMgPC0gZnVsbF9qb2luKHZhcmlhbnRzX2hldGVyb3p5Z291cyx2YXJpYW50c19ob21venlnb3VzLGJ5PSJIR1ZTYyIsY29weT1GQUxTRSxzdWZmaXg9YygiLngiLCIueSIpKSAlPiUKICBtdXRhdGVfYWxsKGZ1bnMocmVwbGFjZSguLCBpcy5uYSguKSwgMCkpKSAlPiUgCiAgbXV0YXRlKFRvdGFsX0FsbGVsZV9Db3VudD1gc3VtKGFsbGVsZXMpLnhgK2BzdW0oYWxsZWxlcykueWApICU+JSAKICBtdXRhdGUoU2FtcGxlX0FGPVRvdGFsX0FsbGVsZV9Db3VudC8obl9kaXN0aW5jdChtYXN0ZXJmaWxlX2VvY19nb29kUTJfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUUkU2FtcGxlKSoyKSkKbWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF8yIDwtIGxlZnRfam9pbihtYXN0ZXJmaWxlX2VvY19nb29kUV8wLjAwNV9MT1dfc3lub255bW91c19Ob0xPRlRFRV9FTlNUY2Fub25pY2FsLHZhcmlhbnRzWyxjKDEsNDo1KV0sYnk9IkhHVlNjIixjb3B5PUZBTFNFKQpgYGAKCkV4Y2x1ZGUgdmFyaWFudHMgd2l0aCBzYW1wbGUgQUYgPjAuMDEKYGBge3J9Cm1hc3RlcmZpbGVfZW9jX2dvb2RRXzAuMDA1X0xPV19zeW5vbnltb3VzX05vTE9GVEVFX0VOU1RjYW5vbmljYWxfc2FtcGxlQUYwLjAxIDwtIGZpbHRlcihtYXN0ZXJmaWxlX2VvY19nb29kUV8wLjAwNV9MT1dfc3lub255bW91c19Ob0xPRlRFRV9FTlNUY2Fub25pY2FsXzIsU2FtcGxlX0FGIDwgMC4wMSkKYGBgCgpPdXRwdXQgbGlzdCBvZiBnZW5lcyBhbmQgdmFyaWFudHMgd2l0aCBzYW1wbGUgQUYgPjAuMDEKYGBge3J9Cm1hc3RlcmZpbGVfZW9jX2dvb2RRXzAuMDA1X0xPV19zeW5vbnltb3VzX05vTE9GVEVFX0VOU1RjYW5vbmljYWxfZ2VuZXNhbmR2YXJpYW50czAuMDEgPC0gZmlsdGVyKG1hc3RlcmZpbGVfZW9jX2dvb2RRXzAuMDA1X0xPV19zeW5vbnltb3VzX05vTE9GVEVFX0VOU1RjYW5vbmljYWxfMixTYW1wbGVfQUYgPiAwLjAxKQptYXN0ZXJmaWxlX2VvY19nb29kUV8wLjAwNV9MT1dfc3lub255bW91c19Ob0xPRlRFRV9FTlNUY2Fub25pY2FsX2dlbmVzYW5kdmFyaWFudHMwLjAxWyxjKDI6NiwyNTo1NCldICU+JSAKICBkaXN0aW5jdCgua2VlcF9hbGwgPSBGQUxTRSkgJT4lIAogIHdyaXRlX2V4Y2VsX2NzdihwYXRoPSJtYXN0ZXJmaWxlX2VvY19nb29kUV8wLjAwMV9MT1dfc3lub255bW91c19Ob0xPRlRFRV9FTlNUY2Fub25pY2FsX2dlbmVzYW5kdmFyaWFudHMwLjAxLmNzdiIsbmE9Ii4iLGFwcGVuZD1GQUxTRSxjb2xfbmFtZXM9VFJVRSkKYGBgCgpTYW1wbGUgZ2VuZSBjb3VudHMgYW5kIGZyZXF1ZW5jaWVzCmBgYHtyfQpnZW5lc19vbmVWYXJBbGxlbGUgPC0gbWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF9zYW1wbGVBRjAuMDEgJT4lIHNlbGVjdChHZW5lLFNhbXBsZS5HVCkgJT4lIAogIHNlbGVjdChHZW5lLFNhbXBsZS5HVCkgJT4lIAogIGdyb3VwX2J5KEdlbmUsU2FtcGxlLkdUKSAlPiUgCiAgc3VtbWFyaXNlKG4oKSkgJT4lIAogIGZpbHRlcigoU2FtcGxlLkdUJWluJWMoIicwLzEiLCInMS8wIikpKSAlPiUgCiAgcmVuYW1lKGdlbmVfVmFyID0gIm4oKSIpICU+JSAKICBncm91cF9ieShHZW5lKSAlPiUgCiAgc3VtbWFyaXNlKHN1bShnZW5lX1ZhcikpCmdlbmVzX3R3b1ZhckFsbGVsZSA8LSBtYXN0ZXJmaWxlX2VvY19nb29kUV8wLjAwNV9MT1dfc3lub255bW91c19Ob0xPRlRFRV9FTlNUY2Fub25pY2FsX3NhbXBsZUFGMC4wMSAlPiUgc2VsZWN0KEdlbmUsU2FtcGxlLkdUKSAlPiUgCiAgc2VsZWN0KEdlbmUsU2FtcGxlLkdUKSAlPiUgCiAgZ3JvdXBfYnkoR2VuZSxTYW1wbGUuR1QpICU+JSAKICBzdW1tYXJpc2UobigpKSAlPiUgCiAgZmlsdGVyKChTYW1wbGUuR1QhPSInMC8xIikmKFNhbXBsZS5HVCE9IicxLzAiKSkgJT4lIAogIG11dGF0ZShnZW5lX1ZhciA9IGBuKClgKjIpICU+JSAKICBzZWxlY3QoLWBuKClgKSAlPiUgCiAgZ3JvdXBfYnkoR2VuZSkgJT4lIAogIHN1bW1hcmlzZShzdW0oZ2VuZV9WYXIpKQpnZW5lcyA8LSBmdWxsX2pvaW4oZ2VuZXNfb25lVmFyQWxsZWxlLGdlbmVzX3R3b1ZhckFsbGVsZSxieT0iR2VuZSIsY29weT1GQUxTRSxzdWZmaXg9YygiLngiLCIueSIpKSAlPiUgCiAgbXV0YXRlX2FsbChmdW5zKHJlcGxhY2UoLiwgaXMubmEoLiksIDApKSkgJT4lIAogIG11dGF0ZShUb3RhbF9HZW5lX0NvdW50PWBzdW0oZ2VuZV9WYXIpLnhgK2BzdW0oZ2VuZV9WYXIpLnlgKSAlPiUgCiAgbXV0YXRlKFNhbXBsZV9HZW5lX0ZyZXE9VG90YWxfR2VuZV9Db3VudC8obl9kaXN0aW5jdChtYXN0ZXJmaWxlX2VvY19nb29kUTJfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUUkU2FtcGxlKSoyKSkKbWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF9zYW1wbGVBRjAuMDFfMiA8LSBsZWZ0X2pvaW4obWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF9zYW1wbGVBRjAuMDEsIGdlbmVzWyxjKDEsNDo1KV0sYnk9IkdlbmUiLGNvcHk9RkFMU0UpCmBgYAoKQWRkIEdub21BRCBnZW5lLWxldmVsIGRhdGEKYGBge3J9CmVuc2VtYmxfYmlvdHlwZXMgPC0gcmVhZC5kZWxpbSgiZW5zZW1ibF9iaW90eXBlcy50c3YiLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSAlPiUgCiAgc2VsZWN0KGVuc2VtYmxfdHJhbnNjcmlwdF9pZCx0cmFuc2NyaXB0X2Jpb3R5cGUpICU+JSAKICBkcGx5cjo6cmVuYW1lKCJGZWF0dXJlIj0iZW5zZW1ibF90cmFuc2NyaXB0X2lkIiwiQklPVFlQRSI9InRyYW5zY3JpcHRfYmlvdHlwZSIpCgphbGxfZmVhdHVyZXNfZXhvbnNfb25seV9mcmFjdGlvbl9jb3ZlcmVkX2FnaWxlbnRfdjZfYmFzZV9maWd1cmVzIDwtIHJlYWQuZGVsaW0oIn4vYWxsX2ZlYXR1cmVzX2V4b25zX29ubHlfZnJhY3Rpb25fY292ZXJlZF9hZ2lsZW50X3Y2XzE1MGJwX2V4dGVuZGVkLnRzdiIpCgpnbm9tYWRfY292ZXJhZ2VfY29kaW5nX2ZlYXR1cmVzIDwtIHJlYWQuZGVsaW0oIn4vZ25vbWFkX2NvdmVyYWdlX2NvZGluZ19mZWF0dXJlcy50c3YiKSAlPiUgCiAgbXV0YXRlKCJ0b3RhbF8xMHhfbm9uX2NhbmNlcl9jb3VudCI9KChleG9tZV8xMHgpKjU2ODg1KSsoKGdlbm9tZV8xMHgpKjc3MTgpKSAlPiUgCiAgbXV0YXRlKCJ0b3RhbF8xMHhfbm9uX2NhbmNlcl9ORkVfY291bnQiPSgoZXhvbWVfMTB4KSo1MTM3NykrKChnZW5vbWVfMTB4KSo3NzE4KSkKZ25vbWFkX2NvdmVyYWdlX2NvZGluZ19mZWF0dXJlcyR0b3RhbF8xMHhfbm9uX2NhbmNlcl9jb3VudD1yb3VuZChnbm9tYWRfY292ZXJhZ2VfY29kaW5nX2ZlYXR1cmVzJHRvdGFsXzEweF9ub25fY2FuY2VyX2NvdW50KQpnbm9tYWRfY292ZXJhZ2VfY29kaW5nX2ZlYXR1cmVzJHRvdGFsXzEweF9ub25fY2FuY2VyX05GRV9jb3VudD1yb3VuZChnbm9tYWRfY292ZXJhZ2VfY29kaW5nX2ZlYXR1cmVzJHRvdGFsXzEweF9ub25fY2FuY2VyX05GRV9jb3VudCkKCkdub21BRF9zdGF0c19zeW5vbnltb3VzX1ZFUF9OT19SRiA8LSByZWFkLmRlbGltKCJhZ2lsZW50X3Y2X2dub21hZF92Mi4xLjFfZ2VuZXN0YXRzX2Nhbm9uaWNhbF9TWU5fbm9MT0ZURUUudHN2IiwgaGVhZGVyPVRSVUUsIHJvdy5uYW1lcz1OVUxMLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSAlPiUgCiAgbGVmdF9qb2luKGVuc2VtYmxfYmlvdHlwZXMsYnk9IkZlYXR1cmUiLGNvcHk9RkFMU0UpICU+JSAKICBmaWx0ZXIoQklPVFlQRSVpbiVjKCJwcm90ZWluX2NvZGluZyIpKSAlPiUgCiAgZGlzdGluY3QoLmtlZXBfYWxsID0gRkFMU0UpICU+JSAKICBsZWZ0X2pvaW4oYWxsX2ZlYXR1cmVzX2V4b25zX29ubHlfZnJhY3Rpb25fY292ZXJlZF9hZ2lsZW50X3Y2X2Jhc2VfZmlndXJlc1ssYygxLDQpXSxieT0iRmVhdHVyZSIsY29weT1GQUxTRSkgJT4lIAogIGxlZnRfam9pbihnbm9tYWRfY292ZXJhZ2VfY29kaW5nX2ZlYXR1cmVzWyxjKDEsNiw3KV0sYnk9IkZlYXR1cmUiLGNvcHk9RkFMU0UpCiAgCm1hc3RlcmZpbGVfZW9jX2dvb2RRXzAuMDA1X0xPV19zeW5vbnltb3VzX05vTE9GVEVFX0VOU1RjYW5vbmljYWxfc2FtcGxlQUYwLjAxX3dpdGhHbm9tQURzdGF0cyA8LSBsZWZ0X2pvaW4obWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF9zYW1wbGVBRjAuMDFfMiwgR25vbUFEX3N0YXRzX3N5bm9ueW1vdXNfVkVQX05PX1JGWyxjKDIsMjA6MjUsMjc6MjkpXSxieT0iRmVhdHVyZSIsY29weT1GQUxTRSkKbWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF9zYW1wbGVBRjAuMDFfd2l0aEdub21BRHN0YXRzMiA8LSBtdXRhdGVfYXQobWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF9zYW1wbGVBRjAuMDFfd2l0aEdub21BRHN0YXRzLHZhcnMoc3RhcnRzX3dpdGgoIkZJTFRFUl8iKSksZnVucyhyZXBsYWNlKC4sIGlzLm5hKC4pLCAwKSkpICU+JSAKICBtdXRhdGVfaWYoZ3JlcGwoInBvcG1heCQiLCBuYW1lcyguKSksZnVucyhpZmVsc2UoLiA9PSAiTkEiLCAwLCBhcy5udW1lcmljKC4pKSkpICU+JSAKICBtdXRhdGVfYXQodmFycyhlbmRzX3dpdGgoInBvcG1heCIpKSxmdW5zKHJlcGxhY2UoLiwgaXMubmEoLiksIDApKSkKYGBgCgpDcmVhdGUgZGF0YSBmcmFtZXMgd2l0aCBBZ2lsZW50IFN1cmVTZWxlY3Qgd2hvbGUgZXhvbWUgZ2VuZXMgKGFsbCBFTlNULCBwcm90ZWluLWNvZGluZyBvbmx5IGFuZCBub24tcHJvdGVpbi1jb2RpbmcpCmBgYHtyfQpHbm9tQURfc3RhdHNfQWdpbGVudFNTdjZfbGlzdCA8LSAgcmVhZC5kZWxpbSgiYWdpbGVudF92Nl9nbm9tYWRfdjIuMS4xX2dlbmVzdGF0c19jYW5vbmljYWxfU1lOX25vTE9GVEVFLnRzdiIsIGhlYWRlcj1UUlVFLCByb3cubmFtZXM9TlVMTCwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkgJT4lIAogIGZpbHRlcihDQU5PTklDQUw9PSJZRVMiKSAlPiUgCiAgZGlzdGluY3QoLmtlZXBfYWxsID0gRkFMU0UpICU+JSAKICBzZWxlY3QoU1lNQk9MOkVOU1ApCgpHbm9tQURfc3RhdHNfQWdpbGVudFNTdjZfU1lOX05PX0xPRlRFRV9WRVBfRU5TVGNhbm9uaWNhbF9wcm90ZWluX2NvZGluZyA8LSBmaWx0ZXIoR25vbUFEX3N0YXRzX3N5bm9ueW1vdXNfVkVQX05PX1JGLEZlYXR1cmUlaW4lYyhHbm9tQURfc3RhdHNfQWdpbGVudFNTdjZfbGlzdCRGZWF0dXJlKSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoIkdlbmUiPSJFTlNHIikgJT4lIAogIGZpbHRlcihCSU9UWVBFJWluJWMoInByb3RlaW5fY29kaW5nIikpICU+JSAKICBkaXN0aW5jdCgua2VlcF9hbGwgPSBGQUxTRSkKCmFsbEdlbmVzX0FnaWxlbnRTU3Y2X2xpc3RfcHJvdGVpbl9jb2Rpbmdfb25seSA8LSB0aWJibGUoIlNZTUJPTCI9R25vbUFEX3N0YXRzX0FnaWxlbnRTU3Y2X1NZTl9OT19MT0ZURUVfVkVQX0VOU1RjYW5vbmljYWxfcHJvdGVpbl9jb2RpbmckU1lNQk9MLCJHZW5lIj1Hbm9tQURfc3RhdHNfQWdpbGVudFNTdjZfU1lOX05PX0xPRlRFRV9WRVBfRU5TVGNhbm9uaWNhbF9wcm90ZWluX2NvZGluZyRHZW5lLCJGZWF0dXJlIj1Hbm9tQURfc3RhdHNfQWdpbGVudFNTdjZfU1lOX05PX0xPRlRFRV9WRVBfRU5TVGNhbm9uaWNhbF9wcm90ZWluX2NvZGluZyRGZWF0dXJlKSAlPiUgCiAgZGlzdGluY3QoLmtlZXBfYWxsPVRSVUUpICU+JSAKICBhcnJhbmdlKFNZTUJPTCkKCmFsbEdlbmVzX21hc3RlcmZpbGVfZW9jX2dvb2RRXzAuMDA1X0xPV19zeW5vbnltb3VzX05vTE9GVEVFX0VOU1RjYW5vbmljYWxfc2FtcGxlQUYwLjAxX2Jpb3R5cGVfbGlzdCA8LSB0aWJibGUoIlNZTUJPTCI9bWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF9zYW1wbGVBRjAuMDFfd2l0aEdub21BRHN0YXRzMiRTWU1CT0wsIkdlbmUiPW1hc3RlcmZpbGVfZW9jX2dvb2RRXzAuMDA1X0xPV19zeW5vbnltb3VzX05vTE9GVEVFX0VOU1RjYW5vbmljYWxfc2FtcGxlQUYwLjAxX3dpdGhHbm9tQURzdGF0czIkR2VuZSwiQklPVFlQRSI9bWFzdGVyZmlsZV9lb2NfZ29vZFFfMC4wMDVfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUVfRU5TVGNhbm9uaWNhbF9zYW1wbGVBRjAuMDFfd2l0aEdub21BRHN0YXRzMiRCSU9UWVBFKSAlPiUgCiAgZGlzdGluY3QoLmtlZXBfYWxsPVRSVUUpICU+JSAKICBmaWx0ZXIoQklPVFlQRSVpbiVjKCJwcm90ZWluX2NvZGluZyIpKSAlPiUgCiAgYXJyYW5nZShTWU1CT0wpCgpjb21wYXJpc29uX3NhbXBsZUFGMC4wMV9iaW90eXBlX2FsbEdlbmVzIDwtIG1hc3RlcmZpbGVfZW9jX2dvb2RRXzAuMDA1X0xPV19zeW5vbnltb3VzX05vTE9GVEVFX0VOU1RjYW5vbmljYWxfc2FtcGxlQUYwLjAxX3dpdGhHbm9tQURzdGF0czIgJT4lIAogIG11dGF0ZShUb3RhbF9DYXNlX0Jhc2VzPShuX2Rpc3RpbmN0KG1hc3RlcmZpbGVfZW9jX2dvb2RRMl9MT1dfc3lub255bW91c19Ob0xPRlRFRSRTYW1wbGUpKjIqVG90YWxfQmFzZXNfQ292ZXJlZCkpICU+JSAKICBmaWx0ZXIoQklPVFlQRSVpbiVjKCJwcm90ZWluX2NvZGluZyIpKSAlPiUgCiAgc2VsZWN0KFNZTUJPTCxHZW5lLFRvdGFsX0dlbmVfQ291bnQsVG90YWxfQ2FzZV9CYXNlcykgJT4lIAogIGRpc3RpbmN0KFNZTUJPTCxHZW5lLFRvdGFsX0dlbmVfQ291bnQsVG90YWxfQ2FzZV9CYXNlcykgCmNvbXBhcmlzb25fc2FtcGxlQUYwLjAxX2Jpb3R5cGVfYWxsR2VuZXMyIDwtIGJpbmRfcm93cyhjb21wYXJpc29uX3NhbXBsZUFGMC4wMV9iaW90eXBlX2FsbEdlbmVzLCBhbnRpX2pvaW4oYWxsR2VuZXNfQWdpbGVudFNTdjZfbGlzdF9wcm90ZWluX2NvZGluZ19vbmx5LGNvbXBhcmlzb25fc2FtcGxlQUYwLjAxX2Jpb3R5cGVfYWxsR2VuZXMsYnk9IkdlbmUiKSkgJT4lIAogIG11dGF0ZV9hdCh2YXJzKCJUb3RhbF9HZW5lX0NvdW50IiksZnVucyhyZXBsYWNlKC4sIGlzLm5hKC4pLCAwKSkpCmNvbXBhcmlzb25fc2FtcGxlQUYwLjAxX2Jpb3R5cGVfYWxsR2VuZXMzIDwtIHJpZ2h0X2pvaW4oCiAgY29tcGFyaXNvbl9zYW1wbGVBRjAuMDFfYmlvdHlwZV9hbGxHZW5lczIsCiAgR25vbUFEX3N0YXRzX0FnaWxlbnRTU3Y2X1NZTl9OT19MT0ZURUVfVkVQX0VOU1RjYW5vbmljYWxfcHJvdGVpbl9jb2RpbmcsCiAgYnk9IkdlbmUiLGNvcHk9RkFMU0UpICU+JSAKICBtdXRhdGVfYXQodmFycygiVG90YWxfQ2FzZV9CYXNlcyIpLGZ1bnMocmVwbGFjZSguLCBpcy5uYSguKSwgbl9kaXN0aW5jdChtYXN0ZXJmaWxlX2VvY19nb29kUTJfTE9XX3N5bm9ueW1vdXNfTm9MT0ZURUUkU2FtcGxlKSoyKlRvdGFsX0Jhc2VzX0NvdmVyZWQpKSkgJT4lIAogIHNlbGVjdCgiU1lNQk9MLngiLCJHZW5lIiwiVG90YWxfR2VuZV9Db3VudCIsIlRvdGFsX0Nhc2VfQmFzZXMiLCJGSUxURVJfUkZfU1lOX05PX0xPRlRFRV9BQ18wLjAwNSIsIkZJTFRFUl9SRl9TWU5fTk9fTE9GVEVFX0FDXzAuMDA1X05GRSIsIlRvdGFsX0Jhc2VzX0NvdmVyZWQiLCJ0b3RhbF8xMHhfbm9uX2NhbmNlcl9jb3VudCIsInRvdGFsXzEweF9ub25fY2FuY2VyX05GRV9jb3VudCIpICU+JSAKICBkcGx5cjo6cmVuYW1lKCJTWU1CT0wiPSJTWU1CT0wueCIpICU+JSAKICBtdXRhdGUoIlRvdGFsX0dub21BRF9CYXNlcyI9dG90YWxfMTB4X25vbl9jYW5jZXJfY291bnQqMipUb3RhbF9CYXNlc19Db3ZlcmVkKSAlPiUgCiAgbXV0YXRlKCJUb3RhbF9Hbm9tQURfTkZFX0Jhc2VzIj10b3RhbF8xMHhfbm9uX2NhbmNlcl9ORkVfY291bnQqMipUb3RhbF9CYXNlc19Db3ZlcmVkKSAlPiUgCiAgZmlsdGVyKFRvdGFsX0Jhc2VzX0NvdmVyZWQhPTApICU+JSAKICBkaXN0aW5jdCgua2VlcF9hbGw9VFJVRSkKYGBgCgpDYWxjdWxhdGUgdG90YWwgTG9GIHZhcmlhbnRzIGluIHNhbXBsZSB2cyB0b3RhbCBMb0YgdmFyaWFudHMgaW4gR25vbUFEIG5vbi1jYW5jZXIgTkZFIGFuZCB1c2UgZm9yIGNoaS1zcXVhcmVkIHRlc3QKYGBge3J9Cm9kZHNyYXRpbyA8LSBmdW5jdGlvbiAoYSwgYiA9IE5VTEwsIGMgPSBOVUxMLCBkID0gTlVMTCwgY29uZi5sZXZlbCA9IDAuOTUsIAogICAgcC5jYWxjLmJ5LmluZGVwZW5kZW5jZSA9IFRSVUUpIAp7CiAgICBpZiAoaXMubWF0cml4KGEpKSB7CiAgICAgICAgaWYgKChkaW0oYSlbMV0gIT0gMkwpIHwgKGRpbShhKVsyXSAhPSAyTCkpIHsKICAgICAgICAgICAgc3RvcCgiSW5wdXQgbWF0cml4IG11c3QgYmUgYSAyeDIgdGFibGUuIikKICAgICAgICB9CiAgICAgICAgLmEgPC0gYVsxLCAxXQogICAgICAgIC5iIDwtIGFbMSwgMl0KICAgICAgICAuYyA8LSBhWzIsIDFdCiAgICAgICAgLmQgPC0gYVsyLCAyXQogICAgICAgIC5kYXRhLm5hbWUgPC0gZGVwYXJzZShzdWJzdGl0dXRlKGEpKQogICAgfQogICAgZWxzZSB7CiAgICAgICAgLmEgPC0gYQogICAgICAgIC5iIDwtIGIKICAgICAgICAuYyA8LSBjCiAgICAgICAgLmQgPC0gZAogICAgICAgIC5kYXRhLm5hbWUgPC0gcGFzdGUoZGVwYXJzZShzdWJzdGl0dXRlKGEpKSwgZGVwYXJzZShzdWJzdGl0dXRlKGIpKSwgCiAgICAgICAgICAgIGRlcGFyc2Uoc3Vic3RpdHV0ZShjKSksIGRlcGFyc2Uoc3Vic3RpdHV0ZShkKSkpCiAgICB9CiAgICAuTUFUIDwtIG1hdHJpeChjKC5hLCAuYiwgTTEgPC0gLmEgKyAuYiwgLmMsIC5kLCBNMCA8LSAuYyArIAogICAgICAgIC5kLCBOMSA8LSAuYSArIC5jLCBOMCA8LSAuYiArIC5kLCBUb3RhbCA8LSAuYSArIC5iICsgCiAgICAgICAgLmMgKyAuZCksIDMsIDMpCiAgICBjb2xuYW1lcyguTUFUKSA8LSBjKCJTYW1wbGUiLCAiR25vbUFEIiwgIlRvdGFsIikgIygiRGlzZWFzZSIsICJOb25kaXNlYXNlIiwgIlRvdGFsIikKICAgIHJvd25hbWVzKC5NQVQpIDwtIGMoIlN5biIsICJObyBTeW4iLCAiVG90YWwiKSAjKCJFeHBvc2VkIiwgIk5vbmV4cG9zZWQiLCAiVG90YWwiKQogICAgY2xhc3MoLk1BVCkgPC0gInRhYmxlIgogICAgcHJpbnQoLk1BVCkKICAgIEVTVElNQVRFIDwtICguYSAvLmIpLyguYy8uZCkKICAgIG5vcm0ucHAgPC0gcW5vcm0oMSAtICgxIC0gY29uZi5sZXZlbCkvMikKICAgIGlmIChwLmNhbGMuYnkuaW5kZXBlbmRlbmNlKSB7CiAgICAgICAgcC52IDwtIDIgKiAoMSAtIHBub3JtKGFicygoLmEgLSBOMSAqIE0xL1RvdGFsKS9zcXJ0KE4xICogCiAgICAgICAgICAgIE4wICogTTEgKiBNMC9Ub3RhbC9Ub3RhbC8oVG90YWwgLSAxKSkpKSkKICAgIH0KICAgIGVsc2UgewogICAgICAgIHAudiA8LSAyICogKDEgLSBwbm9ybShsb2coaWZlbHNlKEVTVElNQVRFID4gMSwgRVNUSU1BVEUsIAogICAgICAgICAgICAxL0VTVElNQVRFKSkvc3FydCgxLy5hICsgMS8uYiArIDEvLmMgKyAxLy5kKSkpCiAgICB9CiAgICBPUkwgPC0gRVNUSU1BVEUgKiBleHAoLW5vcm0ucHAgKiBzcXJ0KDEvLmEgKyAxLy5iICsgMS8uYyArIAogICAgICAgIDEvLmQpKQogICAgT1JVIDwtIEVTVElNQVRFICogZXhwKG5vcm0ucHAgKiBzcXJ0KDEvLmEgKyAxLy5iICsgMS8uYyArIAogICAgICAgIDEvLmQpKSAlPiUgc2lnbmlmKGRpZ2l0cz03KQogICAgQ0lOVCA8LSBwYXN0ZShzaWduaWYoT1JMLGRpZ2l0cyA9IDcpLHNpZ25pZihPUlUsZGlnaXRzID0gNyksc2VwPSJ+IikKICAgIGF0dHIoQ0lOVCwgImNvbmYubGV2ZWwiKSA8LSBjb25mLmxldmVsCiAgICBSVkFMIDwtIGxpc3QocC52YWx1ZSA9IHAudiwgY29uZi5pbnQgPSBDSU5ULCBlc3RpbWF0ZSA9IEVTVElNQVRFLCAKICAgICAgICBtZXRob2QgPSAiT2RkcyByYXRpbyBlc3RpbWF0ZSBhbmQgaXRzIHNpZ25pZmljYW5jZSBwcm9iYWJpbGl0eSIsIAogICAgICAgIGRhdGEubmFtZSA9IC5kYXRhLm5hbWUpCiAgICBjbGFzcyhSVkFMKSA8LSAiaHRlc3QiCiAgICByZXR1cm4oUlZBTCkKfQoKYSA8LSBzdW0oY29tcGFyaXNvbl9zYW1wbGVBRjAuMDFfYmlvdHlwZV9hbGxHZW5lczMkVG90YWxfR2VuZV9Db3VudCkgJT4lIGFzLm51bWVyaWMoKQpiIDwtIG5fZGlzdGluY3QobWFzdGVyZmlsZV9lb2NfZ29vZFEyX0xPV19zeW5vbnltb3VzX05vTE9GVEVFJFNhbXBsZSkqMiozMzIxODMwNCAlPiUgYXMubnVtZXJpYygpCmIxIDwtIGItYSAlPiUgYXMubnVtZXJpYygpCmMgPC0gc3VtKGNvbXBhcmlzb25fc2FtcGxlQUYwLjAxX2Jpb3R5cGVfYWxsR2VuZXMzJEZJTFRFUl9SRl9TWU5fTk9fTE9GVEVFX0FDXzAuMDA1KSAlPiUgYXMubnVtZXJpYygpCmQgPC0gKDMwNjUxMDc1KjIqMTE4NDc5KSsoMzI0ODI2ODAqMioxNTcwOCkgJT4lIGFzLm51bWVyaWMoKQpkMSA8LSBkLWMgJT4lIGFzLm51bWVyaWMoKQplIDwtIHN1bShjb21wYXJpc29uX3NhbXBsZUFGMC4wMV9iaW90eXBlX2FsbEdlbmVzMyRGSUxURVJfUkZfU1lOX05PX0xPRlRFRV9BQ18wLjAwNV9ORkUpICU+JSBhcy5udW1lcmljKCkKZiA8LSAoMzA2NTEwNzUqMio1MTM3NykrKDMyNDgyNjgwKjIqNzcxOCkgJT4lIGFzLm51bWVyaWMoKQpmMSA8LSBmLWUgJT4lIGFzLm51bWVyaWMoKQoKY2hpWDJfMC4wMDVfYmlvdHlwZSA8LSBtYXRyaXgoYyhhLGIxLGMsZDEpLG5yb3c9MixieXJvdz1UUlVFKQpjaGlYMl8wLjAwNV9ORkVfYmlvdHlwZSA8LSBtYXRyaXgoYyhhLGIxLGUsZjEpLG5yb3c9MixieXJvdz1UUlVFKQoKc2luayhmaWxlPSJtYXN0ZXJmaWxlX2VvY19TWU5fTk9fTE9GVEVFX2NvbXBhcmlzb25fY2hpWDJfcmVzdWx0cy50eHQiLGFwcGVuZD1GQUxTRSkKCmNoaXNxLnRlc3QoY2hpWDJfMC4wMDVfYmlvdHlwZSxjb3JyZWN0PUZBTFNFKQpvZGRzcmF0aW8oY2hpWDJfMC4wMDVfYmlvdHlwZSkKY2hpc3EudGVzdChjaGlYMl8wLjAwNV9ORkVfYmlvdHlwZSxjb3JyZWN0PUZBTFNFKQpvZGRzcmF0aW8oY2hpWDJfMC4wMDVfTkZFX2Jpb3R5cGUpCgpzaW5rKCkKYGBgCg==