ALL IMPORTED FILES MUST BE IN THE SAME DIRECTORY AS THIS SCRIPT
Load tidyverse package
setwd("~/OneDrive - The University of Melbourne/R data")
library("tidyverse")
Import raw vcf data from “masterfile” and exclude variants with GnomAD non-cancer AF > 0
masterfile <- read.delim("masterfile.tsv", header=TRUE, row.names=NULL, na.strings = ".", stringsAsFactors=FALSE) %>%
dplyr::rename("Sample"="X.Sample") %>%
filter(GnomAD_v2.1_non_cancer_AF==0)
Exclude non-epithelial, uterine-only and BRCA +ve samples
ViP_Complete_Cohort <- read.delim("ViP_LoF_Complete_Cohort.txt", stringsAsFactors=FALSE)
ViP_Complete_Cohort_list <- ViP_Complete_Cohort[,1]
masterfile_eoc <- filter(masterfile,Sample%in%c(ViP_Complete_Cohort_list))
Append patient path data and family history info
ViP_OvCa_Path_Data <- read.delim("ViP_OvCa_Path_Data.txt", header=TRUE, row.names=NULL, stringsAsFactors=FALSE) %>%
dplyr::rename("Sample"=Exome.ID)
NoFHxCa <- read.delim("NoFHxCa.tsv", header=TRUE, row.names=NULL, stringsAsFactors=FALSE) %>%
select(Exome.ID,FHx) %>%
dplyr::rename("Sample"=Exome.ID)
masterfile_eoc2 <- left_join(masterfile_eoc,ViP_OvCa_Path_Data,by="Sample",copy=FALSE) %>%
left_join(NoFHxCa,by="Sample",copy=FALSE) %>%
mutate_at(vars("FHx"),funs(replace(., is.na(.), "YES")))
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_eoc3 <- filter(masterfile_eoc2,Sample%in%c(ViP_Discovery_Cohort_list))
Add Sample AD/DP column to calculate read freq for variants with missing PMCFREQ values
masterfile_eoc4 <- mutate(masterfile_eoc3, AD = as.numeric(sapply(strsplit(Sample.AD,","), function(x) tail(x,1))), DP = as.numeric(Sample.DP), Sample.FREQ = AD/DP)
Total_Sample_Alleles <- (n_distinct(masterfile_eoc4$Sample)*2)
Exclude low-quality variants, GnomAD RF/InbreedingCoeff-flagged variants
masterfile_eoc_lowFreq <- filter(masterfile_eoc4, (QUAL>=30)&
(Identified!="FilteredInAll")&
(Sample.PMCDP>=20)&
(Sample.PMCFREQ<0.25)&
(Sample.FREQ<0.25)) %>%
filter(Sample.FREQ>=0.01) %>%
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))
Remove HAP-only indel variants with PMCFREQ==0
masterfile_eoc_lowFreq_HAP_SNV <- filter(masterfile_eoc_lowFreq,Sample.PMCFREQ==0) %>%
filter(Variant_Type=="SNV")
masterfile_eoc_lowFreq2 <- filter(masterfile_eoc_lowFreq,Sample.PMCFREQ!=0) %>%
bind_rows(masterfile_eoc_lowFreq_HAP_SNV,.id=NULL)
Exclude MODERATE impact variants
masterfile_eoc_lowFreq_HIGH <- filter(masterfile_eoc_lowFreq2, IMPACT=="HIGH")
Separate Ensembl canonical and RefSeq canonical variants
masterfile_eoc_lowFreq_HIGH_ENSTcanonical <- filter(masterfile_eoc_lowFreq_HIGH,CANONICAL=="YES") %>%
write_excel_csv(path="masterfile_eoc_altAF0.25_HIGH_ENSTcanonical.csv",na=".",append=FALSE,col_names=TRUE)
Sample variant counts and AFs
variant_counts_AFs <- function(vcf){
variants_heterozygous <- vcf %>%
select(HGVSc,Sample.GT) %>%
group_by(HGVSc,Sample.GT) %>%
summarise(n()) %>%
filter((Sample.GT%in%c("'0/1","'1/0"))) %>%
dplyr::rename(alleles = "n()") %>%
group_by(HGVSc) %>%
summarise(sum(alleles))
variants_homozygous <- vcf %>%
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/Total_Sample_Alleles)
vcf <- left_join(vcf, variants[,c(1,4:5)],by="HGVSc",copy=FALSE)
}
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_2 <- variant_counts_AFs(masterfile_eoc_lowFreq_HIGH_ENSTcanonical)
Sample gene counts and frequencies
gene_counts_AF <- function(vcf){
genes_oneVarAllele <- vcf %>% select(SYMBOL,Sample.GT) %>%
select(SYMBOL,Sample.GT) %>%
group_by(SYMBOL,Sample.GT) %>%
summarise(n()) %>%
filter((Sample.GT%in%c("'0/1","'1/0"))) %>%
dplyr::rename(gene_Var = "n()") %>%
group_by(SYMBOL) %>%
summarise(sum(gene_Var))
genes_twoVarAllele <- vcf %>% select(SYMBOL,Sample.GT) %>%
select(SYMBOL,Sample.GT) %>%
group_by(SYMBOL,Sample.GT) %>%
summarise(n()) %>%
filter((Sample.GT!="'0/1")&(Sample.GT!="'1/0")) %>%
mutate(gene_Var = `n()`*2) %>%
select(-`n()`) %>%
group_by(SYMBOL) %>%
summarise(sum(gene_Var))
genes <- full_join(genes_oneVarAllele,genes_twoVarAllele,by="SYMBOL",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/Total_Sample_Alleles)
vcf <- left_join(vcf, genes[,c(1,4:5)],by="SYMBOL",copy=FALSE)
}
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_3 <- gene_counts_AF(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_2)
Add GnomAD gene-level data
GnomAD_stats_LOF_VEP <- read.delim("GnomAD_stats_LOF_VEP.tsv", header=TRUE, row.names=NULL, stringsAsFactors=FALSE)
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats <- left_join(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_3, GnomAD_stats_LOF_VEP[,c(2,30:41)],by="Feature",copy=FALSE)
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats2 <- mutate_at(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_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)))
Calculate Sample/GnomAD gene freq ratios for total and NFE GnomAD figures, including and excluding variants with AF > 0.005
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios <-
mutate(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats2, "Sample_Gene_LOF_Freq_Ratio_GnomAD"=Sample_Gene_Freq/FILTER_RF_LOF_HIGHIMPACT_AF_1.0_ADJ,
"Sample_Gene_LOF_Freq_Ratio_GnomAD_0.005"=Sample_Gene_Freq/FILTER_RF_LOF_HIGHIMPACT_AF_0.005_ADJ,
"Ratio_Difference"=Sample_Gene_LOF_Freq_Ratio_GnomAD_0.005-Sample_Gene_LOF_Freq_Ratio_GnomAD,
"Sample_Gene_LOF_Freq_Ratio_GnomAD_NFE"=Sample_Gene_Freq/FILTER_RF_LOF_HIGHIMPACT_AF_1.0_NFE_ADJ,
"Sample_Gene_LOF_Freq_Ratio_GnomAD_NFE_0.005"=Sample_Gene_Freq/FILTER_RF_LOF_HIGHIMPACT_AF_0.005_NFE_ADJ,
"Ratio_Difference_NFE"=Sample_Gene_LOF_Freq_Ratio_GnomAD_NFE_0.005-Sample_Gene_LOF_Freq_Ratio_GnomAD_NFE)
Calculate Sample/GnomAD allele freq ratios
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios2 <- mutate(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios, "Sample_Gene_LOF_AF_Ratio"=Sample_AF/GnomAD_v2.1_non_cancer_AF,
"Sample_Gene_LOF_AF_Ratio_NFE"=Sample_AF/GnomAD_v2.1_non_cancer_AF_nfe)
Attach other GnomAD data for DNA repair genes analysis
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3 <- mutate(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios2,Total_Case_Alleles=Total_Sample_Alleles) %>%
left_join(GnomAD_stats_LOF_VEP[,c(2,6,10,14:29)],by="Feature",copy=FALSE)
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios4 <- mutate(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3, MAX_AN=replace(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3$MAX_AN, is.na(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3$MAX_AN), max(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3$MAX_AN, na.rm=TRUE))) %>%
mutate(MAX_AN_NFE=replace(.$MAX_AN_NFE, is.na(.$MAX_AN_NFE), max(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3$MAX_AN_NFE, na.rm=TRUE)))
Post-filtering figures (ENST, excl. mutation +ve samples)
n_distinct(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3$Sample)
[1] 150
n_distinct(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3$Gene)
[1] 102
n_distinct(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3$HGVSc)
[1] 117
Divide into groups stratified by age (<60/>=60) and presence/absence of FHx, and output files.
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios_ageUnder60 <- filter(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3,Reported.Age.Dx<60) %>%
write_excel_csv(path="masterfile_eoc_altAF0.25_HIGH_ENSTcanonical_ageUnder60.csv",na=".",append=FALSE,col_names=TRUE)
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios_ageOver60 <- filter(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3,Reported.Age.Dx>=60) %>%
write_excel_csv(path="masterfile_eoc_altAF0.25_HIGH_ENSTcanonical_ageOver60.csv",na=".",append=FALSE,col_names=TRUE)
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios_FHx <- filter(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3,FHx%in%c("YES")) %>%
write_excel_csv(path="masterfile_eoc_altAF0.25_HIGH_ENSTcanonical_FHx.csv",na=".",append=FALSE,col_names=TRUE)
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios_noFHx <-
filter(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3,!FHx%in%c("YES")) %>%
write_excel_csv(path="masterfile_eoc_altAF0.25_HIGH_ENSTcanonical_noFHx.csv",na=".",append=FALSE,col_names=TRUE)
Identify ViP samples with and without low-frequency variants post-filtering (incl age/FHx distribution), and perform simple linear regression comparison for age vs presence of low-frequency variants
ViP_LowFreqVar_Samples <- select(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3,Sample) %>% distinct(.keep_all=FALSE)
ViP_noLowFreqVar_Samples <- filter(ViP_Discovery_Cohort,!Exome.ID%in%ViP_LowFreqVar_Samples$Sample)
ViP_noLowFreqVar_Path <- filter(ViP_OvCa_Path_Data,Sample%in%ViP_noLowFreqVar_Samples$Exome.ID)
ViP_LowFreqVar_Path <- filter(ViP_OvCa_Path_Data,Sample%in%ViP_LowFreqVar_Samples$Sample)
ViP_FHx <- select(masterfile_eoc4,Sample,FHx) %>%
distinct(.keep_all=FALSE)
FHx <- filter(ViP_FHx,FHx=="YES")
NoFHx <- filter(ViP_FHx,FHx=="NO")
FHx_LowFreqVar <- filter(FHx,Sample%in%ViP_LowFreqVar_Samples$Sample)
NoFHx_LowFreqVar <- filter(NoFHx,Sample%in%ViP_LowFreqVar_Samples$Sample)
FHx_noLowFreqVar <- filter(FHx,Sample%in%ViP_noLowFreqVar_Samples$Exome.ID)
NoFHxCa_noLowFreqVar <- filter(NoFHx,Sample%in%ViP_noLowFreqVar_Samples$Exome.ID)
ViP_noLowFreqVar_Path %>% mutate(age_group = ifelse(Reported.Age.Dx <30,"<30",
ifelse(Reported.Age.Dx < 40,"30-39",
ifelse(Reported.Age.Dx < 50,"40-49",
ifelse(Reported.Age.Dx < 60,"50-59",
ifelse(Reported.Age.Dx < 70,"60-69",
ifelse(Reported.Age.Dx < 80,"70-79",">80")))))))%>%
group_by(age_group)%>%
count()
ViP_LowFreqVar_Path %>% mutate(age_group = ifelse(Reported.Age.Dx <30,"<30",
ifelse(Reported.Age.Dx < 40,"30-39",
ifelse(Reported.Age.Dx < 50,"40-49",
ifelse(Reported.Age.Dx < 60,"50-59",
ifelse(Reported.Age.Dx < 70,"60-69",
ifelse(Reported.Age.Dx < 80,"70-79",">80")))))))%>%
group_by(age_group)%>%
count()
Low_vs_noLowFreqVar <- bind_rows(ViP_LowFreqVar_Path,ViP_noLowFreqVar_Path,.id = "LowFreq_status")
Low_vs_noLowFreqVar$LowFreq_status <- as.factor(Low_vs_noLowFreqVar$LowFreq_status)
Age_lm <- lm(Reported.Age.Dx~LowFreq_status,Low_vs_noLowFreqVar)
summary(Age_lm)
Call:
lm(formula = Reported.Age.Dx ~ LowFreq_status, data = Low_vs_noLowFreqVar)
Residuals:
Min 1Q Median 3Q Max
-36.640 -7.386 0.614 7.614 28.614
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 61.6400 0.9157 67.312 <2e-16 ***
LowFreq_status2 -2.2539 1.0899 -2.068 0.0392 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 11.22 on 508 degrees of freedom
Multiple R-squared: 0.008347, Adjusted R-squared: 0.006395
F-statistic: 4.276 on 1 and 508 DF, p-value: 0.03916
Extract DNA repair gene variants from sample data by repair pathway, and combine into one table
DNArepair_other_list <- tibble("SYMBOL"=c("XRCC1","PARP1","PARP2","APEX1","FEN1","OGG1","UNG","SMUG1","MBD4","TDG","MUTYH","NTHL1","MPG","NEIL1","NEIL2","NEIL3","APEX2","PNKP","APLF","PARP3","MSH3","MSH4","MSH5","MLH3","PMS1","PMS2P3","EXO1","RFC1","RFC2","RFC3","RFC4","RFC5","PCNA","ERCC4","ERCC2","ERCC5","XPC","ERCC6","GTF2H2","ERCC3","XPA","RAD23B","POLE","POLD1","RAD23A","LIG3","CETN2","DDB1","DDB2","GTF2H1","GTF2H3","GTF2H4","GTF2H5","CDK7","CCNH","MNAT1","LIG1","ERCC8","UVSSA","XAB2","MMS19","ATM","RPA1","RPA2","RPA3","RPA4","RAD51","NBN","RAD50","CHEK2","MRE11A","RAD52","RAD51B","DMC1","XRCC2","XRCC3","RAD54L","RAD54B","SHFM1","RBBP8","SLX1A","SLX1B","GEN1","ATR","ERCC1","FANCA","FANCB","FANCC","FANCD2","FANCE","FANCF","FANCG","FANCI","FANCL","FANCM","PALB2","CHEK1","SLX4","FAN1","C1orf86","C19orf40","MUS81","EME1","XRCC6","XRCC5","PRKDC","LIG4","XRCC4","DCLRE1C","NHEJ1","MGMT","ALKBH2","ALKBH3","PAXIP1","BLM","KMT2C","CRIP1","CDK12","BAP1","BARD1","WRN","BUB1","CENPE","ZW10","TTK","KNTC1","AURKB","POLB","POLH","POLQ","TDP1","TDP2","NUDT1","DUT","RRM2B","POLG","REV3L","MAD2L2","REV1","POLI","POLK","POLL","POLM","POLN","TREX1","TREX2","APTX","SPO11","ENDOV","UBE2A","UBE2B","RAD18","SHPRH","HLTF","RNF168","SPRTN","RNF8","RNF4","UBE2V2","UBE2N","H2AFX","CHAF1A","SETMAR","RECQL4","MPLKIP","DCLRE1A","DCLRE1B","PRPF19","RECQL","RECQL5","HELQ","RDM1","NABP2","ATRIP","MDC1","RAD1","RAD9A","HUS1","RAD17","TP53","TP53BP1","TOPBP1","CLK2","PER1","MLH1","MSH2","MSH6","PMS2","TP53","RAD51C","RAD51D","BRIP1","BRCA1","BRCA2"))
masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios_DNArepair_other <- filter(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios3,SYMBOL%in%DNArepair_other_list$SYMBOL) %>% write_excel_csv(path="masterfile_eoc_altAF0.25_HIGH_ENSTcanonical_DNArepair_other.csv",na=".",append=FALSE,col_names=TRUE)
DNA repair gene filtering figures
n_distinct(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios_DNArepair_other$Sample)
[1] 5
n_distinct(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios_DNArepair_other$Gene)
[1] 4
n_distinct(masterfile_eoc_lowFreq_HIGH_ENSTcanonical_withGnomADstats_ratios_DNArepair_other$HGVSc)
[1] 5
LS0tCnRpdGxlOiAiVGhlc2lzIExvdy1GcmVxdWVuY3kgRE5BIFJlcGFpciBHZW5lcyBTb21hdGljIExvRiBWYXJpYW50cyBGaWx0ZXJpbmcgU2NyaXB0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpBTEwgSU1QT1JURUQgRklMRVMgTVVTVCBCRSBJTiBUSEUgU0FNRSBESVJFQ1RPUlkgQVMgVEhJUyBTQ1JJUFQKCkxvYWQgdGlkeXZlcnNlIHBhY2thZ2UKYGBge3J9CnNldHdkKCJ+L09uZURyaXZlIC0gVGhlIFVuaXZlcnNpdHkgb2YgTWVsYm91cm5lL1IgZGF0YSIpCmxpYnJhcnkoInRpZHl2ZXJzZSIpCmBgYAoKSW1wb3J0IHJhdyB2Y2YgZGF0YSBmcm9tICJtYXN0ZXJmaWxlIiBhbmQgZXhjbHVkZSB2YXJpYW50cyB3aXRoIEdub21BRCBub24tY2FuY2VyIEFGID4gMApgYGB7cn0KbWFzdGVyZmlsZSA8LSByZWFkLmRlbGltKCJtYXN0ZXJmaWxlLnRzdiIsIGhlYWRlcj1UUlVFLCByb3cubmFtZXM9TlVMTCwgbmEuc3RyaW5ncyA9ICIuIiwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoIlNhbXBsZSI9IlguU2FtcGxlIikgJT4lIAogIGZpbHRlcihHbm9tQURfdjIuMV9ub25fY2FuY2VyX0FGPT0wKQpgYGAKCkV4Y2x1ZGUgbm9uLWVwaXRoZWxpYWwsIHV0ZXJpbmUtb25seSBhbmQgQlJDQSArdmUgc2FtcGxlcwpgYGB7cn0KVmlQX0NvbXBsZXRlX0NvaG9ydCA8LSByZWFkLmRlbGltKCJWaVBfTG9GX0NvbXBsZXRlX0NvaG9ydC50eHQiLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQpWaVBfQ29tcGxldGVfQ29ob3J0X2xpc3QgPC0gVmlQX0NvbXBsZXRlX0NvaG9ydFssMV0KCm1hc3RlcmZpbGVfZW9jIDwtIGZpbHRlcihtYXN0ZXJmaWxlLFNhbXBsZSVpbiVjKFZpUF9Db21wbGV0ZV9Db2hvcnRfbGlzdCkpCmBgYAoKQXBwZW5kIHBhdGllbnQgcGF0aCBkYXRhIGFuZCBmYW1pbHkgaGlzdG9yeSBpbmZvCmBgYHtyfQpWaVBfT3ZDYV9QYXRoX0RhdGEgPC0gcmVhZC5kZWxpbSgiVmlQX092Q2FfUGF0aF9EYXRhLnR4dCIsIGhlYWRlcj1UUlVFLCByb3cubmFtZXM9TlVMTCwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoIlNhbXBsZSI9RXhvbWUuSUQpCk5vRkh4Q2EgPC0gcmVhZC5kZWxpbSgiTm9GSHhDYS50c3YiLCBoZWFkZXI9VFJVRSwgcm93Lm5hbWVzPU5VTEwsIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpICU+JSAKICBzZWxlY3QoRXhvbWUuSUQsRkh4KSAlPiUgCiAgZHBseXI6OnJlbmFtZSgiU2FtcGxlIj1FeG9tZS5JRCkKbWFzdGVyZmlsZV9lb2MyIDwtIGxlZnRfam9pbihtYXN0ZXJmaWxlX2VvYyxWaVBfT3ZDYV9QYXRoX0RhdGEsYnk9IlNhbXBsZSIsY29weT1GQUxTRSkgJT4lIAogIGxlZnRfam9pbihOb0ZIeENhLGJ5PSJTYW1wbGUiLGNvcHk9RkFMU0UpICU+JSAKICBtdXRhdGVfYXQodmFycygiRkh4IiksZnVucyhyZXBsYWNlKC4sIGlzLm5hKC4pLCAiWUVTIikpKQpgYGAKCkV4Y2x1ZGUgb3RoZXIgbXV0YXRpb24gK3ZlIHNhbXBsZXMgKE1MSDEvTVNIMi9NU0g2L1BNUzIsIFRQNTMsIFJBRDUxQy9ELCBCUklQMSkKYGBge3J9ClZpUF9EaXNjb3ZlcnlfQ29ob3J0IDwtIHJlYWQuZGVsaW0oIlZpUF9Mb0ZfRGlzY292ZXJ5X0NvaG9ydC50eHQiLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQpWaVBfRGlzY292ZXJ5X0NvaG9ydF9saXN0IDwtIFZpUF9EaXNjb3ZlcnlfQ29ob3J0WywxXQoKbWFzdGVyZmlsZV9lb2MzIDwtIGZpbHRlcihtYXN0ZXJmaWxlX2VvYzIsU2FtcGxlJWluJWMoVmlQX0Rpc2NvdmVyeV9Db2hvcnRfbGlzdCkpCmBgYAoKQWRkIFNhbXBsZSBBRC9EUCBjb2x1bW4gdG8gY2FsY3VsYXRlIHJlYWQgZnJlcSBmb3IgdmFyaWFudHMgd2l0aCBtaXNzaW5nIFBNQ0ZSRVEgdmFsdWVzCmBgYHtyfQptYXN0ZXJmaWxlX2VvYzQgPC0gbXV0YXRlKG1hc3RlcmZpbGVfZW9jMywgQUQgPSBhcy5udW1lcmljKHNhcHBseShzdHJzcGxpdChTYW1wbGUuQUQsIiwiKSwgZnVuY3Rpb24oeCkgdGFpbCh4LDEpKSksIERQID0gYXMubnVtZXJpYyhTYW1wbGUuRFApLCBTYW1wbGUuRlJFUSA9IEFEL0RQKQoKVG90YWxfU2FtcGxlX0FsbGVsZXMgPC0gKG5fZGlzdGluY3QobWFzdGVyZmlsZV9lb2M0JFNhbXBsZSkqMikKYGBgCgpFeGNsdWRlIGxvdy1xdWFsaXR5IHZhcmlhbnRzLCBHbm9tQUQgUkYvSW5icmVlZGluZ0NvZWZmLWZsYWdnZWQgdmFyaWFudHMKYGBge3J9Cm1hc3RlcmZpbGVfZW9jX2xvd0ZyZXEgPC0gZmlsdGVyKG1hc3RlcmZpbGVfZW9jNCwgKFFVQUw+PTMwKSYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKElkZW50aWZpZWQhPSJGaWx0ZXJlZEluQWxsIikmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTYW1wbGUuUE1DRFA+PTIwKSYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFNhbXBsZS5QTUNGUkVRPDAuMjUpJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU2FtcGxlLkZSRVE8MC4yNSkpICU+JSAKICBmaWx0ZXIoU2FtcGxlLkZSRVE+PTAuMDEpICU+JSAKICBmaWx0ZXIoKCFzdHJfZGV0ZWN0KEdub21BRF92Mi4xX0ZJTFRFUl9leG9tZSwiSW5icmVlZGluZ0NvZWZmIikmCiAgICAgICAgICAgICFzdHJfZGV0ZWN0KEdub21BRF92Mi4xX0ZJTFRFUl9leG9tZSwiUkYiKSl8CiAgICAgICAgICAgaXMubmEoR25vbUFEX3YyLjFfRklMVEVSX2V4b21lKSkgJT4lCiAgZmlsdGVyKCghc3RyX2RldGVjdChHbm9tQURfdjIuMV9GSUxURVJfZ2Vub21lLCJJbmJyZWVkaW5nQ29lZmYiKSYKICAgICAgICAgICAgIXN0cl9kZXRlY3QoR25vbUFEX3YyLjFfRklMVEVSX2dlbm9tZSwiUkYiKSl8CiAgICAgICAgICAgaXMubmEoR25vbUFEX3YyLjFfRklMVEVSX2dlbm9tZSkpCmBgYAoKUmVtb3ZlIEhBUC1vbmx5IGluZGVsIHZhcmlhbnRzIHdpdGggUE1DRlJFUT09MApgYGB7cn0KbWFzdGVyZmlsZV9lb2NfbG93RnJlcV9IQVBfU05WIDwtIGZpbHRlcihtYXN0ZXJmaWxlX2VvY19sb3dGcmVxLFNhbXBsZS5QTUNGUkVRPT0wKSAlPiUgCiAgZmlsdGVyKFZhcmlhbnRfVHlwZT09IlNOViIpCm1hc3RlcmZpbGVfZW9jX2xvd0ZyZXEyIDwtIGZpbHRlcihtYXN0ZXJmaWxlX2VvY19sb3dGcmVxLFNhbXBsZS5QTUNGUkVRIT0wKSAlPiUgCiAgYmluZF9yb3dzKG1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSEFQX1NOViwuaWQ9TlVMTCkKYGBgCgpFeGNsdWRlIE1PREVSQVRFIGltcGFjdCB2YXJpYW50cwpgYGB7cn0KbWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIIDwtIGZpbHRlcihtYXN0ZXJmaWxlX2VvY19sb3dGcmVxMiwgSU1QQUNUPT0iSElHSCIpCmBgYAoKU2VwYXJhdGUgRW5zZW1ibCBjYW5vbmljYWwgYW5kIFJlZlNlcSBjYW5vbmljYWwgdmFyaWFudHMKYGBge3J9Cm1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsIDwtIGZpbHRlcihtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0gsQ0FOT05JQ0FMPT0iWUVTIikgJT4lIAogIHdyaXRlX2V4Y2VsX2NzdihwYXRoPSJtYXN0ZXJmaWxlX2VvY19hbHRBRjAuMjVfSElHSF9FTlNUY2Fub25pY2FsLmNzdiIsbmE9Ii4iLGFwcGVuZD1GQUxTRSxjb2xfbmFtZXM9VFJVRSkKYGBgCgpTYW1wbGUgdmFyaWFudCBjb3VudHMgYW5kIEFGcwpgYGB7cn0KdmFyaWFudF9jb3VudHNfQUZzIDwtIGZ1bmN0aW9uKHZjZil7CnZhcmlhbnRzX2hldGVyb3p5Z291cyA8LSB2Y2YgJT4lIAogIHNlbGVjdChIR1ZTYyxTYW1wbGUuR1QpICU+JSAKICBncm91cF9ieShIR1ZTYyxTYW1wbGUuR1QpICU+JSAKICBzdW1tYXJpc2UobigpKSAlPiUgCiAgZmlsdGVyKChTYW1wbGUuR1QlaW4lYygiJzAvMSIsIicxLzAiKSkpICU+JSAKICBkcGx5cjo6cmVuYW1lKGFsbGVsZXMgPSAibigpIikgJT4lIAogIGdyb3VwX2J5KEhHVlNjKSAlPiUgCiAgc3VtbWFyaXNlKHN1bShhbGxlbGVzKSkKdmFyaWFudHNfaG9tb3p5Z291cyA8LSB2Y2YgJT4lIAogIHNlbGVjdChIR1ZTYyxTYW1wbGUuR1QpICU+JSAKICBncm91cF9ieShIR1ZTYyxTYW1wbGUuR1QpICU+JSAKICBzdW1tYXJpc2UobigpKSAlPiUgCiAgZmlsdGVyKChTYW1wbGUuR1QhPSInMC8xIikmKFNhbXBsZS5HVCE9IicxLzAiKSkgJT4lIAogIG11dGF0ZShhbGxlbGVzID0gYG4oKWAqMikgJT4lIAogIHNlbGVjdCgtYG4oKWApICU+JSAKICBncm91cF9ieShIR1ZTYykgJT4lIAogIHN1bW1hcmlzZShzdW0oYWxsZWxlcykpCnZhcmlhbnRzIDwtIGZ1bGxfam9pbih2YXJpYW50c19oZXRlcm96eWdvdXMsdmFyaWFudHNfaG9tb3p5Z291cyxieT0iSEdWU2MiLGNvcHk9RkFMU0Usc3VmZml4PWMoIi54IiwiLnkiKSkgJT4lCiAgbXV0YXRlX2FsbChmdW5zKHJlcGxhY2UoLiwgaXMubmEoLiksIDApKSkgJT4lIAogIG11dGF0ZShUb3RhbF9BbGxlbGVfQ291bnQ9YHN1bShhbGxlbGVzKS54YCtgc3VtKGFsbGVsZXMpLnlgKSAlPiUgCiAgbXV0YXRlKFNhbXBsZV9BRj1Ub3RhbF9BbGxlbGVfQ291bnQvVG90YWxfU2FtcGxlX0FsbGVsZXMpCnZjZiA8LSBsZWZ0X2pvaW4odmNmLCB2YXJpYW50c1ssYygxLDQ6NSldLGJ5PSJIR1ZTYyIsY29weT1GQUxTRSkKfQoKbWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfMiA8LSB2YXJpYW50X2NvdW50c19BRnMobWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWwpCmBgYAoKU2FtcGxlIGdlbmUgY291bnRzIGFuZCBmcmVxdWVuY2llcwpgYGB7cn0KZ2VuZV9jb3VudHNfQUYgPC0gZnVuY3Rpb24odmNmKXsKZ2VuZXNfb25lVmFyQWxsZWxlIDwtIHZjZiAlPiUgc2VsZWN0KFNZTUJPTCxTYW1wbGUuR1QpICU+JSAKICBzZWxlY3QoU1lNQk9MLFNhbXBsZS5HVCkgJT4lIAogIGdyb3VwX2J5KFNZTUJPTCxTYW1wbGUuR1QpICU+JSAKICBzdW1tYXJpc2UobigpKSAlPiUgCiAgZmlsdGVyKChTYW1wbGUuR1QlaW4lYygiJzAvMSIsIicxLzAiKSkpICU+JSAKICBkcGx5cjo6cmVuYW1lKGdlbmVfVmFyID0gIm4oKSIpICU+JSAKICBncm91cF9ieShTWU1CT0wpICU+JSAKICBzdW1tYXJpc2Uoc3VtKGdlbmVfVmFyKSkKZ2VuZXNfdHdvVmFyQWxsZWxlIDwtIHZjZiAlPiUgc2VsZWN0KFNZTUJPTCxTYW1wbGUuR1QpICU+JSAKICBzZWxlY3QoU1lNQk9MLFNhbXBsZS5HVCkgJT4lIAogIGdyb3VwX2J5KFNZTUJPTCxTYW1wbGUuR1QpICU+JSAKICBzdW1tYXJpc2UobigpKSAlPiUgCiAgZmlsdGVyKChTYW1wbGUuR1QhPSInMC8xIikmKFNhbXBsZS5HVCE9IicxLzAiKSkgJT4lIAogIG11dGF0ZShnZW5lX1ZhciA9IGBuKClgKjIpICU+JSAKICBzZWxlY3QoLWBuKClgKSAlPiUgCiAgZ3JvdXBfYnkoU1lNQk9MKSAlPiUgCiAgc3VtbWFyaXNlKHN1bShnZW5lX1ZhcikpCmdlbmVzIDwtIGZ1bGxfam9pbihnZW5lc19vbmVWYXJBbGxlbGUsZ2VuZXNfdHdvVmFyQWxsZWxlLGJ5PSJTWU1CT0wiLGNvcHk9RkFMU0Usc3VmZml4PWMoIi54IiwiLnkiKSkgJT4lIAogIG11dGF0ZV9hbGwoZnVucyhyZXBsYWNlKC4sIGlzLm5hKC4pLCAwKSkpICU+JSAKICBtdXRhdGUoVG90YWxfR2VuZV9Db3VudD1gc3VtKGdlbmVfVmFyKS54YCtgc3VtKGdlbmVfVmFyKS55YCkgJT4lIAogIG11dGF0ZShTYW1wbGVfR2VuZV9GcmVxPVRvdGFsX0dlbmVfQ291bnQvVG90YWxfU2FtcGxlX0FsbGVsZXMpCnZjZiA8LSBsZWZ0X2pvaW4odmNmLCBnZW5lc1ssYygxLDQ6NSldLGJ5PSJTWU1CT0wiLGNvcHk9RkFMU0UpCn0KCm1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsXzMgPC0gZ2VuZV9jb3VudHNfQUYobWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfMikKYGBgCgpBZGQgR25vbUFEIGdlbmUtbGV2ZWwgZGF0YQpgYGB7cn0KR25vbUFEX3N0YXRzX0xPRl9WRVAgPC0gcmVhZC5kZWxpbSgiR25vbUFEX3N0YXRzX0xPRl9WRVAudHN2IiwgaGVhZGVyPVRSVUUsIHJvdy5uYW1lcz1OVUxMLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQoKbWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzIDwtIGxlZnRfam9pbihtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF8zLCBHbm9tQURfc3RhdHNfTE9GX1ZFUFssYygyLDMwOjQxKV0sYnk9IkZlYXR1cmUiLGNvcHk9RkFMU0UpIAptYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHMyIDwtIG11dGF0ZV9hdChtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHMsdmFycyhzdGFydHNfd2l0aCgiRklMVEVSXyIpKSxmdW5zKHJlcGxhY2UoLiwgaXMubmEoLiksIDApKSkgJT4lIAogIG11dGF0ZV9pZihncmVwbCgicG9wbWF4JCIsIG5hbWVzKC4pKSxmdW5zKGlmZWxzZSguID09ICJOQSIsIDAsIGFzLm51bWVyaWMoLikpKSkgJT4lIAogIG11dGF0ZV9hdCh2YXJzKGVuZHNfd2l0aCgicG9wbWF4IikpLGZ1bnMocmVwbGFjZSguLCBpcy5uYSguKSwgMCkpKQpgYGAKCkNhbGN1bGF0ZSBTYW1wbGUvR25vbUFEIGdlbmUgZnJlcSByYXRpb3MgZm9yIHRvdGFsIGFuZCBORkUgR25vbUFEIGZpZ3VyZXMsIGluY2x1ZGluZyBhbmQgZXhjbHVkaW5nIHZhcmlhbnRzIHdpdGggQUYgPiAwLjAwNQpgYGB7cn0KbWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzX3JhdGlvcyA8LSAKICBtdXRhdGUobWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzMiwgIlNhbXBsZV9HZW5lX0xPRl9GcmVxX1JhdGlvX0dub21BRCI9U2FtcGxlX0dlbmVfRnJlcS9GSUxURVJfUkZfTE9GX0hJR0hJTVBBQ1RfQUZfMS4wX0FESiwKIlNhbXBsZV9HZW5lX0xPRl9GcmVxX1JhdGlvX0dub21BRF8wLjAwNSI9U2FtcGxlX0dlbmVfRnJlcS9GSUxURVJfUkZfTE9GX0hJR0hJTVBBQ1RfQUZfMC4wMDVfQURKLAoiUmF0aW9fRGlmZmVyZW5jZSI9U2FtcGxlX0dlbmVfTE9GX0ZyZXFfUmF0aW9fR25vbUFEXzAuMDA1LVNhbXBsZV9HZW5lX0xPRl9GcmVxX1JhdGlvX0dub21BRCwgCiJTYW1wbGVfR2VuZV9MT0ZfRnJlcV9SYXRpb19Hbm9tQURfTkZFIj1TYW1wbGVfR2VuZV9GcmVxL0ZJTFRFUl9SRl9MT0ZfSElHSElNUEFDVF9BRl8xLjBfTkZFX0FESiwKIlNhbXBsZV9HZW5lX0xPRl9GcmVxX1JhdGlvX0dub21BRF9ORkVfMC4wMDUiPVNhbXBsZV9HZW5lX0ZyZXEvRklMVEVSX1JGX0xPRl9ISUdISU1QQUNUX0FGXzAuMDA1X05GRV9BREosCiJSYXRpb19EaWZmZXJlbmNlX05GRSI9U2FtcGxlX0dlbmVfTE9GX0ZyZXFfUmF0aW9fR25vbUFEX05GRV8wLjAwNS1TYW1wbGVfR2VuZV9MT0ZfRnJlcV9SYXRpb19Hbm9tQURfTkZFKQpgYGAKCkNhbGN1bGF0ZSBTYW1wbGUvR25vbUFEIGFsbGVsZSBmcmVxIHJhdGlvcyAKYGBge3J9Cm1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3MyIDwtIG11dGF0ZShtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zLCAiU2FtcGxlX0dlbmVfTE9GX0FGX1JhdGlvIj1TYW1wbGVfQUYvR25vbUFEX3YyLjFfbm9uX2NhbmNlcl9BRiwgCiJTYW1wbGVfR2VuZV9MT0ZfQUZfUmF0aW9fTkZFIj1TYW1wbGVfQUYvR25vbUFEX3YyLjFfbm9uX2NhbmNlcl9BRl9uZmUpCmBgYAoKQXR0YWNoIG90aGVyIEdub21BRCBkYXRhIGZvciBETkEgcmVwYWlyIGdlbmVzIGFuYWx5c2lzCmBgYHtyfQptYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zMyA8LSBtdXRhdGUobWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzX3JhdGlvczIsVG90YWxfQ2FzZV9BbGxlbGVzPVRvdGFsX1NhbXBsZV9BbGxlbGVzKSAlPiUgCiAgbGVmdF9qb2luKEdub21BRF9zdGF0c19MT0ZfVkVQWyxjKDIsNiwxMCwxNDoyOSldLGJ5PSJGZWF0dXJlIixjb3B5PUZBTFNFKSAKbWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzX3JhdGlvczQgPC0gbXV0YXRlKG1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3MzLCBNQVhfQU49cmVwbGFjZShtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zMyRNQVhfQU4sIGlzLm5hKG1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3MzJE1BWF9BTiksIG1heChtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zMyRNQVhfQU4sIG5hLnJtPVRSVUUpKSkgJT4lIAogIG11dGF0ZShNQVhfQU5fTkZFPXJlcGxhY2UoLiRNQVhfQU5fTkZFLCBpcy5uYSguJE1BWF9BTl9ORkUpLCBtYXgobWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzX3JhdGlvczMkTUFYX0FOX05GRSwgbmEucm09VFJVRSkpKQpgYGAKClBvc3QtZmlsdGVyaW5nIGZpZ3VyZXMgKEVOU1QsIGV4Y2wuIG11dGF0aW9uICt2ZSBzYW1wbGVzKQpgYGB7cn0Kbl9kaXN0aW5jdChtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zMyRTYW1wbGUpCm5fZGlzdGluY3QobWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzX3JhdGlvczMkR2VuZSkKbl9kaXN0aW5jdChtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zMyRIR1ZTYykKYGBgCgpEaXZpZGUgaW50byBncm91cHMgc3RyYXRpZmllZCBieSBhZ2UgKDw2MC8+PTYwKSBhbmQgcHJlc2VuY2UvYWJzZW5jZSBvZiBGSHgsIGFuZCBvdXRwdXQgZmlsZXMuCmBgYHtyfQptYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zX2FnZVVuZGVyNjAgPC0gZmlsdGVyKG1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3MzLFJlcG9ydGVkLkFnZS5EeDw2MCkgJT4lCiAgd3JpdGVfZXhjZWxfY3N2KHBhdGg9Im1hc3RlcmZpbGVfZW9jX2FsdEFGMC4yNV9ISUdIX0VOU1RjYW5vbmljYWxfYWdlVW5kZXI2MC5jc3YiLG5hPSIuIixhcHBlbmQ9RkFMU0UsY29sX25hbWVzPVRSVUUpCiAgCm1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3NfYWdlT3ZlcjYwIDwtIGZpbHRlcihtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zMyxSZXBvcnRlZC5BZ2UuRHg+PTYwKSAlPiUgCiAgd3JpdGVfZXhjZWxfY3N2KHBhdGg9Im1hc3RlcmZpbGVfZW9jX2FsdEFGMC4yNV9ISUdIX0VOU1RjYW5vbmljYWxfYWdlT3ZlcjYwLmNzdiIsbmE9Ii4iLGFwcGVuZD1GQUxTRSxjb2xfbmFtZXM9VFJVRSkKICAKbWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzX3JhdGlvc19GSHggPC0gZmlsdGVyKG1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3MzLEZIeCVpbiVjKCJZRVMiKSkgJT4lIAogIHdyaXRlX2V4Y2VsX2NzdihwYXRoPSJtYXN0ZXJmaWxlX2VvY19hbHRBRjAuMjVfSElHSF9FTlNUY2Fub25pY2FsX0ZIeC5jc3YiLG5hPSIuIixhcHBlbmQ9RkFMU0UsY29sX25hbWVzPVRSVUUpCiAgCm1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3Nfbm9GSHggPC0gCmZpbHRlcihtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zMywhRkh4JWluJWMoIllFUyIpKSAlPiUgCiAgd3JpdGVfZXhjZWxfY3N2KHBhdGg9Im1hc3RlcmZpbGVfZW9jX2FsdEFGMC4yNV9ISUdIX0VOU1RjYW5vbmljYWxfbm9GSHguY3N2IixuYT0iLiIsYXBwZW5kPUZBTFNFLGNvbF9uYW1lcz1UUlVFKQpgYGAKCklkZW50aWZ5IFZpUCBzYW1wbGVzIHdpdGggYW5kIHdpdGhvdXQgbG93LWZyZXF1ZW5jeSB2YXJpYW50cyBwb3N0LWZpbHRlcmluZyAoaW5jbCBhZ2UvRkh4IGRpc3RyaWJ1dGlvbiksIGFuZCBwZXJmb3JtIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBjb21wYXJpc29uIGZvciBhZ2UgdnMgcHJlc2VuY2Ugb2YgbG93LWZyZXF1ZW5jeSB2YXJpYW50cwpgYGB7cn0KVmlQX0xvd0ZyZXFWYXJfU2FtcGxlcyA8LSBzZWxlY3QobWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzX3JhdGlvczMsU2FtcGxlKSAlPiUgZGlzdGluY3QoLmtlZXBfYWxsPUZBTFNFKQpWaVBfbm9Mb3dGcmVxVmFyX1NhbXBsZXMgPC0gZmlsdGVyKFZpUF9EaXNjb3ZlcnlfQ29ob3J0LCFFeG9tZS5JRCVpbiVWaVBfTG93RnJlcVZhcl9TYW1wbGVzJFNhbXBsZSkKVmlQX25vTG93RnJlcVZhcl9QYXRoIDwtIGZpbHRlcihWaVBfT3ZDYV9QYXRoX0RhdGEsU2FtcGxlJWluJVZpUF9ub0xvd0ZyZXFWYXJfU2FtcGxlcyRFeG9tZS5JRCkKVmlQX0xvd0ZyZXFWYXJfUGF0aCA8LSBmaWx0ZXIoVmlQX092Q2FfUGF0aF9EYXRhLFNhbXBsZSVpbiVWaVBfTG93RnJlcVZhcl9TYW1wbGVzJFNhbXBsZSkKVmlQX0ZIeCA8LSBzZWxlY3QobWFzdGVyZmlsZV9lb2M0LFNhbXBsZSxGSHgpICU+JSAKICBkaXN0aW5jdCgua2VlcF9hbGw9RkFMU0UpCkZIeCA8LSBmaWx0ZXIoVmlQX0ZIeCxGSHg9PSJZRVMiKQpOb0ZIeCA8LSBmaWx0ZXIoVmlQX0ZIeCxGSHg9PSJOTyIpCgpGSHhfTG93RnJlcVZhciA8LSBmaWx0ZXIoRkh4LFNhbXBsZSVpbiVWaVBfTG93RnJlcVZhcl9TYW1wbGVzJFNhbXBsZSkKTm9GSHhfTG93RnJlcVZhciA8LSBmaWx0ZXIoTm9GSHgsU2FtcGxlJWluJVZpUF9Mb3dGcmVxVmFyX1NhbXBsZXMkU2FtcGxlKQpGSHhfbm9Mb3dGcmVxVmFyIDwtIGZpbHRlcihGSHgsU2FtcGxlJWluJVZpUF9ub0xvd0ZyZXFWYXJfU2FtcGxlcyRFeG9tZS5JRCkKTm9GSHhDYV9ub0xvd0ZyZXFWYXIgPC0gZmlsdGVyKE5vRkh4LFNhbXBsZSVpbiVWaVBfbm9Mb3dGcmVxVmFyX1NhbXBsZXMkRXhvbWUuSUQpIAoKVmlQX25vTG93RnJlcVZhcl9QYXRoICU+JSBtdXRhdGUoYWdlX2dyb3VwID0gaWZlbHNlKFJlcG9ydGVkLkFnZS5EeCA8MzAsIjwzMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFJlcG9ydGVkLkFnZS5EeCA8IDQwLCIzMC0zOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShSZXBvcnRlZC5BZ2UuRHggPCA1MCwiNDAtNDkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFJlcG9ydGVkLkFnZS5EeCA8IDYwLCI1MC01OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFJlcG9ydGVkLkFnZS5EeCA8IDcwLCI2MC02OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShSZXBvcnRlZC5BZ2UuRHggPCA4MCwiNzAtNzkiLCI+ODAiKSkpKSkpKSU+JQogIGdyb3VwX2J5KGFnZV9ncm91cCklPiUKICBjb3VudCgpClZpUF9Mb3dGcmVxVmFyX1BhdGggJT4lIG11dGF0ZShhZ2VfZ3JvdXAgPSBpZmVsc2UoUmVwb3J0ZWQuQWdlLkR4IDwzMCwiPDMwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUmVwb3J0ZWQuQWdlLkR4IDwgNDAsIjMwLTM5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFJlcG9ydGVkLkFnZS5EeCA8IDUwLCI0MC00OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUmVwb3J0ZWQuQWdlLkR4IDwgNjAsIjUwLTU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUmVwb3J0ZWQuQWdlLkR4IDwgNzAsIjYwLTY5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFJlcG9ydGVkLkFnZS5EeCA8IDgwLCI3MC03OSIsIj44MCIpKSkpKSkpJT4lCiAgZ3JvdXBfYnkoYWdlX2dyb3VwKSU+JQogIGNvdW50KCkKTG93X3ZzX25vTG93RnJlcVZhciA8LSBiaW5kX3Jvd3MoVmlQX0xvd0ZyZXFWYXJfUGF0aCxWaVBfbm9Mb3dGcmVxVmFyX1BhdGgsLmlkID0gIkxvd0ZyZXFfc3RhdHVzIikKTG93X3ZzX25vTG93RnJlcVZhciRMb3dGcmVxX3N0YXR1cyA8LSBhcy5mYWN0b3IoTG93X3ZzX25vTG93RnJlcVZhciRMb3dGcmVxX3N0YXR1cykKQWdlX2xtIDwtIGxtKFJlcG9ydGVkLkFnZS5EeH5Mb3dGcmVxX3N0YXR1cyxMb3dfdnNfbm9Mb3dGcmVxVmFyKQpzdW1tYXJ5KEFnZV9sbSkKYGBgCgpFeHRyYWN0IEROQSByZXBhaXIgZ2VuZSB2YXJpYW50cyBmcm9tIHNhbXBsZSBkYXRhIGJ5IHJlcGFpciBwYXRod2F5LCBhbmQgY29tYmluZSBpbnRvIG9uZSB0YWJsZQpgYGB7cn0KRE5BcmVwYWlyX290aGVyX2xpc3QgPC0gdGliYmxlKCJTWU1CT0wiPWMoIlhSQ0MxIiwiUEFSUDEiLCJQQVJQMiIsIkFQRVgxIiwiRkVOMSIsIk9HRzEiLCJVTkciLCJTTVVHMSIsIk1CRDQiLCJUREciLCJNVVRZSCIsIk5USEwxIiwiTVBHIiwiTkVJTDEiLCJORUlMMiIsIk5FSUwzIiwiQVBFWDIiLCJQTktQIiwiQVBMRiIsIlBBUlAzIiwiTVNIMyIsIk1TSDQiLCJNU0g1IiwiTUxIMyIsIlBNUzEiLCJQTVMyUDMiLCJFWE8xIiwiUkZDMSIsIlJGQzIiLCJSRkMzIiwiUkZDNCIsIlJGQzUiLCJQQ05BIiwiRVJDQzQiLCJFUkNDMiIsIkVSQ0M1IiwiWFBDIiwiRVJDQzYiLCJHVEYySDIiLCJFUkNDMyIsIlhQQSIsIlJBRDIzQiIsIlBPTEUiLCJQT0xEMSIsIlJBRDIzQSIsIkxJRzMiLCJDRVROMiIsIkREQjEiLCJEREIyIiwiR1RGMkgxIiwiR1RGMkgzIiwiR1RGMkg0IiwiR1RGMkg1IiwiQ0RLNyIsIkNDTkgiLCJNTkFUMSIsIkxJRzEiLCJFUkNDOCIsIlVWU1NBIiwiWEFCMiIsIk1NUzE5IiwiQVRNIiwiUlBBMSIsIlJQQTIiLCJSUEEzIiwiUlBBNCIsIlJBRDUxIiwiTkJOIiwiUkFENTAiLCJDSEVLMiIsIk1SRTExQSIsIlJBRDUyIiwiUkFENTFCIiwiRE1DMSIsIlhSQ0MyIiwiWFJDQzMiLCJSQUQ1NEwiLCJSQUQ1NEIiLCJTSEZNMSIsIlJCQlA4IiwiU0xYMUEiLCJTTFgxQiIsIkdFTjEiLCJBVFIiLCJFUkNDMSIsIkZBTkNBIiwiRkFOQ0IiLCJGQU5DQyIsIkZBTkNEMiIsIkZBTkNFIiwiRkFOQ0YiLCJGQU5DRyIsIkZBTkNJIiwiRkFOQ0wiLCJGQU5DTSIsIlBBTEIyIiwiQ0hFSzEiLCJTTFg0IiwiRkFOMSIsIkMxb3JmODYiLCJDMTlvcmY0MCIsIk1VUzgxIiwiRU1FMSIsIlhSQ0M2IiwiWFJDQzUiLCJQUktEQyIsIkxJRzQiLCJYUkNDNCIsIkRDTFJFMUMiLCJOSEVKMSIsIk1HTVQiLCJBTEtCSDIiLCJBTEtCSDMiLCJQQVhJUDEiLCJCTE0iLCJLTVQyQyIsIkNSSVAxIiwiQ0RLMTIiLCJCQVAxIiwiQkFSRDEiLCJXUk4iLCJCVUIxIiwiQ0VOUEUiLCJaVzEwIiwiVFRLIiwiS05UQzEiLCJBVVJLQiIsIlBPTEIiLCJQT0xIIiwiUE9MUSIsIlREUDEiLCJURFAyIiwiTlVEVDEiLCJEVVQiLCJSUk0yQiIsIlBPTEciLCJSRVYzTCIsIk1BRDJMMiIsIlJFVjEiLCJQT0xJIiwiUE9MSyIsIlBPTEwiLCJQT0xNIiwiUE9MTiIsIlRSRVgxIiwiVFJFWDIiLCJBUFRYIiwiU1BPMTEiLCJFTkRPViIsIlVCRTJBIiwiVUJFMkIiLCJSQUQxOCIsIlNIUFJIIiwiSExURiIsIlJORjE2OCIsIlNQUlROIiwiUk5GOCIsIlJORjQiLCJVQkUyVjIiLCJVQkUyTiIsIkgyQUZYIiwiQ0hBRjFBIiwiU0VUTUFSIiwiUkVDUUw0IiwiTVBMS0lQIiwiRENMUkUxQSIsIkRDTFJFMUIiLCJQUlBGMTkiLCJSRUNRTCIsIlJFQ1FMNSIsIkhFTFEiLCJSRE0xIiwiTkFCUDIiLCJBVFJJUCIsIk1EQzEiLCJSQUQxIiwiUkFEOUEiLCJIVVMxIiwiUkFEMTciLCJUUDUzIiwiVFA1M0JQMSIsIlRPUEJQMSIsIkNMSzIiLCJQRVIxIiwiTUxIMSIsIk1TSDIiLCJNU0g2IiwiUE1TMiIsIlRQNTMiLCJSQUQ1MUMiLCJSQUQ1MUQiLCJCUklQMSIsIkJSQ0ExIiwiQlJDQTIiKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zX0ROQXJlcGFpcl9vdGhlciA8LSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIobWFzdGVyZmlsZV9lb2NfbG93RnJlcV9ISUdIX0VOU1RjYW5vbmljYWxfd2l0aEdub21BRHN0YXRzX3JhdGlvczMsU1lNQk9MJWluJUROQXJlcGFpcl9vdGhlcl9saXN0JFNZTUJPTCkgJT4lIHdyaXRlX2V4Y2VsX2NzdihwYXRoPSJtYXN0ZXJmaWxlX2VvY19hbHRBRjAuMjVfSElHSF9FTlNUY2Fub25pY2FsX0ROQXJlcGFpcl9vdGhlci5jc3YiLG5hPSIuIixhcHBlbmQ9RkFMU0UsY29sX25hbWVzPVRSVUUpCmBgYAoKRE5BIHJlcGFpciBnZW5lIGZpbHRlcmluZyBmaWd1cmVzCmBgYHtyfQpuX2Rpc3RpbmN0KG1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3NfRE5BcmVwYWlyX290aGVyJFNhbXBsZSkKbl9kaXN0aW5jdChtYXN0ZXJmaWxlX2VvY19sb3dGcmVxX0hJR0hfRU5TVGNhbm9uaWNhbF93aXRoR25vbUFEc3RhdHNfcmF0aW9zX0ROQXJlcGFpcl9vdGhlciRHZW5lKQpuX2Rpc3RpbmN0KG1hc3RlcmZpbGVfZW9jX2xvd0ZyZXFfSElHSF9FTlNUY2Fub25pY2FsX3dpdGhHbm9tQURzdGF0c19yYXRpb3NfRE5BcmVwYWlyX290aGVyJEhHVlNjKQpgYGAK