Data import

Read in data sets for BLAST annotation, PFAM annotation and I-TASSER output metrics

GeneDesc <- read_tsv("../data/GiardiaDB-39_GintestinalisAssemblageA_AnnotatedProteins.description",
                     col_names = FALSE, col_types = cols())
names(GeneDesc) <- c('GeneID','Description')
metrics_df <- read.delim("../data/metrics_clean.txt",sep="\t", stringsAsFactors = FALSE, quote="", header=TRUE)
mismatch_BLAST <- read_tsv("../data/mismatches_BLAST.tsv", col_types = cols())
PDB_pfam <- read_tsv("../data/hmmer_pdb_all.txt", col_types = cols())  #accessed in Oct 2017

|=======                                                                                                     |   7%    1 MB
|========                                                                                                    |   7%    1 MB
|========                                                                                                    |   8%    1 MB
|=========                                                                                                   |   8%    1 MB
|==========                                                                                                  |   9%    1 MB
|==========                                                                                                  |   9%    1 MB
|===========                                                                                                 |  10%    1 MB
|===========                                                                                                 |  10%    1 MB
|============                                                                                                |  11%    1 MB
|============                                                                                                |  11%    2 MB
|=============                                                                                               |  12%    2 MB
|=============                                                                                               |  12%    2 MB
|==============                                                                                              |  13%    2 MB
|==============                                                                                              |  13%    2 MB
|===============                                                                                             |  14%    2 MB
|===============                                                                                             |  14%    2 MB
|================                                                                                            |  14%    2 MB
|================                                                                                            |  15%    2 MB
|=================                                                                                           |  15%    2 MB
|=================                                                                                           |  16%    2 MB
|==================                                                                                          |  16%    3 MB
|==================                                                                                          |  17%    3 MB
|===================                                                                                         |  17%    3 MB
|====================                                                                                        |  18%    3 MB
|====================                                                                                        |  18%    3 MB
|=====================                                                                                       |  19%    3 MB
|=====================                                                                                       |  19%    3 MB
|======================                                                                                      |  20%    3 MB
|======================                                                                                      |  20%    3 MB
|=======================                                                                                     |  21%    3 MB
|=======================                                                                                     |  21%    3 MB
|========================                                                                                    |  22%    3 MB
|========================                                                                                    |  22%    4 MB
|=========================                                                                                   |  23%    4 MB
|=========================                                                                                   |  23%    4 MB
|==========================                                                                                  |  24%    4 MB
|==========================                                                                                  |  24%    4 MB
|===========================                                                                                 |  25%    4 MB
|===========================                                                                                 |  25%    4 MB
|============================                                                                                |  26%    4 MB
|============================                                                                                |  26%    4 MB
|=============================                                                                               |  27%    4 MB
|==============================                                                                              |  27%    4 MB
|==============================                                                                              |  28%    4 MB
|===============================                                                                             |  28%    5 MB
|===============================                                                                             |  29%    5 MB
|================================                                                                            |  29%    5 MB
|================================                                                                            |  29%    5 MB
|=================================                                                                           |  30%    5 MB
|=================================                                                                           |  30%    5 MB
|==================================                                                                          |  31%    5 MB
|==================================                                                                          |  31%    5 MB
|===================================                                                                         |  32%    5 MB
|===================================                                                                         |  32%    5 MB
|====================================                                                                        |  33%    5 MB
|====================================                                                                        |  33%    6 MB
|=====================================                                                                       |  34%    6 MB
|=====================================                                                                       |  34%    6 MB
|======================================                                                                      |  35%    6 MB
|======================================                                                                      |  35%    6 MB
|=======================================                                                                     |  36%    6 MB
|========================================                                                                    |  36%    6 MB
|========================================                                                                    |  37%    6 MB
|=========================================                                                                   |  37%    6 MB
|=========================================                                                                   |  38%    6 MB
|==========================================                                                                  |  38%    6 MB
|==========================================                                                                  |  39%    6 MB
|===========================================                                                                 |  39%    7 MB
|===========================================                                                                 |  40%    7 MB
|============================================                                                                |  40%    7 MB
|============================================                                                                |  41%    7 MB
|=============================================                                                               |  41%    7 MB
|=============================================                                                               |  42%    7 MB
|==============================================                                                              |  42%    7 MB
|==============================================                                                              |  43%    7 MB
|===============================================                                                             |  43%    7 MB
|===============================================                                                             |  43%    7 MB
|================================================                                                            |  44%    7 MB
|================================================                                                            |  44%    7 MB
|=================================================                                                           |  45%    8 MB
|==================================================                                                          |  45%    8 MB
|==================================================                                                          |  46%    8 MB
|===================================================                                                         |  46%    8 MB
|===================================================                                                         |  47%    8 MB
|====================================================                                                        |  47%    8 MB
|====================================================                                                        |  48%    8 MB
|=====================================================                                                       |  48%    8 MB
|=====================================================                                                       |  49%    8 MB
|======================================================                                                      |  49%    8 MB
|======================================================                                                      |  50%    8 MB
|=======================================================                                                     |  50%    9 MB
|=======================================================                                                     |  51%    9 MB
|========================================================                                                    |  51%    9 MB
|========================================================                                                    |  52%    9 MB
|=========================================================                                                   |  52%    9 MB
|=========================================================                                                   |  53%    9 MB
|==========================================================                                                  |  53%    9 MB
|===========================================================                                                 |  54%    9 MB
|===========================================================                                                 |  54%    9 MB
|============================================================                                                |  55%    9 MB
|============================================================                                                |  55%    9 MB
|=============================================================                                               |  56%    9 MB
|=============================================================                                               |  56%   10 MB
|==============================================================                                              |  57%   10 MB
|==============================================================                                              |  57%   10 MB
|===============================================================                                             |  57%   10 MB
|===============================================================                                             |  58%   10 MB
|================================================================                                            |  58%   10 MB
|================================================================                                            |  59%   10 MB
|=================================================================                                           |  59%   10 MB
|=================================================================                                           |  60%   10 MB
|==================================================================                                          |  60%   10 MB
|==================================================================                                          |  61%   10 MB
|===================================================================                                         |  61%   10 MB
|===================================================================                                         |  62%   11 MB
|====================================================================                                        |  62%   11 MB
|=====================================================================                                       |  63%   11 MB
|=====================================================================                                       |  63%   11 MB
|======================================================================                                      |  64%   11 MB
|======================================================================                                      |  64%   11 MB
|=======================================================================                                     |  65%   11 MB
|=======================================================================                                     |  65%   11 MB
|========================================================================                                    |  66%   11 MB
|========================================================================                                    |  66%   11 MB
|=========================================================================                                   |  67%   11 MB
|=========================================================================                                   |  67%   12 MB
|==========================================================================                                  |  68%   12 MB
|==========================================================================                                  |  68%   12 MB
|===========================================================================                                 |  69%   12 MB
|===========================================================================                                 |  69%   12 MB
|============================================================================                                |  70%   12 MB
|============================================================================                                |  70%   12 MB
|=============================================================================                               |  71%   12 MB
|=============================================================================                               |  71%   12 MB
|==============================================================================                              |  71%   12 MB
|==============================================================================                              |  72%   12 MB
|===============================================================================                             |  72%   12 MB
|================================================================================                            |  73%   13 MB
|================================================================================                            |  73%   13 MB
|=================================================================================                           |  74%   13 MB
|=================================================================================                           |  74%   13 MB
|==================================================================================                          |  75%   13 MB
|==================================================================================                          |  75%   13 MB
|===================================================================================                         |  76%   13 MB
|===================================================================================                         |  76%   13 MB
|====================================================================================                        |  77%   13 MB
|====================================================================================                        |  77%   13 MB
|=====================================================================================                       |  78%   13 MB
|=====================================================================================                       |  78%   13 MB
|======================================================================================                      |  79%   14 MB
|======================================================================================                      |  79%   14 MB
|=======================================================================================                     |  80%   14 MB
|=======================================================================================                     |  80%   14 MB
|========================================================================================                    |  81%   14 MB
|=========================================================================================                   |  81%   14 MB
|=========================================================================================                   |  82%   14 MB
|==========================================================================================                  |  82%   14 MB
|==========================================================================================                  |  83%   14 MB
|===========================================================================================                 |  83%   14 MB
|===========================================================================================                 |  84%   14 MB
|============================================================================================                |  84%   15 MB
|============================================================================================                |  85%   15 MB
|=============================================================================================               |  85%   15 MB
|=============================================================================================               |  85%   15 MB
|==============================================================================================              |  86%   15 MB
|==============================================================================================              |  86%   15 MB
|===============================================================================================             |  87%   15 MB
|===============================================================================================             |  87%   15 MB
|================================================================================================            |  88%   15 MB
|================================================================================================            |  88%   15 MB
|=================================================================================================           |  89%   15 MB
|=================================================================================================           |  89%   15 MB
|==================================================================================================          |  90%   16 MB
|===================================================================================================         |  90%   16 MB
|===================================================================================================         |  91%   16 MB
|====================================================================================================        |  91%   16 MB
|====================================================================================================        |  92%   16 MB
|=====================================================================================================       |  92%   16 MB
|=====================================================================================================       |  93%   16 MB
|======================================================================================================      |  93%   16 MB
|======================================================================================================      |  94%   16 MB
|=======================================================================================================     |  94%   16 MB
|=======================================================================================================     |  95%   16 MB
|========================================================================================================    |  95%   16 MB
|========================================================================================================    |  96%   17 MB
|=========================================================================================================   |  96%   17 MB
|=========================================================================================================   |  97%   17 MB
|==========================================================================================================  |  97%   17 MB
|==========================================================================================================  |  98%   17 MB
|=========================================================================================================== |  98%   17 MB
|============================================================================================================|  99%   17 MB
|============================================================================================================|  99%   17 MB
|=============================================================================================================| 100%   17 MB
PDB_pfam <- PDB_pfam %>% mutate(code_chain=paste0(PDB_ID,CHAIN_ID)) %>%  
            separate(PFAM_ACC, into=c('PFAMpref','PFAMsuff')) 
###Giardia PFAM domains
#GDB_IPS <- read_tsv("http://giardiadb.org/common/downloads/release-39/GintestinalisAssemblageAWB/txt/GiardiaDB-39_GintestinalisAssemblageAWB_InterproDomains.txt", col_names = FALSE) 
GDB_IPS <- read_tsv("../data/GiardiaDB-39_GintestinalisAssemblageAWB_InterproDomains.txt", 
                    col_types = cols(), col_names = FALSE)
names(GDB_IPS) <- c('GeneID','source','InterproID','Desc','GDBpfam_start','GDBpfam_end','eVal')
GDB_pfam <- GDB_IPS %>% filter(str_detect(InterproID,'^PF')) %>%
  dplyr::rename(PFAMpref=InterproID) %>% distinct()
PFAM_descriptionTable <- read_tsv("../data/PFAM_descriptionMapping.tsv",col_names = TRUE, col_types = cols())

Compute additional metrics

Metrics derived from I-TASSER output: sd of secondary structure predictions, and query:reference length ratio.

metrics_all <- metrics_df %>% 
  mutate(lenRatio=seq.ssLen/PDB_AA) %>% 
  mutate(Hprop=nHrc/seq.ssLen,
                      Eprop=nErc/seq.ssLen, 
                      Cprop=nCrc/seq.ssLen) %>%  
  rowwise() %>% mutate(SS_sd = sd(c(Hprop, Eprop, Cprop))) 

Check positive controls

SFigure 1

Investigate discordant reference structure matches for Giardia peptides encoding solved structures

mismatch_BLAST_status <- mismatch_BLAST %>% 
  mutate(matchStatus = factor(case_when(str_detect(status,'miss') ~ 'Matched_other',
                                   str_detect(status,'hit') ~ 'Matched_Gd'))) %>% 
  mutate(refSpecies = factor(case_when(str_detect(status,'hit') ~ 'Gd',
                                       str_detect(status,'non-Giardia') ~ 'other',
                                       TRUE ~ 'Gd'))) %>% 
  select(GeneID, matchStatus,refSpecies,Ref_Query_AAlenRatio,bit_score)
  
mismatch_BLAST_status %>% 
  rename(`Reference species` = refSpecies,
         `Match status` = matchStatus,
         `AA length ratio` = Ref_Query_AAlenRatio,
         'Bit score' = bit_score) %>% 
  gather(key,value,-c(GeneID,`Match status`,`Reference species`)) %>% 
  mutate(xSep=paste0(`Match status`,'_vs_',`Reference species`)) %>% 
  ggplot(aes(x=xSep, y=value)) + 
  geom_boxplot(aes(col=`Match status`), alpha=0) + 
  geom_jitter(aes(col=`Match status`,shape=`Reference species`), width=0.1, size=2) +
  facet_wrap(~ key, scales="free")   +
  theme(axis.text.x = element_text(angle=45,hjust=1)) +
  xlab("")
ggsave("../results/SF1.pdf",width=8,height=4)

Test differences in BLAST bit scores, and query:reference AA length ratios

mismatch_BLAST_forTest <- mismatch_BLAST_status %>% unite(match_species, c(matchStatus,refSpecies))
#Test differences in Ref_Query_AAlenRatio
aov_lenRat.res <- aov(Ref_Query_AAlenRatio ~ match_species, data = mismatch_BLAST_forTest )
summary(aov_lenRat.res)
              Df  Sum Sq  Mean Sq F value  Pr(>F)   
match_species  2 0.01126 0.005628    6.39 0.00649 **
Residuals     22 0.01938 0.000881                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#Multiple pair-wise comparisons
TukeyHSD(aov_lenRat.res)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = Ref_Query_AAlenRatio ~ match_species, data = mismatch_BLAST_forTest)

$match_species
                                           diff          lwr         upr     p adj
Matched_other_Gd-Matched_Gd_Gd       -0.0531666 -0.091663990 -0.01466921 0.0059271
Matched_other_other-Matched_Gd_Gd    -0.0004910 -0.038988390  0.03800639 0.9994342
Matched_other_other-Matched_other_Gd  0.0526756  0.005526119  0.09982508 0.0267095
#Test differences in bit_score
aov_bitScore.res <- aov(bit_score ~ match_species, data = mismatch_BLAST_forTest )
summary(aov_bitScore.res)
              Df  Sum Sq Mean Sq F value Pr(>F)  
match_species  2  708405  354202   5.403 0.0123 *
Residuals     22 1442156   65553                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#Multiple pair-wise comparisons
TukeyHSD(aov_bitScore.res)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = bit_score ~ match_species, data = mismatch_BLAST_forTest)

$match_species
                                       diff       lwr       upr     p adj
Matched_other_Gd-Matched_Gd_Gd       -179.2 -511.3312 152.93122 0.3808485
Matched_other_other-Matched_Gd_Gd    -428.2 -760.3312 -96.06878 0.0101240
Matched_other_other-Matched_other_Gd -249.0 -655.7760 157.77601 0.2933180

PFAM code matching

Join PFAM annotation databases and identify query:reference pairs with at least 1 matching PFAM code.
Annotation: PFAM codes assigned to Giardia query peptides: ‘GDB_pfam’
PFAM codes assigned to peptides encoding PDB reference structures: ‘PDB_pfam’.

metrics_long <- metrics_all %>% 
  mutate(code_chain=toupper(codechain)) %>% 
  left_join(GDB_pfam,by="GeneID") %>% rename(GDB_PFAMpref=PFAMpref) %>% 
  left_join(PDB_pfam,by="code_chain") %>% rename(PDB_PFAMpref=PFAMpref) %>% 
  distinct() %>% rename(GDB_PFAM_desc = Desc, PDB_PFAM_desc = PFAM_desc)

Plot number of PFAM domains per query:reference pair

nPFAM_Q_R <- metrics_long %>% 
  select(GeneID, GDB_PFAMpref, PDB_PFAMpref) %>% 
  distinct() %>% 
  group_by(GeneID) %>% 
  summarize_at(vars(GDB_PFAMpref, PDB_PFAMpref), funs( . %>% na.omit() %>% n_distinct )) %>% 
  rename(nPFAM_GDB = GDB_PFAMpref, nPFAM_PDB = PDB_PFAMpref )
nPFAM_Q_R %>% gather(key,value,-GeneID) %>% ggplot(aes(value)) +
  geom_bar(aes(fill=key), position="dodge", show.legend = TRUE) 

Calculate n. matching domains

#Because all pairwise combinations of PFAM domains are listed, need only filter for exact match:
nMatch_count <- metrics_long %>% 
  select(GeneID,code,chain,code_chain,GDB_PFAMpref,PDB_PFAMpref) %>%
  distinct() %>% 
  group_by(GeneID) %>% 
  filter(GDB_PFAMpref==PDB_PFAMpref) %>% 
  summarize(n_Match = n()) 
  
nMatch <- metrics_all[ , "GeneID"] %>% 
  left_join(nMatch_count, by="GeneID") %>% 
  mutate(n_Match = ifelse(is.na(n_Match), 0 ,n_Match)) 

Summarize PFAM matches across annotation groups

metrics_nMatch <- metrics_all %>% 
  left_join(nPFAM_Q_R, by="GeneID") %>% 
  left_join(nMatch,by="GeneID") %>% 
   mutate(n_Match=ifelse(is.na(n_Match), 0, n_Match)) %>% 
   mutate(matchStatus=ifelse(n_Match==0,'noMatch','exactMatch')) %>% 
   left_join(GeneDesc,by="GeneID") %>% select(GeneID,Description,everything()) %>% 
   mutate(descBin = ifelse(str_detect(Description,'hypothetical') | str_detect(Description,'Hypothetical'), 'Hyp','Annot')) 
metrics_nMatch %>% count(descBin,matchStatus) 

SFigure 2

Relative peptide length and number of matching PFAM domains.

lenRatio_X_nMatch <- metrics_nMatch %>% 
  select(GeneID, Cov, GDB_AA, lenRatio, contains('nPFAM'),n_Match, descBin) %>% 
  mutate(`n_Match:nPFAM_PDB` = n_Match/nPFAM_PDB) %>% 
  na.omit() %>% 
  group_by(n_Match, nPFAM_PDB) %>% summarize(median_lenRatio = median(lenRatio), 
                                                mean_lenRatio = mean(lenRatio), 
                                                mean_GDB_AAlen = mean(GDB_AA), 
                                                median_GDB_AAlen = median(GDB_AA), 
                                             group_size = n()) %>% 
  arrange(n_Match, nPFAM_PDB, desc(group_size))
metrics_nMatch %>% 
  filter(nPFAM_PDB<=4) %>% #filter(n_Match==0) %>% 
  filter(nPFAM_PDB>0) %>% 
  ggplot() + 
  geom_boxplot(aes(x=n_Match , y=lenRatio, group=factor(n_Match)), alpha=0, width=0.5)+  
  geom_jitter(aes(x=n_Match , y=lenRatio, col=factor(nPFAM_PDB), 
                  group=factor(nPFAM_PDB)), 
                  position=position_jitterdodge(dodge.width = 0.85), alpha=0.5, cex=0.25) +
  geom_text(data=lenRatio_X_nMatch %>% 
              filter(n_Match<=4, nPFAM_PDB<=4), 
            aes(x=n_Match, y=3, label=group_size, group=nPFAM_PDB), size=3) +
  facet_wrap( ~ nPFAM_PDB) +
  theme(legend.position = "none") +
  ggtitle("N. matching PFAM terms vs query:reference AA length ratio",
          subtitle="Facet by n. PFAM terms in PDB reference") +
  xlab("N. matching PFAM domains") + ylab("Query:reference AA length ratio")
ggsave("../results/SF2.pdf",width=6,height=6)

Figure 2a

Plot intersection of BLAST annotation status and PFAM code annotations.

source("upset.R")
upSets <- metrics_nMatch %>% select(GeneID, descBin, nPFAM_GDB, nPFAM_PDB, n_Match) %>% 
  mutate_at(vars(-GeneID, -descBin) , funs(binary = ifelse(. > 0, 1, 0))) %>% 
  mutate(descCategory = ifelse(descBin=="Hyp",1,2)) %>%  
  distinct() %>% select(GeneID, descCategory, contains('binary')) %>% 
  rename(Query = nPFAM_GDB_binary, Reference = nPFAM_PDB_binary, Match = n_Match_binary)
upSets %>% count(descCategory, Query, Reference, Match)        
annotStatus <- function(row, min, max){
  newData <- (row["descCategory"] <= max) & (row["descCategory"] > min)}
upset(data.frame(upSets), 
      sets=c('Query','Reference','Match'),
      main.bar.color = 'black',
      queries = list(list(query = annotStatus, params = list(1,2),
                          color="light blue",active=TRUE)), point.size=3)

pdf("../results/F2a.pdf", width = 4,height=3, onefile = FALSE) #works..ish
#pdf("../results/F2a.pdf", width = 4.5,height=3.5, onefile = FALSE)
upset(data.frame(upSets), 
      sets=c('Query','Reference','Match'),
      main.bar.color = 'black',
      queries = list(list(query = annotStatus, params = list(1,2),
                          color="light blue",active=TRUE)), point.size=3)
dev.off()
quartz_off_screen 
                2 

Figure 2b

PFAM term enrichment testing

source("rowwise_fisher.R")
matchStatus_PFAMcounts <- metrics_long %>% 
  left_join(metrics_nMatch %>% select(GeneID, matchStatus), by="GeneID") %>% 
  dplyr::select(1,lenRatio, matchStatus, GDB_PFAMpref,PDB_PFAMpref) %>% 
  gather(key=DB,value=PFAM,-c(GeneID,matchStatus,lenRatio)) %>% 
  na.omit() %>% 
  filter(lenRatio >0.9 & lenRatio <1.1) %>% ungroup() %>% 
  count(matchStatus,DB,PFAM) %>% 
  spread(key=DB, value=n, fill = 0) 
#set up parameters for Fisher tables  
myStatus <- "exactMatch"
minFreq <- 3
Foreground <- 'PDB_PFAMpref'
background <- 'GDB_PFAMpref'
termSums <- matchStatus_PFAMcounts %>% 
  filter(get(Foreground) >= minFreq) %>%
  filter(matchStatus == myStatus) %>% 
  summarize(allForeground = sum(get(Foreground)),
            allBackground = sum(get(background)),
            allTerms = sum(get(Foreground),get(background))) %>% unlist()
Fisher_df <- matchStatus_PFAMcounts %>% 
  filter(matchStatus==myStatus) %>% 
  dplyr::rename(Foreground = PDB_PFAMpref, 
                BACKGROUND = GDB_PFAMpref) %>% 
  rowwise() %>% 
  mutate(sumTerm=sum(Foreground,BACKGROUND),
         allForeground=termSums[[1]],
         allBackground=termSums[[2]],
         allTerms=termSums[[3]]) %>% 
  mutate('a' = Foreground,
         'b' = sumTerm - Foreground,
         'c' = allForeground - Foreground,
         'd' = allTerms - allForeground - b) %>% 
  dplyr::select(PFAM,Foreground,BACKGROUND,everything()) %>% 
  ungroup() 
mydata <- Fisher_df
p <- t(apply(mydata %>% 
               dplyr::select(a,b,c,d) %>% 
               filter(a >= minFreq), 1, row_fisher))
results <- cbind(mydata %>% filter(a >= minFreq) %>% 
                   dplyr::select(1:7), p) %>% 
#1:7 as no background of repressed, lowly transcribed (<0.85 percentile; i.e., the equivalent of the nonDTG set), is included.
  arrange(p_val) %>% 
  mutate(adjP=p.adjust(.$p_val, method="BH" ))  #correction for multiple comparisons
#No significant enrichment
results %>% filter(p_val < 0.05) %>% 
  arrange(p_val) %>% 
  filter(matchStatus=='exactMatch') %>% 
  mutate(`Reference_PFAM` = Foreground/allForeground,
         `Query_PFAM` = BACKGROUND/allBackground) %>% 
  left_join(PDB_pfam %>% select(PFAMpref,PFAM_Name,PFAM_desc), by=c("PFAM" = "PFAMpref")) %>% 
  distinct() %>% 
  dplyr::select(Foreground,BACKGROUND, PFAM,PFAM_desc,Query_PFAM,Reference_PFAM) %>% 
  filter(Foreground >= 7) %>% select(-c(Foreground,BACKGROUND)) %>% 
  gather(key,value,-c(PFAM,PFAM_desc)) %>% 
  ggplot(aes(x=reorder(PFAM_desc,value,FUN=max),y=value,fill=key)) + 
  geom_bar(stat="identity",position="dodge", show.legend = TRUE) +
  coord_flip() +
  xlab("") + ylab("Proportion of PFAM terms") +
  labs(fill="")
ggsave("../results/F2b.pdf",width=8,height=3.5)

Check putative additional domains in NEK kinases

EF hand domains in NEK kinases

metrics_nMatch %>% filter(n_Match > 0, str_detect(Description,"NEK")) %>% 
  filter(nPFAM_PDB > n_Match) %>% 
  filter(code=="3HX4") %>% 
  left_join(metrics_long,by="GeneID") %>% 
  select(GeneID, n_Match, contains("PFAMpref"), contains("PFAM_desc")) %>% 
  distinct() %>% 
  filter(PDB_PFAMpref=="PF13499") 

Kinase domains hypothetical proteins

metrics_nMatch %>% 
  filter(descBin=="Hyp") %>% 
  filter(nPFAM_PDB > n_Match) %>% 
  filter(code=="4O1O") %>% 
  left_join(metrics_long,by="GeneID") %>% 
  group_by(GeneID) %>% filter(!str_detect(GDB_PFAM_desc,'kinase')) %>% 
  select(GeneID, n_Match, contains("PFAMpref"), contains("PFAM_desc")) %>% 
  distinct() %>% count(GeneID)
NA

Figure 2c

Plot n. unique PFAM codes available via query and reference peptides.

metrics_nMatch %>% select(GeneID, contains('nPFAM'),  n_Match, matchStatus) %>% 
  filter(matchStatus=="exactMatch") %>% 
  select(contains('nPFAM')) %>% 
  gather(key=source,value=nPFAM) %>% 
  ggplot(aes(x=nPFAM)) + geom_bar(aes(fill=source), position="dodge") +
  xlab("N. unique PFAM codes") + ylab("N. proteins")
metrics_nMatch %>% select(GeneID, contains('nPFAM'),  n_Match, matchStatus) %>% 
  filter(matchStatus=="exactMatch") %>% 
  select(contains('nPFAM')) %>% 
  gather(key=source,value=nPFAM) %>% 
  group_by(source) %>% summarize(mean_nPFAM=mean(nPFAM)) 
ggsave("../results/F2c.pdf",width=5,height=4)

Random forest classifier

Train classifier

Create training and test data

Gd_forRF <- metrics_nMatch %>% select(1,TM:RMSD_model_sd,lenRatio,SS_sd,matchStatus) %>% na.omit()
#Gd_forRF %>% str()
  
geneOrder <- read_tsv("../data/Gd_forRF_geneIDorder.tsv")
Parsed with column specification:
cols(
  GeneID = col_character()
)
Gd_forRF <- geneOrder %>% left_join(Gd_forRF, by="GeneID")  #original geneOrder
set.seed(1234) ; forTRAIN_exact <- Gd_forRF %>% filter(matchStatus=="exactMatch") %>%  sample_n(750);
set.seed(1234) ; forTRAIN_noMatch <- Gd_forRF %>% filter(matchStatus!="exactMatch") %>%  sample_n(750);
forTRAIN <- rbind(forTRAIN_exact, forTRAIN_noMatch)
#set.seed(1234); TEST <- Gd_forRF %>% anti_join(forTRAIN, by="GeneID") %>% sample_n(1500) ; 
set.seed(4321); forTEST_exact <- Gd_forRF %>% anti_join(forTRAIN_exact, by="GeneID") %>% filter(matchStatus=="exactMatch") %>% sample_n(250)
      
set.seed(4321); forTEST_noMatch <- Gd_forRF %>% anti_join(forTRAIN_noMatch, by="GeneID") %>% filter(matchStatus!="exactMatch") %>% sample_n(250)
TEST <- rbind(forTEST_exact, forTEST_noMatch) 
TRAIN <- forTRAIN %>% dplyr::select(-c(GeneID)) 

Model training is only run once.

rf_model <- train(matchStatus ~. , data=TRAIN, method="rf",
                  trControl = trainControl(method="cv", number=5, verboseIter=TRUE),
                  prox=TRUE, verbose=TRUE)
saveRDS(rf_model,"../data/rf_model.Rds")

Print final model

rf_model <- readRDS("../data/rf_model.Rds")
print(rf_model$finalModel)

Call:
 randomForest(x = x, y = y, mtry = param$mtry, proximity = TRUE,      verbose = TRUE) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 2

        OOB estimate of  error rate: 9.93%
Confusion matrix:
           exactMatch noMatch class.error
exactMatch        694      56  0.07466667
noMatch            93     657  0.12400000

Classifier performance

predTEST <- predict(rf_model, newdata=TEST, type="prob")
predALL <- predict(rf_model, newdata=Gd_forRF, type="prob")
#summary(predTEST)
#summary(predALL)
#accuracy on hold-out TEST set:
TEST %>%  mutate(RFexact_pred = predTEST$exactMatch) %>% 
  mutate(predStatus=ifelse(RFexact_pred >= 0.5,"exactMatch","noMatch")) %>% 
  count(matchStatus, predStatus)
#entire proteome
Gd_forRF %>% mutate(RFexact_pred = predALL$exactMatch) %>% 
  mutate(predStatus=ifelse(RFexact_pred >= 0.5,"exactMatch","noMatch")) %>% 
  count(matchStatus, predStatus)
Gd_matchPredict <- Gd_forRF %>% mutate(exactMatchPred = predALL$exactMatch) %>% ungroup()

Fig 3a

Compute feature importance

Gd_imp <- data.frame(varImp(rf_model, scale=FALSE)$importance)  
Gd_imp$noi  <- row.names(Gd_imp); row.names(Gd_imp) <- NULL
names(Gd_imp) <- c('Contribn', 'impFactor') ; #head(Gd_imp)
Gd_imp <- Gd_imp %>%dplyr::select(2,1) %>% arrange(desc(Contribn)) %>%  mutate(propCont = Contribn/sum(Contribn))
imp_plot <- Gd_imp %>% 
  mutate(impFactor_recode = case_when(impFactor=="AApc" ~ 'AA_%ID',
                               impFactor=="Cscore" ~ 'C_score',
                               impFactor=="AApc" ~ "AA_%ID",
                               impFactor=="Cov" ~ 'Coverage',
                               impFactor=="exactMatchPred" ~ 'Exact_match_prediction',
                               impFactor=="lenRatio" ~ 'Length_ratio',
                               TRUE ~ impFactor)) %>% 
  ggplot(aes(x=reorder(impFactor_recode, propCont), y=propCont)) +
  geom_bar(stat="identity", aes(fill=impFactor_recode), show.legend = FALSE) +
  ylab("Importance") + xlab("") + ylim(0,0.3) +
  coord_flip()  
imp_plot
ggsave("../results/SF3a.pdf",imp_plot, width=4,height=3)

Fig 3b

Sensitivity and specificity

##AUROC
#https://gist.github.com/jwaage/6d8f4eb096e4f18a0894ca1ce27af834
forROC <- Gd_matchPredict %>% 
  dplyr::select(TM:exactMatchPred) %>% 
  mutate(matchStatus = abs(as.numeric(factor(matchStatus))-2)) 
aucOut <- data_frame('sensPlt' = NA, 'specPlt' = NA, 'Metric'=NA,'AUC' = NA)
for (i in names(forROC)){#print(i)
  r <- roc(forROC$matchStatus, forROC[ , i] %>% pull())
  sens <- r$sensitivities
  spec <- r$specificities
  a <- auc(r)[1]
  rnd <- round(a,3)
  result <- data_frame('sensPlt' = rev(sens), 'specPlt' = rev(spec)) %>% mutate(Metric = i, AUC = rnd)
  aucOut <- rbind(aucOut,result) %>% na.omit() }
auc_plot <- aucOut %>%  mutate(Metric = case_when(Metric=="AApc" ~ 'AA_%ID',
                               Metric=="Cscore" ~ 'C_score',
                               Metric=="AApc" ~ "AA_%ID",
                               Metric=="Cov" ~ 'Coverage',
                               Metric=="exactMatchPred" ~ 'Exact_match_prediction',
                               Metric=="lenRatio" ~ 'AA_length_ratio',
                               TRUE ~ Metric)) %>% 
  filter(Metric !="matchStatus") %>% 
  distinct() %>% na.omit() %>% filter(AUC >= 0.7) %>% 
  ggplot(aes(x=specPlt,y=sensPlt)) + 
  geom_segment(aes(x = 0, y = 1, xend = 1, yend = 0), alpha = 0.5) + 
  geom_step(aes(col=Metric), lty = 2,lwd=1) +
  scale_x_reverse(name = "False positive rate (Specificity)",limits = c(1,0)) + 
  ylab("True positive rate (Sensitivity)") + 
  coord_equal() +
  scale_color_manual(values= c("AA_%ID" = "#F8766D","C_score" = "#DE8C00",
                               "Exact_match_prediction" = 'black','AA_length_ratio' = "#00BA38",
                               "RMSD" = "#00BFC4","TM_model" = "#F564E3")) 
aucOut %>% select(-contains('Plt')) %>% distinct() %>% arrange(desc(AUC))
auc_plot
ggsave("../results/F3b.pdf",auc_plot, width=5,height=5)

Test classifier on models from Human

Metric distribution by RF confidence

Gd_all <- metrics_nMatch %>% left_join(Gd_matchPredict %>% dplyr::select(1,exactMatchPred),by="GeneID")  
Gd_all_RFconf <- Gd_all %>% 
  mutate(RF_confidence = case_when(matchStatus=="exactMatch" & exactMatchPred >= 0.5 ~ 'HiConf',
                                matchStatus=="noMatch" & exactMatchPred < 0.5        ~ 'LowerConf',
                                matchStatus=="exactMatch" & exactMatchPred < 0.5     ~ "LowerConf-like",
                                matchStatus=="noMatch" & exactMatchPred >= 0.5       ~ "HiConf-like",
                                TRUE ~ "")) 
Gd_all_RFconf %>% select(TM:RMSD_model_sd,lenRatio,SS_sd,matchStatus,exactMatchPred,RF_confidence) %>% 
  rename(Exact_match_prediction = exactMatchPred, AA_length_ratio = lenRatio,
         `AA_%ID` = AApc, Coverage = Cov, C_score = Cscore) %>% 
  filter(C_score > -8 & RMSD_model < 25) %>% 
  gather(key,value,-c(RF_confidence,matchStatus)) %>% 
  filter(str_detect(RF_confidence,"Conf")) %>% 
  na.omit() %>% 
  mutate(key = fct_relevel(factor(key), c('SS_sd', 'C_score','C_sd', 'AA_length_ratio',
                                          'TM','RMSD','AA_%ID','Coverage',
                                          'TM_model','TM_model_sd','RMSD_model','RMSD_model_sd',
                                          'Exact_match_prediction'))) %>% 
  ggplot(aes(x=key, y=value, col=RF_confidence)) + 
  geom_point(position=position_jitterdodge(jitter.width = 0.1, dodge.width=1), 
             size=0.02, alpha=0.2, show.legend = TRUE) +
  geom_boxplot( position=position_dodge(1), alpha=0) +
  xlab("") + ylab("") +
  theme(legend.title=element_blank(), 
        strip.background = element_blank(), 
        strip.text.x = element_text(size=0)) +
  facet_wrap( ~ key, scales="free")
ggsave("../results/F4.pdf",width=9.5,height=9)

SFigure 4a

Technical variation: Train 500 models on the same data.

RF_train_iter500 <- data_frame('dummy'=rep(NA, nrow(Gd_forRF)))
for(i in 1:500){
  
  a <- train(matchStatus ~. , data=TRAIN, method="rf",
             trControl = trainControl(method="cv", number=5, verboseIter=TRUE),
             prox=TRUE, verbose=TRUE)
  
  fm <- as_data_frame(predict(a, newdata = Gd_forRF, type="prob"))
  fm <- fm[ , 1]
  names(fm) <- paste0('rf_',i)
  RF_train_iter500 <- cbind(RF_train_iter500, fm)
  
}

RF_train_iter500 <- RF_train_iter500[ , -1]

saveRDS(RF_train_iter500, "../data/RF_train_iter500.Rds")

Plot technical variation

RF_train_iter500 <- readRDS("../data/RF_train_iter500.Rds")
RF_train_iter500_summary <- data_frame('mean' = rowMeans(RF_train_iter500), 
                      'sd' = apply(RF_train_iter500 ,1, sd, na.rm = TRUE),
                      'sem' = apply(RF_train_iter500 , 1, function(x) sd(x)/sqrt(length(x))),
                      'len' = apply(RF_train_iter500 , 1, length ))
RF_train_iter500_summary %>% cbind(Gd_forRF) %>% dplyr::select(mean,sd,sem,matchStatus) %>% 
  ggplot(aes(mean, log10(1/sd))) + geom_point(aes(col=matchStatus), cex=0.5) +
  ylim(1,3.5)
ggsave("../results/SF6a.pdf",width=5,height=4)

SFigure 4b

Robustness: Train 50 models on different training data and set sizes

RF_sample_iter500 <- data_frame("GeneID" = Gd_forRF %>% select(GeneID) %>% pull())

for(i in c(50,100,200,300,400,500)){ 
  for(j in 1:50){
    sample_iterTrain <- rbind(Gd_forRF %>% filter(matchStatus=='noMatch') %>% sample_n(i),
                       Gd_forRF %>% filter(matchStatus=='exactMatch') %>% sample_n(i))
    
    rfMod_iter <- train(matchStatus ~ . , data = sample_iterTrain %>% select(-GeneID), method="rf",
                        trControl = trainControl(method="cv", number=5, verboseIter=TRUE),
                        prox=TRUE, verbose=TRUE)
    fm_t <- as_data_frame(predict(rfMod_iter, newdata=Gd_forRF, type="prob"))
    fm_t <- fm_t[ , 1]
    names(fm_t) <- paste('rf_train', 2*i, 'iter', j, sep="_")
    RF_sample_iter500 <- cbind(RF_sample_iter500, fm_t)
  }
}

saveRDS(RF_sample_iter500, "../data/RF_sample_iter500.Rds")

Plot reproducibility

RF_sample_iter500 <- readRDS("../data/RF_sample_iter500.Rds")
RF_sample_iter500 %>% 
  gather(key,value,-GeneID) %>% 
  separate(key,into=c("v1","v2","v3","v4","v5"),sep="_",convert = TRUE) %>% 
  select(GeneID,v3,v5,value) %>% dplyr::rename(trainingSetSize=v3,iteration=v5) %>%
  group_by(GeneID,trainingSetSize) %>% summarize(mean=mean(value),sd=sd(value)) %>% 
  left_join(Gd_forRF %>% select(GeneID,matchStatus),by="GeneID") %>% 
  ggplot(aes(x=factor(trainingSetSize),y=sd)) +
  geom_boxplot(alpha=0.2, aes(col=matchStatus )) +
  xlab('Training set size') + ylab("sd(Probability of high-confidence category)")
ggsave("../results/SF6b.pdf",width=7,height=4)

SFigure 4c

RF_sample_iter500 %>% 
  gather(key,value,-GeneID) %>% 
  separate(key,into=c("v1","v2","v3","v4","v5"),sep="_",convert = TRUE) %>% 
  select(GeneID,v3,v5,value) %>% 
  dplyr::rename(trainingSetSize=v3,iteration=v5) %>%
  group_by(GeneID,trainingSetSize) %>% 
  mutate(call=ifelse(value>0.5,1,0)) %>% 
  group_by(GeneID,trainingSetSize) %>% 
  mutate(meanCall=mean(call), meanVal=mean(value),
         sdCall=sd(call), sdVal=sd(value)) %>% 
  ungroup() %>% 
  select(-c(value,iteration,call)) %>% distinct() %>% 
  left_join(Gd_forRF %>% select(GeneID, matchStatus),by="GeneID") %>% 
  left_join(Gd_all_RFconf %>% select(GeneID,exactMatchPred,RF_confidence),
            by="GeneID") %>% filter(RF_confidence!="") %>% 
  ggplot(aes(x=meanCall,y=meanVal)) +         
  geom_point(aes(col=RF_confidence),cex=0.2) + 
  facet_wrap(~ trainingSetSize) 
ggsave("../results/SF6c.pdf",width=8,height=4)

Features of lower conf-like models?

Gd_all_RFconf %>% filter(RF_confidence=="LowerConf-like") %>% 
  left_join(metrics_long,by="GeneID") %>% 
  filter(PDB_PFAMpref== GDB_PFAMpref) %>% 
  select(GeneID,GDB_PFAMpref) %>% 
  distinct() %>% 
  left_join(PFAM_descriptionTable,by=c('GDB_PFAMpref' = 'PFAMcode')) %>% 
  count(desc) %>% arrange(desc(n)) %>% filter(n>1)
Gd_all_RFconf %>% filter(RF_confidence=="LowerConf") %>% 
  left_join(metrics_long,by="GeneID") %>% 
  select(GeneID,GDB_PFAMpref) %>% 
  na.omit() %>% 
  distinct() %>% 
  left_join(PFAM_descriptionTable,by=c('GDB_PFAMpref' = 'PFAMcode')) %>% 
  count(desc) %>% arrange(desc(n)) %>% filter(n>5)

Compute relative abundance of domains across confidence groups

Gd_all_RFconf %>% 
  left_join(metrics_long,by="GeneID") %>% 
  select(GeneID,GDB_PFAMpref,PDB_PFAMpref, RF_confidence) %>%distinct() %>%  
  gather(key,value,-c(GeneID,RF_confidence)) %>% 
  distinct() %>% ungroup() %>% 
  filter(RF_confidence!="") %>% na.omit() %>% 
  group_by(RF_confidence,key) %>% count(value) %>% 
  spread(RF_confidence,n, fill = 0) %>% 
  filter(key=="GDB_PFAMpref") %>% 
  rowwise() %>% 
  mutate(ratio = (LowerConf /1389) / (sum(`HiConf`,`HiConf-like`,`LowerConf-like`) / 1389)) %>% 
  filter(LowerConf>0, ratio!="Inf") %>% 
  arrange(desc(ratio)) %>% 
  left_join(PFAM_descriptionTable,by=c('value'='PFAMcode')) %>% 
  select(desc,ratio, everything())
NA
NA
NA

Clustering analysis

SFigure 5

Compare sequence- and structure-based clusters

blst_Nek <- read_tsv("../data/Nek_kinase_BLASTp.tsv", col_names = TRUE)
Parsed with column specification:
cols(
  query_id = col_character(),
  subject_id = col_character(),
  pct_identity = col_double(),
  aln_length = col_integer(),
  n_of_mismatches = col_integer(),
  gap_openings = col_integer(),
  q_start = col_integer(),
  q_end = col_integer(),
  s_start = col_integer(),
  s_end = col_integer(),
  e_value = col_double(),
  bit_score = col_double()
)
TM_Nek <- read_tsv("../data/Nek_kinase_TM.tsv", col_names = TRUE)
Parsed with column specification:
cols(
  struc1 = col_character(),
  struc2 = col_character(),
  TM = col_double()
)
blst_matFull <- blst_Nek %>% mutate(value=percent_rank(bit_score)) %>% 
  select(query_id,subject_id,value) %>% 
  spread(subject_id,value, fill = 0) %>% select(-query_id) %>% as.matrix() 
rownames(blst_matFull) <- colnames(blst_matFull)
TM_matFull <- TM_Nek %>% spread(struc2,TM, fill=0) %>% select(-struc1) %>% as.matrix()
rownames(TM_matFull) <- colnames(TM_matFull)
blst_TM_mds <- rbind((1-cor(blst_matFull)) %>% 
                       cmdscale() %>%
                       as_tibble() %>% 
                       mutate(dtype="blst"), 
                     (1-cor(TM_matFull)) %>% 
                       cmdscale() %>%
                       as_tibble() %>% 
                       mutate(dtype="TM")) %>% 
  dplyr::rename(Dim.1 = V1, Dim.2 = V2) %>% 
  mutate(GeneID=str_replace(rep(rownames(blst_matFull),2),"GL_","GL50803_"))
blst_TM_mds %>% 
  left_join(Gd_all_RFconf, by="GeneID") %>% 
  mutate(dtype=recode(dtype,blst="BLAST",TM="TM-align")) %>% 
  filter(!is.na(RF_confidence)) %>%
  dplyr::rename("RF confidence" = RF_confidence) %>% 
  ggplot(aes(x=Dim.1,y=Dim.2 )) + 
  geom_point(aes(col=`RF confidence`, shape=`RF confidence`), size=2) +
  scale_shape_manual(values=c('HiConf'=1,'HiConf-like' = 1, 'LowerConf' =2, "LowerConf-like" = 2)) +
  facet_wrap(~ dtype , scales="free")
ggsave("../results/SF7.pdf",width=9,height=4)

Transcriptional abundance

SFigure 6

Transcriptional abundance by RF confidence

transcription_cpm <- read_tsv("../data/Ansell_2017_GiardiaCPM.tsv", col_types = cols())
transc_by_category <- Gd_all_RFconf %>% 
   mutate(transcriptLen=(GDB_AA * 3) - 3) %>% 
   left_join(transcription_cpm,by="GeneID") %>% 
   select(GeneID,RF_confidence,transcriptLen,contains('-s')) %>% 
   gather(key,value,-c(GeneID,transcriptLen,RF_confidence)) %>% 
   mutate(value=ifelse(is.na(value),0.1,value)) %>% 
   mutate(value=value/transcriptLen) %>% na.omit() %>% 
   group_by(GeneID,RF_confidence) %>% summarize(meanVal=mean(value)) %>% 
  filter(!RF_confidence=="") 
 
transc_by_category %>% 
   filter(meanVal > 0.001) %>% 
   ggplot(aes(x=RF_confidence,y=log10(meanVal))) + 
   geom_boxplot(aes(fill=RF_confidence), width=0.5, col="black", alpha=0.5) +
   geom_violin(aes(col=RF_confidence), alpha=0) +
   theme(legend.position="none") +
   theme(axis.text.x=element_text(angle=45, hjust=1)) + 
   xlab("") + ylab("log10(length-normalized CPM)")
ggsave("../results/SF8.pdf",width=4,height=4)

#Test differences 
aov_transc.res <- aov(meanVal ~ RF_confidence, 
                      data=transc_by_category %>% filter(meanVal> 0.001)) 
summary(aov_transc.res)  
                Df Sum Sq Mean Sq F value Pr(>F)    
RF_confidence    3   50.3  16.754   42.42 <2e-16 ***
Residuals     4343 1715.3   0.395                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
TukeyHSD(aov_transc.res)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = meanVal ~ RF_confidence, data = transc_by_category %>% filter(meanVal > 0.001))

$RF_confidence
                                  diff        lwr         upr     p adj
HiConf-like-HiConf          0.20759312  0.1019366  0.31324968 0.0000028
LowerConf-HiConf           -0.16190156 -0.2199994 -0.10380374 0.0000000
LowerConf-like-HiConf      -0.10677903 -0.3923471  0.17878900 0.7716333
LowerConf-HiConf-like      -0.36949468 -0.4671976 -0.27179175 0.0000000
LowerConf-like-HiConf-like -0.31437215 -0.6105471 -0.01819719 0.0324399
LowerConf-like-LowerConf    0.05512253 -0.2275993  0.33784440 0.9588284
 

Supplementary Tables

Write supplementary Tables

write_tsv(Gd_all_RFconf %>% 
            select(-c(seq.ssLen,
                      nHrc,nErc,nCrc,
                      strucSum,strpPDB_AA, codechain)) %>% 
                     dplyr::rename(Exact_match_prediction =exactMatchPred,
                Length_ratio=lenRatio,Match_status=matchStatus,`AA_%ID`=AApc,
                C_score=Cscore,
                Annot_status=descBin,Confidence_category =RF_confidence) %>% 
            arrange(desc(C_score,Confidence_category)),
            path="../results/STable_2.tsv")
write_tsv(Gd_all_RFconf %>% 
            select(-c(seq.ssLen,
                      nHrc,nErc,nCrc,
                      strucSum,strpPDB_AA, codechain)) %>% 
            filter(RF_confidence=="HiConf-like" & descBin=="Hyp") %>%
            dplyr::rename(Exact_match_prediction =exactMatchPred,
                Length_ratio=lenRatio,Match_status=matchStatus,`AA_%ID`=AApc,
                C_score=Cscore,
                Annot_status=descBin,Confidence_category =RF_confidence) %>% 
              arrange(desc(C_score,Confidence_category)), 
          path="../results/STable_3.tsv")

RF clasifier sans %AA ID

Figure 3b

RF classifier without AA_%ID

TRAIN_nopcAA <- forTRAIN %>% dplyr::select(-c(GeneID,AApc)) 

rf_model_nopcAA <- train(matchStatus ~. , data=TRAIN_nopcAA, method="rf",
                  trControl = trainControl(method="cv", number=5, verboseIter=FALSE),
                  prox=TRUE, verbose=FALSE)
saveRDS(rf_model_nopcAA, "../data/rf_model_nopcAA.Rds")
rf_model_nopcAA <- readRDS("../data/rf_model_nopcAA.Rds")
print(rf_model_nopcAA$finalModel)

Call:
 randomForest(x = x, y = y, mtry = param$mtry, proximity = TRUE,      verbose = FALSE) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 2

        OOB estimate of  error rate: 11%
Confusion matrix:
           exactMatch noMatch class.error
exactMatch        683      67  0.08933333
noMatch            98     652  0.13066667

Classifier performance without % AA ID.

predTEST_nopcAA <- predict(rf_model_nopcAA, newdata=TEST, type="prob")
predALL_nopcAA <- predict(rf_model_nopcAA, newdata=Gd_forRF, type="prob")
# summary(predTEST_nopcAA)
# summary(predALL_nopcAA)
#accuracy on hold-out TEST set:
TEST %>%  mutate(RFexact_pred_nopcAA = predTEST_nopcAA$exactMatch) %>% 
  mutate(predStatus=ifelse(RFexact_pred_nopcAA > 0.5,"exactMatch","noMatch")) %>% 
  count(matchStatus, predStatus) %>% 
  group_by(matchStatus) %>% mutate(gpErr=n/sum(n))
#entire proteome
Gd_forRF %>% mutate(RFexact_pred_nopcAA = predALL_nopcAA$exactMatch) %>% 
  mutate(predStatus=ifelse(RFexact_pred_nopcAA > 0.5,"exactMatch","noMatch")) %>% 
  count(matchStatus, predStatus) %>% 
  group_by(matchStatus) %>% mutate(gpErr=n/sum(n))

Compute feature importance and predictive power

Gd_imp_nopcAA <- data.frame(varImp(rf_model_nopcAA, scale=FALSE)$importance) 
Gd_imp_nopcAA$noi  <- row.names(Gd_imp_nopcAA); row.names(Gd_imp_nopcAA) <- NULL
names(Gd_imp_nopcAA) <- c('Contribn', 'impFactor') 
Gd_imp_nopcAA <- Gd_imp_nopcAA %>%dplyr::select(2,1) %>% 
  arrange(desc(Contribn)) %>%  mutate(propCont = Contribn/sum(Contribn))
imp_plot_nopcAA <- Gd_imp_nopcAA %>% 
  mutate(impFactor_recode = case_when(impFactor=="Cscore" ~ 'C_score',
                               impFactor=="Cov" ~ 'Coverage',
                               impFactor=="exactMatchPred" ~ 'Exact_match_prediction',
                               impFactor=="lenRatio" ~ 'Length_ratio',
                               TRUE ~ impFactor)) %>% 
  ggplot(aes(x=reorder(impFactor_recode, propCont), y=propCont)) +
  geom_bar(stat="identity", aes(fill=impFactor_recode), show.legend = FALSE) +
  ylab("Importance") + xlab("") +
  coord_flip()  
imp_plot_nopcAA
ggsave("../results/SF5.pdf", imp_plot_nopcAA, width=4,height=3)

LS0tCnRpdGxlOiAiUHJvdGVpbiBzdHJ1Y3R1cmUtYmFzZWQgaG9tb2xvZ3kgYW5kIG1hY2hpbmUgbGVhcm5pbmciCnN1YnRpdGxlOiAiU2NyaXB0cyB0byByZXByb2R1Y2UgZmlndXJlcyBhbmQgdGFibGVzIGluIG1hbnVzY3JpcHQgR0lHQS1ELTE4LTAwMjg4IgphdXRob3I6ICJCcmVuZGFuIFIuRS4gQW5zZWxsIgpkYXRlOiAiMTAvMTYvMjAxOCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgI3RoZW1lOiB1bml0ZWQKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgI2dpdGh1Yl9kb2N1bWVudDogZGVmYXVsdAplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgdGlkeSA9IFRSVUUpCgoKbGlicmFyeSh0aWR5dmVyc2UpOyBsaWJyYXJ5KGdncGxvdDIpOyAKbGlicmFyeShzdHJpbmdyKTsgbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KGNhcmV0KTsgbGlicmFyeShVcFNldFIpCmxpYnJhcnkocnBhcnQpOyBsaWJyYXJ5KHBST0MpCgoKc2VsZWN0IDwtIGRwbHlyOjpzZWxlY3QKCmBgYAoKI0RhdGEgaW1wb3J0IAoKUmVhZCBpbiBkYXRhIHNldHMgZm9yIEJMQVNUIGFubm90YXRpb24sIFBGQU0gYW5ub3RhdGlvbiBhbmQgSS1UQVNTRVIgb3V0cHV0IG1ldHJpY3MKYGBge3IsIGV2YWw9VFJVRX0KR2VuZURlc2MgPC0gcmVhZF90c3YoIi4uL2RhdGEvR2lhcmRpYURCLTM5X0dpbnRlc3RpbmFsaXNBc3NlbWJsYWdlQV9Bbm5vdGF0ZWRQcm90ZWlucy5kZXNjcmlwdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IEZBTFNFLCBjb2xfdHlwZXMgPSBjb2xzKCkpCgpuYW1lcyhHZW5lRGVzYykgPC0gYygnR2VuZUlEJywnRGVzY3JpcHRpb24nKQoKbWV0cmljc19kZiA8LSByZWFkLmRlbGltKCIuLi9kYXRhL21ldHJpY3NfY2xlYW4udHh0IixzZXA9Ilx0Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBxdW90ZT0iIiwgaGVhZGVyPVRSVUUpCgptaXNtYXRjaF9CTEFTVCA8LSByZWFkX3RzdigiLi4vZGF0YS9taXNtYXRjaGVzX0JMQVNULnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKClBEQl9wZmFtIDwtIHJlYWRfdHN2KCIuLi9kYXRhL2htbWVyX3BkYl9hbGwudHh0IiwgY29sX3R5cGVzID0gY29scygpKSAgI2FjY2Vzc2VkIGluIE9jdCAyMDE3CgpQREJfcGZhbSA8LSBQREJfcGZhbSAlPiUgbXV0YXRlKGNvZGVfY2hhaW49cGFzdGUwKFBEQl9JRCxDSEFJTl9JRCkpICU+JSAgCiAgICAgICAgICAgIHNlcGFyYXRlKFBGQU1fQUNDLCBpbnRvPWMoJ1BGQU1wcmVmJywnUEZBTXN1ZmYnKSkgCgojIyNHaWFyZGlhIFBGQU0gZG9tYWlucwoKI0dEQl9JUFMgPC0gcmVhZF90c3YoImh0dHA6Ly9naWFyZGlhZGIub3JnL2NvbW1vbi9kb3dubG9hZHMvcmVsZWFzZS0zOS9HaW50ZXN0aW5hbGlzQXNzZW1ibGFnZUFXQi90eHQvR2lhcmRpYURCLTM5X0dpbnRlc3RpbmFsaXNBc3NlbWJsYWdlQVdCX0ludGVycHJvRG9tYWlucy50eHQiLCBjb2xfbmFtZXMgPSBGQUxTRSkgCgpHREJfSVBTIDwtIHJlYWRfdHN2KCIuLi9kYXRhL0dpYXJkaWFEQi0zOV9HaW50ZXN0aW5hbGlzQXNzZW1ibGFnZUFXQl9JbnRlcnByb0RvbWFpbnMudHh0IiwgCiAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scygpLCBjb2xfbmFtZXMgPSBGQUxTRSkKbmFtZXMoR0RCX0lQUykgPC0gYygnR2VuZUlEJywnc291cmNlJywnSW50ZXJwcm9JRCcsJ0Rlc2MnLCdHREJwZmFtX3N0YXJ0JywnR0RCcGZhbV9lbmQnLCdlVmFsJykKCkdEQl9wZmFtIDwtIEdEQl9JUFMgJT4lIGZpbHRlcihzdHJfZGV0ZWN0KEludGVycHJvSUQsJ15QRicpKSAlPiUKICBkcGx5cjo6cmVuYW1lKFBGQU1wcmVmPUludGVycHJvSUQpICU+JSBkaXN0aW5jdCgpCgpQRkFNX2Rlc2NyaXB0aW9uVGFibGUgPC0gcmVhZF90c3YoIi4uL2RhdGEvUEZBTV9kZXNjcmlwdGlvbk1hcHBpbmcudHN2Iixjb2xfbmFtZXMgPSBUUlVFLCBjb2xfdHlwZXMgPSBjb2xzKCkpCgpgYGAKCiMjQ29tcHV0ZSBhZGRpdGlvbmFsIG1ldHJpY3MKCk1ldHJpY3MgZGVyaXZlZCBmcm9tIEktVEFTU0VSIG91dHB1dDogc2Qgb2Ygc2Vjb25kYXJ5IHN0cnVjdHVyZSBwcmVkaWN0aW9ucywgYW5kIHF1ZXJ5OnJlZmVyZW5jZSBsZW5ndGggcmF0aW8uCmBgYHtyLCBldmFsPVRSVUV9CgptZXRyaWNzX2FsbCA8LSBtZXRyaWNzX2RmICU+JSAKICBtdXRhdGUobGVuUmF0aW89c2VxLnNzTGVuL1BEQl9BQSkgJT4lIAogIG11dGF0ZShIcHJvcD1uSHJjL3NlcS5zc0xlbiwKICAgICAgICAgICAgICAgICAgICAgIEVwcm9wPW5FcmMvc2VxLnNzTGVuLCAKICAgICAgICAgICAgICAgICAgICAgIENwcm9wPW5DcmMvc2VxLnNzTGVuKSAlPiUgIAogIHJvd3dpc2UoKSAlPiUgbXV0YXRlKFNTX3NkID0gc2QoYyhIcHJvcCwgRXByb3AsIENwcm9wKSkpIAoKYGBgCgoKCiNDaGVjayBwb3NpdGl2ZSBjb250cm9scwojI1NGaWd1cmUgMQoKSW52ZXN0aWdhdGUgZGlzY29yZGFudCByZWZlcmVuY2Ugc3RydWN0dXJlIG1hdGNoZXMgZm9yICpHaWFyZGlhKiBwZXB0aWRlcyBlbmNvZGluZyBzb2x2ZWQgc3RydWN0dXJlcwoKYGBge3J9CgoKbWlzbWF0Y2hfQkxBU1Rfc3RhdHVzIDwtIG1pc21hdGNoX0JMQVNUICU+JSAKICBtdXRhdGUobWF0Y2hTdGF0dXMgPSBmYWN0b3IoY2FzZV93aGVuKHN0cl9kZXRlY3Qoc3RhdHVzLCdtaXNzJykgfiAnTWF0Y2hlZF9vdGhlcicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChzdGF0dXMsJ2hpdCcpIH4gJ01hdGNoZWRfR2QnKSkpICU+JSAKICBtdXRhdGUocmVmU3BlY2llcyA9IGZhY3RvcihjYXNlX3doZW4oc3RyX2RldGVjdChzdGF0dXMsJ2hpdCcpIH4gJ0dkJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChzdGF0dXMsJ25vbi1HaWFyZGlhJykgfiAnb3RoZXInLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gJ0dkJykpKSAlPiUgCiAgc2VsZWN0KEdlbmVJRCwgbWF0Y2hTdGF0dXMscmVmU3BlY2llcyxSZWZfUXVlcnlfQUFsZW5SYXRpbyxiaXRfc2NvcmUpCiAgCm1pc21hdGNoX0JMQVNUX3N0YXR1cyAlPiUgCiAgcmVuYW1lKGBSZWZlcmVuY2Ugc3BlY2llc2AgPSByZWZTcGVjaWVzLAogICAgICAgICBgTWF0Y2ggc3RhdHVzYCA9IG1hdGNoU3RhdHVzLAogICAgICAgICBgQUEgbGVuZ3RoIHJhdGlvYCA9IFJlZl9RdWVyeV9BQWxlblJhdGlvLAogICAgICAgICAnQml0IHNjb3JlJyA9IGJpdF9zY29yZSkgJT4lIAogIGdhdGhlcihrZXksdmFsdWUsLWMoR2VuZUlELGBNYXRjaCBzdGF0dXNgLGBSZWZlcmVuY2Ugc3BlY2llc2ApKSAlPiUgCiAgbXV0YXRlKHhTZXA9cGFzdGUwKGBNYXRjaCBzdGF0dXNgLCdfdnNfJyxgUmVmZXJlbmNlIHNwZWNpZXNgKSkgJT4lIAogIGdncGxvdChhZXMoeD14U2VwLCB5PXZhbHVlKSkgKyAKICBnZW9tX2JveHBsb3QoYWVzKGNvbD1gTWF0Y2ggc3RhdHVzYCksIGFscGhhPTApICsgCiAgZ2VvbV9qaXR0ZXIoYWVzKGNvbD1gTWF0Y2ggc3RhdHVzYCxzaGFwZT1gUmVmZXJlbmNlIHNwZWNpZXNgKSwgd2lkdGg9MC4xLCBzaXplPTIpICsKICBmYWNldF93cmFwKH4ga2V5LCBzY2FsZXM9ImZyZWUiKSAgICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSxoanVzdD0xKSkgKwogIHhsYWIoIiIpCgpnZ3NhdmUoIi4uL3Jlc3VsdHMvU0YxLnBkZiIsd2lkdGg9OCxoZWlnaHQ9NCkKCmBgYAoKClRlc3QgZGlmZmVyZW5jZXMgaW4gQkxBU1QgYml0IHNjb3JlcywgYW5kIHF1ZXJ5OnJlZmVyZW5jZSBBQSBsZW5ndGggcmF0aW9zCmBgYHtyfQoKbWlzbWF0Y2hfQkxBU1RfZm9yVGVzdCA8LSBtaXNtYXRjaF9CTEFTVF9zdGF0dXMgJT4lIHVuaXRlKG1hdGNoX3NwZWNpZXMsIGMobWF0Y2hTdGF0dXMscmVmU3BlY2llcykpCgojVGVzdCBkaWZmZXJlbmNlcyBpbiBSZWZfUXVlcnlfQUFsZW5SYXRpbwphb3ZfbGVuUmF0LnJlcyA8LSBhb3YoUmVmX1F1ZXJ5X0FBbGVuUmF0aW8gfiBtYXRjaF9zcGVjaWVzLCBkYXRhID0gbWlzbWF0Y2hfQkxBU1RfZm9yVGVzdCApCnN1bW1hcnkoYW92X2xlblJhdC5yZXMpCgojTXVsdGlwbGUgcGFpci13aXNlIGNvbXBhcmlzb25zClR1a2V5SFNEKGFvdl9sZW5SYXQucmVzKQoKI1Rlc3QgZGlmZmVyZW5jZXMgaW4gYml0X3Njb3JlCmFvdl9iaXRTY29yZS5yZXMgPC0gYW92KGJpdF9zY29yZSB+IG1hdGNoX3NwZWNpZXMsIGRhdGEgPSBtaXNtYXRjaF9CTEFTVF9mb3JUZXN0ICkKc3VtbWFyeShhb3ZfYml0U2NvcmUucmVzKQoKI011bHRpcGxlIHBhaXItd2lzZSBjb21wYXJpc29ucwpUdWtleUhTRChhb3ZfYml0U2NvcmUucmVzKQoKCgpgYGAKCgojUEZBTSBjb2RlIG1hdGNoaW5nCgpKb2luIFBGQU0gYW5ub3RhdGlvbiBkYXRhYmFzZXMgYW5kIGlkZW50aWZ5IHF1ZXJ5OnJlZmVyZW5jZSBwYWlycyB3aXRoIGF0IGxlYXN0IDEgbWF0Y2hpbmcgUEZBTSBjb2RlLiAgCkFubm90YXRpb246IFBGQU0gY29kZXMgYXNzaWduZWQgdG8gR2lhcmRpYSBxdWVyeSBwZXB0aWRlczogJ0dEQl9wZmFtJyAgIAogICAgICAgICAgICBQRkFNIGNvZGVzIGFzc2lnbmVkIHRvIHBlcHRpZGVzIGVuY29kaW5nIFBEQiByZWZlcmVuY2Ugc3RydWN0dXJlczogJ1BEQl9wZmFtJy4KCmBgYHtyLCBldmFsPVRSVUV9CgptZXRyaWNzX2xvbmcgPC0gbWV0cmljc19hbGwgJT4lIAogIG11dGF0ZShjb2RlX2NoYWluPXRvdXBwZXIoY29kZWNoYWluKSkgJT4lIAogIGxlZnRfam9pbihHREJfcGZhbSxieT0iR2VuZUlEIikgJT4lIHJlbmFtZShHREJfUEZBTXByZWY9UEZBTXByZWYpICU+JSAKICBsZWZ0X2pvaW4oUERCX3BmYW0sYnk9ImNvZGVfY2hhaW4iKSAlPiUgcmVuYW1lKFBEQl9QRkFNcHJlZj1QRkFNcHJlZikgJT4lIAogIGRpc3RpbmN0KCkgJT4lIHJlbmFtZShHREJfUEZBTV9kZXNjID0gRGVzYywgUERCX1BGQU1fZGVzYyA9IFBGQU1fZGVzYykKCgpgYGAKClBsb3QgbnVtYmVyIG9mIFBGQU0gZG9tYWlucyBwZXIgcXVlcnk6cmVmZXJlbmNlIHBhaXIKYGBge3J9Cm5QRkFNX1FfUiA8LSBtZXRyaWNzX2xvbmcgJT4lIAogIHNlbGVjdChHZW5lSUQsIEdEQl9QRkFNcHJlZiwgUERCX1BGQU1wcmVmKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoR2VuZUlEKSAlPiUgCiAgc3VtbWFyaXplX2F0KHZhcnMoR0RCX1BGQU1wcmVmLCBQREJfUEZBTXByZWYpLCBmdW5zKCAuICU+JSBuYS5vbWl0KCkgJT4lIG5fZGlzdGluY3QgKSkgJT4lIAogIHJlbmFtZShuUEZBTV9HREIgPSBHREJfUEZBTXByZWYsIG5QRkFNX1BEQiA9IFBEQl9QRkFNcHJlZiApCgpuUEZBTV9RX1IgJT4lIGdhdGhlcihrZXksdmFsdWUsLUdlbmVJRCkgJT4lIGdncGxvdChhZXModmFsdWUpKSArCiAgZ2VvbV9iYXIoYWVzKGZpbGw9a2V5KSwgcG9zaXRpb249ImRvZGdlIiwgc2hvdy5sZWdlbmQgPSBUUlVFKSAKYGBgCgoKQ2FsY3VsYXRlIG4uIG1hdGNoaW5nIGRvbWFpbnMKYGBge3J9CgojQmVjYXVzZSBhbGwgcGFpcndpc2UgY29tYmluYXRpb25zIG9mIFBGQU0gZG9tYWlucyBhcmUgbGlzdGVkLCBuZWVkIG9ubHkgZmlsdGVyIGZvciBleGFjdCBtYXRjaDoKbk1hdGNoX2NvdW50IDwtIG1ldHJpY3NfbG9uZyAlPiUgCiAgc2VsZWN0KEdlbmVJRCxjb2RlLGNoYWluLGNvZGVfY2hhaW4sR0RCX1BGQU1wcmVmLFBEQl9QRkFNcHJlZikgJT4lCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoR2VuZUlEKSAlPiUgCiAgZmlsdGVyKEdEQl9QRkFNcHJlZj09UERCX1BGQU1wcmVmKSAlPiUgCiAgc3VtbWFyaXplKG5fTWF0Y2ggPSBuKCkpIAogIApuTWF0Y2ggPC0gbWV0cmljc19hbGxbICwgIkdlbmVJRCJdICU+JSAKICBsZWZ0X2pvaW4obk1hdGNoX2NvdW50LCBieT0iR2VuZUlEIikgJT4lIAogIG11dGF0ZShuX01hdGNoID0gaWZlbHNlKGlzLm5hKG5fTWF0Y2gpLCAwICxuX01hdGNoKSkgCgpgYGAKClN1bW1hcml6ZSBQRkFNIG1hdGNoZXMgYWNyb3NzIGFubm90YXRpb24gZ3JvdXBzCmBgYHtyfQoKbWV0cmljc19uTWF0Y2ggPC0gbWV0cmljc19hbGwgJT4lIAogIGxlZnRfam9pbihuUEZBTV9RX1IsIGJ5PSJHZW5lSUQiKSAlPiUgCiAgbGVmdF9qb2luKG5NYXRjaCxieT0iR2VuZUlEIikgJT4lIAogICBtdXRhdGUobl9NYXRjaD1pZmVsc2UoaXMubmEobl9NYXRjaCksIDAsIG5fTWF0Y2gpKSAlPiUgCiAgIG11dGF0ZShtYXRjaFN0YXR1cz1pZmVsc2Uobl9NYXRjaD09MCwnbm9NYXRjaCcsJ2V4YWN0TWF0Y2gnKSkgJT4lIAogICBsZWZ0X2pvaW4oR2VuZURlc2MsYnk9IkdlbmVJRCIpICU+JSBzZWxlY3QoR2VuZUlELERlc2NyaXB0aW9uLGV2ZXJ5dGhpbmcoKSkgJT4lIAogICBtdXRhdGUoZGVzY0JpbiA9IGlmZWxzZShzdHJfZGV0ZWN0KERlc2NyaXB0aW9uLCdoeXBvdGhldGljYWwnKSB8IHN0cl9kZXRlY3QoRGVzY3JpcHRpb24sJ0h5cG90aGV0aWNhbCcpLCAnSHlwJywnQW5ub3QnKSkgCmBgYAoKYGBge3J9Cm1ldHJpY3Nfbk1hdGNoICU+JSBjb3VudChkZXNjQmluLG1hdGNoU3RhdHVzKSAKYGBgCgoKIyNTRmlndXJlIDIKUmVsYXRpdmUgcGVwdGlkZSBsZW5ndGggYW5kIG51bWJlciBvZiBtYXRjaGluZyBQRkFNIGRvbWFpbnMuCmBgYHtyfQpsZW5SYXRpb19YX25NYXRjaCA8LSBtZXRyaWNzX25NYXRjaCAlPiUgCiAgc2VsZWN0KEdlbmVJRCwgQ292LCBHREJfQUEsIGxlblJhdGlvLCBjb250YWlucygnblBGQU0nKSxuX01hdGNoLCBkZXNjQmluKSAlPiUgCiAgbXV0YXRlKGBuX01hdGNoOm5QRkFNX1BEQmAgPSBuX01hdGNoL25QRkFNX1BEQikgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZ3JvdXBfYnkobl9NYXRjaCwgblBGQU1fUERCKSAlPiUgc3VtbWFyaXplKG1lZGlhbl9sZW5SYXRpbyA9IG1lZGlhbihsZW5SYXRpbyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuX2xlblJhdGlvID0gbWVhbihsZW5SYXRpbyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuX0dEQl9BQWxlbiA9IG1lYW4oR0RCX0FBKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbl9HREJfQUFsZW4gPSBtZWRpYW4oR0RCX0FBKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX3NpemUgPSBuKCkpICU+JSAKICBhcnJhbmdlKG5fTWF0Y2gsIG5QRkFNX1BEQiwgZGVzYyhncm91cF9zaXplKSkKCgptZXRyaWNzX25NYXRjaCAlPiUgCiAgZmlsdGVyKG5QRkFNX1BEQjw9NCkgJT4lICNmaWx0ZXIobl9NYXRjaD09MCkgJT4lIAogIGZpbHRlcihuUEZBTV9QREI+MCkgJT4lIAogIGdncGxvdCgpICsgCiAgZ2VvbV9ib3hwbG90KGFlcyh4PW5fTWF0Y2ggLCB5PWxlblJhdGlvLCBncm91cD1mYWN0b3Iobl9NYXRjaCkpLCBhbHBoYT0wLCB3aWR0aD0wLjUpKyAgCiAgZ2VvbV9qaXR0ZXIoYWVzKHg9bl9NYXRjaCAsIHk9bGVuUmF0aW8sIGNvbD1mYWN0b3IoblBGQU1fUERCKSwgCiAgICAgICAgICAgICAgICAgIGdyb3VwPWZhY3RvcihuUEZBTV9QREIpKSwgCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcmRvZGdlKGRvZGdlLndpZHRoID0gMC44NSksIGFscGhhPTAuNSwgY2V4PTAuMjUpICsKICBnZW9tX3RleHQoZGF0YT1sZW5SYXRpb19YX25NYXRjaCAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKG5fTWF0Y2g8PTQsIG5QRkFNX1BEQjw9NCksIAogICAgICAgICAgICBhZXMoeD1uX01hdGNoLCB5PTMsIGxhYmVsPWdyb3VwX3NpemUsIGdyb3VwPW5QRkFNX1BEQiksIHNpemU9MykgKwogIGZhY2V0X3dyYXAoIH4gblBGQU1fUERCKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZ2d0aXRsZSgiTi4gbWF0Y2hpbmcgUEZBTSB0ZXJtcyB2cyBxdWVyeTpyZWZlcmVuY2UgQUEgbGVuZ3RoIHJhdGlvIiwKICAgICAgICAgIHN1YnRpdGxlPSJGYWNldCBieSBuLiBQRkFNIHRlcm1zIGluIFBEQiByZWZlcmVuY2UiKSArCiAgeGxhYigiTi4gbWF0Y2hpbmcgUEZBTSBkb21haW5zIikgKyB5bGFiKCJRdWVyeTpyZWZlcmVuY2UgQUEgbGVuZ3RoIHJhdGlvIikKCmdnc2F2ZSgiLi4vcmVzdWx0cy9TRjIucGRmIix3aWR0aD02LGhlaWdodD02KQoKYGBgCgoKIyNGaWd1cmUgMmEKUGxvdCBpbnRlcnNlY3Rpb24gb2YgQkxBU1QgYW5ub3RhdGlvbiBzdGF0dXMgYW5kIFBGQU0gY29kZSBhbm5vdGF0aW9ucy4KCmBgYHtyfQpzb3VyY2UoInVwc2V0LlIiKQoKdXBTZXRzIDwtIG1ldHJpY3Nfbk1hdGNoICU+JSBzZWxlY3QoR2VuZUlELCBkZXNjQmluLCBuUEZBTV9HREIsIG5QRkFNX1BEQiwgbl9NYXRjaCkgJT4lIAogIG11dGF0ZV9hdCh2YXJzKC1HZW5lSUQsIC1kZXNjQmluKSAsIGZ1bnMoYmluYXJ5ID0gaWZlbHNlKC4gPiAwLCAxLCAwKSkpICU+JSAKICBtdXRhdGUoZGVzY0NhdGVnb3J5ID0gaWZlbHNlKGRlc2NCaW49PSJIeXAiLDEsMikpICU+JSAgCiAgZGlzdGluY3QoKSAlPiUgc2VsZWN0KEdlbmVJRCwgZGVzY0NhdGVnb3J5LCBjb250YWlucygnYmluYXJ5JykpICU+JSAKICByZW5hbWUoUXVlcnkgPSBuUEZBTV9HREJfYmluYXJ5LCBSZWZlcmVuY2UgPSBuUEZBTV9QREJfYmluYXJ5LCBNYXRjaCA9IG5fTWF0Y2hfYmluYXJ5KQoKdXBTZXRzICU+JSBjb3VudChkZXNjQ2F0ZWdvcnksIFF1ZXJ5LCBSZWZlcmVuY2UsIE1hdGNoKSAgICAgICAgCgphbm5vdFN0YXR1cyA8LSBmdW5jdGlvbihyb3csIG1pbiwgbWF4KXsKICBuZXdEYXRhIDwtIChyb3dbImRlc2NDYXRlZ29yeSJdIDw9IG1heCkgJiAocm93WyJkZXNjQ2F0ZWdvcnkiXSA+IG1pbil9Cgp1cHNldChkYXRhLmZyYW1lKHVwU2V0cyksIAogICAgICBzZXRzPWMoJ1F1ZXJ5JywnUmVmZXJlbmNlJywnTWF0Y2gnKSwKICAgICAgbWFpbi5iYXIuY29sb3IgPSAnYmxhY2snLAogICAgICBxdWVyaWVzID0gbGlzdChsaXN0KHF1ZXJ5ID0gYW5ub3RTdGF0dXMsIHBhcmFtcyA9IGxpc3QoMSwyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0ibGlnaHQgYmx1ZSIsYWN0aXZlPVRSVUUpKSwgcG9pbnQuc2l6ZT0zKQoKcGRmKCIuLi9yZXN1bHRzL0YyYS5wZGYiLCB3aWR0aCA9IDQsaGVpZ2h0PTMsIG9uZWZpbGUgPSBGQUxTRSkgI3dvcmtzLi5pc2gKI3BkZigiLi4vcmVzdWx0cy9GMmEucGRmIiwgd2lkdGggPSA0LjUsaGVpZ2h0PTMuNSwgb25lZmlsZSA9IEZBTFNFKQp1cHNldChkYXRhLmZyYW1lKHVwU2V0cyksIAogICAgICBzZXRzPWMoJ1F1ZXJ5JywnUmVmZXJlbmNlJywnTWF0Y2gnKSwKICAgICAgbWFpbi5iYXIuY29sb3IgPSAnYmxhY2snLAogICAgICBxdWVyaWVzID0gbGlzdChsaXN0KHF1ZXJ5ID0gYW5ub3RTdGF0dXMsIHBhcmFtcyA9IGxpc3QoMSwyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0ibGlnaHQgYmx1ZSIsYWN0aXZlPVRSVUUpKSwgcG9pbnQuc2l6ZT0zKQoKZGV2Lm9mZigpCgpgYGAKCgoKIyNGaWd1cmUgMmIKClBGQU0gdGVybSBlbnJpY2htZW50IHRlc3RpbmcKCgpgYGB7cn0Kc291cmNlKCJyb3d3aXNlX2Zpc2hlci5SIikKCm1hdGNoU3RhdHVzX1BGQU1jb3VudHMgPC0gbWV0cmljc19sb25nICU+JSAKICBsZWZ0X2pvaW4obWV0cmljc19uTWF0Y2ggJT4lIHNlbGVjdChHZW5lSUQsIG1hdGNoU3RhdHVzKSwgYnk9IkdlbmVJRCIpICU+JSAKICBkcGx5cjo6c2VsZWN0KDEsbGVuUmF0aW8sIG1hdGNoU3RhdHVzLCBHREJfUEZBTXByZWYsUERCX1BGQU1wcmVmKSAlPiUgCiAgZ2F0aGVyKGtleT1EQix2YWx1ZT1QRkFNLC1jKEdlbmVJRCxtYXRjaFN0YXR1cyxsZW5SYXRpbykpICU+JSAKICBuYS5vbWl0KCkgJT4lIAogIGZpbHRlcihsZW5SYXRpbyA+MC45ICYgbGVuUmF0aW8gPDEuMSkgJT4lIHVuZ3JvdXAoKSAlPiUgCiAgY291bnQobWF0Y2hTdGF0dXMsREIsUEZBTSkgJT4lIAogIHNwcmVhZChrZXk9REIsIHZhbHVlPW4sIGZpbGwgPSAwKSAKCiNzZXQgdXAgcGFyYW1ldGVycyBmb3IgRmlzaGVyIHRhYmxlcyAgCm15U3RhdHVzIDwtICJleGFjdE1hdGNoIgptaW5GcmVxIDwtIDMKRm9yZWdyb3VuZCA8LSAnUERCX1BGQU1wcmVmJwpiYWNrZ3JvdW5kIDwtICdHREJfUEZBTXByZWYnCgp0ZXJtU3VtcyA8LSBtYXRjaFN0YXR1c19QRkFNY291bnRzICU+JSAKICBmaWx0ZXIoZ2V0KEZvcmVncm91bmQpID49IG1pbkZyZXEpICU+JQogIGZpbHRlcihtYXRjaFN0YXR1cyA9PSBteVN0YXR1cykgJT4lIAogIHN1bW1hcml6ZShhbGxGb3JlZ3JvdW5kID0gc3VtKGdldChGb3JlZ3JvdW5kKSksCiAgICAgICAgICAgIGFsbEJhY2tncm91bmQgPSBzdW0oZ2V0KGJhY2tncm91bmQpKSwKICAgICAgICAgICAgYWxsVGVybXMgPSBzdW0oZ2V0KEZvcmVncm91bmQpLGdldChiYWNrZ3JvdW5kKSkpICU+JSB1bmxpc3QoKQoKRmlzaGVyX2RmIDwtIG1hdGNoU3RhdHVzX1BGQU1jb3VudHMgJT4lIAogIGZpbHRlcihtYXRjaFN0YXR1cz09bXlTdGF0dXMpICU+JSAKICBkcGx5cjo6cmVuYW1lKEZvcmVncm91bmQgPSBQREJfUEZBTXByZWYsIAogICAgICAgICAgICAgICAgQkFDS0dST1VORCA9IEdEQl9QRkFNcHJlZikgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgbXV0YXRlKHN1bVRlcm09c3VtKEZvcmVncm91bmQsQkFDS0dST1VORCksCiAgICAgICAgIGFsbEZvcmVncm91bmQ9dGVybVN1bXNbWzFdXSwKICAgICAgICAgYWxsQmFja2dyb3VuZD10ZXJtU3Vtc1tbMl1dLAogICAgICAgICBhbGxUZXJtcz10ZXJtU3Vtc1tbM11dKSAlPiUgCiAgbXV0YXRlKCdhJyA9IEZvcmVncm91bmQsCiAgICAgICAgICdiJyA9IHN1bVRlcm0gLSBGb3JlZ3JvdW5kLAogICAgICAgICAnYycgPSBhbGxGb3JlZ3JvdW5kIC0gRm9yZWdyb3VuZCwKICAgICAgICAgJ2QnID0gYWxsVGVybXMgLSBhbGxGb3JlZ3JvdW5kIC0gYikgJT4lIAogIGRwbHlyOjpzZWxlY3QoUEZBTSxGb3JlZ3JvdW5kLEJBQ0tHUk9VTkQsZXZlcnl0aGluZygpKSAlPiUgCiAgdW5ncm91cCgpIAoKCm15ZGF0YSA8LSBGaXNoZXJfZGYKcCA8LSB0KGFwcGx5KG15ZGF0YSAlPiUgCiAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoYSxiLGMsZCkgJT4lIAogICAgICAgICAgICAgICBmaWx0ZXIoYSA+PSBtaW5GcmVxKSwgMSwgcm93X2Zpc2hlcikpCgoKcmVzdWx0cyA8LSBjYmluZChteWRhdGEgJT4lIGZpbHRlcihhID49IG1pbkZyZXEpICU+JSAKICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoMTo3KSwgcCkgJT4lIAojMTo3IGFzIG5vIGJhY2tncm91bmQgb2YgcmVwcmVzc2VkLCBsb3dseSB0cmFuc2NyaWJlZCAoPDAuODUgcGVyY2VudGlsZTsgaS5lLiwgdGhlIGVxdWl2YWxlbnQgb2YgdGhlIG5vbkRURyBzZXQpLCBpcyBpbmNsdWRlZC4KICBhcnJhbmdlKHBfdmFsKSAlPiUgCiAgbXV0YXRlKGFkalA9cC5hZGp1c3QoLiRwX3ZhbCwgbWV0aG9kPSJCSCIgKSkgICNjb3JyZWN0aW9uIGZvciBtdWx0aXBsZSBjb21wYXJpc29ucwoKI05vIHNpZ25pZmljYW50IGVucmljaG1lbnQKcmVzdWx0cyAlPiUgZmlsdGVyKHBfdmFsIDwgMC4wNSkgJT4lIAogIGFycmFuZ2UocF92YWwpICU+JSAKICBmaWx0ZXIobWF0Y2hTdGF0dXM9PSdleGFjdE1hdGNoJykgJT4lIAogIG11dGF0ZShgUmVmZXJlbmNlX1BGQU1gID0gRm9yZWdyb3VuZC9hbGxGb3JlZ3JvdW5kLAogICAgICAgICBgUXVlcnlfUEZBTWAgPSBCQUNLR1JPVU5EL2FsbEJhY2tncm91bmQpICU+JSAKICBsZWZ0X2pvaW4oUERCX3BmYW0gJT4lIHNlbGVjdChQRkFNcHJlZixQRkFNX05hbWUsUEZBTV9kZXNjKSwgYnk9YygiUEZBTSIgPSAiUEZBTXByZWYiKSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGRwbHlyOjpzZWxlY3QoRm9yZWdyb3VuZCxCQUNLR1JPVU5ELCBQRkFNLFBGQU1fZGVzYyxRdWVyeV9QRkFNLFJlZmVyZW5jZV9QRkFNKSAlPiUgCiAgZmlsdGVyKEZvcmVncm91bmQgPj0gNykgJT4lIHNlbGVjdCgtYyhGb3JlZ3JvdW5kLEJBQ0tHUk9VTkQpKSAlPiUgCiAgZ2F0aGVyKGtleSx2YWx1ZSwtYyhQRkFNLFBGQU1fZGVzYykpICU+JSAKICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihQRkFNX2Rlc2MsdmFsdWUsRlVOPW1heCkseT12YWx1ZSxmaWxsPWtleSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPSJkb2RnZSIsIHNob3cubGVnZW5kID0gVFJVRSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeGxhYigiIikgKyB5bGFiKCJQcm9wb3J0aW9uIG9mIFBGQU0gdGVybXMiKSArCiAgbGFicyhmaWxsPSIiKQoKZ2dzYXZlKCIuLi9yZXN1bHRzL0YyYi5wZGYiLHdpZHRoPTgsaGVpZ2h0PTMuNSkKYGBgCgoKCiMjQ2hlY2sgcHV0YXRpdmUgYWRkaXRpb25hbCBkb21haW5zIGluIE5FSyBraW5hc2VzCkVGIGhhbmQgZG9tYWlucyBpbiBORUsga2luYXNlcwpgYGB7cn0KbWV0cmljc19uTWF0Y2ggJT4lIGZpbHRlcihuX01hdGNoID4gMCwgc3RyX2RldGVjdChEZXNjcmlwdGlvbiwiTkVLIikpICU+JSAKICBmaWx0ZXIoblBGQU1fUERCID4gbl9NYXRjaCkgJT4lIAogIGZpbHRlcihjb2RlPT0iM0hYNCIpICU+JSAKICBsZWZ0X2pvaW4obWV0cmljc19sb25nLGJ5PSJHZW5lSUQiKSAlPiUgCiAgc2VsZWN0KEdlbmVJRCwgbl9NYXRjaCwgY29udGFpbnMoIlBGQU1wcmVmIiksIGNvbnRhaW5zKCJQRkFNX2Rlc2MiKSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGZpbHRlcihQREJfUEZBTXByZWY9PSJQRjEzNDk5IikgCgpgYGAKCgpLaW5hc2UgZG9tYWlucyBoeXBvdGhldGljYWwgcHJvdGVpbnMKYGBge3J9Cm1ldHJpY3Nfbk1hdGNoICU+JSAKICBmaWx0ZXIoZGVzY0Jpbj09Ikh5cCIpICU+JSAKICBmaWx0ZXIoblBGQU1fUERCID4gbl9NYXRjaCkgJT4lIAogIGZpbHRlcihjb2RlPT0iNE8xTyIpICU+JSAKICBsZWZ0X2pvaW4obWV0cmljc19sb25nLGJ5PSJHZW5lSUQiKSAlPiUgCiAgZ3JvdXBfYnkoR2VuZUlEKSAlPiUgZmlsdGVyKCFzdHJfZGV0ZWN0KEdEQl9QRkFNX2Rlc2MsJ2tpbmFzZScpKSAlPiUgCiAgc2VsZWN0KEdlbmVJRCwgbl9NYXRjaCwgY29udGFpbnMoIlBGQU1wcmVmIiksIGNvbnRhaW5zKCJQRkFNX2Rlc2MiKSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIGNvdW50KEdlbmVJRCkKICAgICAgICAgCmBgYAoKCgojI0ZpZ3VyZSAyYwpQbG90IG4uIHVuaXF1ZSBQRkFNIGNvZGVzIGF2YWlsYWJsZSB2aWEgcXVlcnkgYW5kIHJlZmVyZW5jZSBwZXB0aWRlcy4KYGBge3J9Cm1ldHJpY3Nfbk1hdGNoICU+JSBzZWxlY3QoR2VuZUlELCBjb250YWlucygnblBGQU0nKSwgIG5fTWF0Y2gsIG1hdGNoU3RhdHVzKSAlPiUgCiAgZmlsdGVyKG1hdGNoU3RhdHVzPT0iZXhhY3RNYXRjaCIpICU+JSAKICBzZWxlY3QoY29udGFpbnMoJ25QRkFNJykpICU+JSAKICBnYXRoZXIoa2V5PXNvdXJjZSx2YWx1ZT1uUEZBTSkgJT4lIAogIGdncGxvdChhZXMoeD1uUEZBTSkpICsgZ2VvbV9iYXIoYWVzKGZpbGw9c291cmNlKSwgcG9zaXRpb249ImRvZGdlIikgKwogIHhsYWIoIk4uIHVuaXF1ZSBQRkFNIGNvZGVzIikgKyB5bGFiKCJOLiBwcm90ZWlucyIpCgoKbWV0cmljc19uTWF0Y2ggJT4lIHNlbGVjdChHZW5lSUQsIGNvbnRhaW5zKCduUEZBTScpLCAgbl9NYXRjaCwgbWF0Y2hTdGF0dXMpICU+JSAKICBmaWx0ZXIobWF0Y2hTdGF0dXM9PSJleGFjdE1hdGNoIikgJT4lIAogIHNlbGVjdChjb250YWlucygnblBGQU0nKSkgJT4lIAogIGdhdGhlcihrZXk9c291cmNlLHZhbHVlPW5QRkFNKSAlPiUgCiAgZ3JvdXBfYnkoc291cmNlKSAlPiUgc3VtbWFyaXplKG1lYW5fblBGQU09bWVhbihuUEZBTSkpIAoKZ2dzYXZlKCIuLi9yZXN1bHRzL0YyYy5wZGYiLHdpZHRoPTUsaGVpZ2h0PTQpCgpgYGAKCgoKCgojUmFuZG9tIGZvcmVzdCBjbGFzc2lmaWVyCgojI1RyYWluIGNsYXNzaWZpZXIKQ3JlYXRlIHRyYWluaW5nIGFuZCB0ZXN0IGRhdGEKYGBge3IsIGV2YWw9VFJVRX0KCkdkX2ZvclJGIDwtIG1ldHJpY3Nfbk1hdGNoICU+JSBzZWxlY3QoMSxUTTpSTVNEX21vZGVsX3NkLGxlblJhdGlvLFNTX3NkLG1hdGNoU3RhdHVzKSAlPiUgbmEub21pdCgpCiNHZF9mb3JSRiAlPiUgc3RyKCkKICAKZ2VuZU9yZGVyIDwtIHJlYWRfdHN2KCIuLi9kYXRhL0dkX2ZvclJGX2dlbmVJRG9yZGVyLnRzdiIpCgpHZF9mb3JSRiA8LSBnZW5lT3JkZXIgJT4lIGxlZnRfam9pbihHZF9mb3JSRiwgYnk9IkdlbmVJRCIpICAjb3JpZ2luYWwgZ2VuZU9yZGVyCgoKc2V0LnNlZWQoMTIzNCkgOyBmb3JUUkFJTl9leGFjdCA8LSBHZF9mb3JSRiAlPiUgZmlsdGVyKG1hdGNoU3RhdHVzPT0iZXhhY3RNYXRjaCIpICU+JSAgc2FtcGxlX24oNzUwKTsKc2V0LnNlZWQoMTIzNCkgOyBmb3JUUkFJTl9ub01hdGNoIDwtIEdkX2ZvclJGICU+JSBmaWx0ZXIobWF0Y2hTdGF0dXMhPSJleGFjdE1hdGNoIikgJT4lICBzYW1wbGVfbig3NTApOwpmb3JUUkFJTiA8LSByYmluZChmb3JUUkFJTl9leGFjdCwgZm9yVFJBSU5fbm9NYXRjaCkKCiNzZXQuc2VlZCgxMjM0KTsgVEVTVCA8LSBHZF9mb3JSRiAlPiUgYW50aV9qb2luKGZvclRSQUlOLCBieT0iR2VuZUlEIikgJT4lIHNhbXBsZV9uKDE1MDApIDsgCgpzZXQuc2VlZCg0MzIxKTsgZm9yVEVTVF9leGFjdCA8LSBHZF9mb3JSRiAlPiUgYW50aV9qb2luKGZvclRSQUlOX2V4YWN0LCBieT0iR2VuZUlEIikgJT4lIGZpbHRlcihtYXRjaFN0YXR1cz09ImV4YWN0TWF0Y2giKSAlPiUgc2FtcGxlX24oMjUwKQogICAgICAKc2V0LnNlZWQoNDMyMSk7IGZvclRFU1Rfbm9NYXRjaCA8LSBHZF9mb3JSRiAlPiUgYW50aV9qb2luKGZvclRSQUlOX25vTWF0Y2gsIGJ5PSJHZW5lSUQiKSAlPiUgZmlsdGVyKG1hdGNoU3RhdHVzIT0iZXhhY3RNYXRjaCIpICU+JSBzYW1wbGVfbigyNTApCgpURVNUIDwtIHJiaW5kKGZvclRFU1RfZXhhY3QsIGZvclRFU1Rfbm9NYXRjaCkgCgpUUkFJTiA8LSBmb3JUUkFJTiAlPiUgZHBseXI6OnNlbGVjdCgtYyhHZW5lSUQpKSAKYGBgCgpNb2RlbCB0cmFpbmluZyBpcyBvbmx5IHJ1biBvbmNlLgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpyZl9tb2RlbCA8LSB0cmFpbihtYXRjaFN0YXR1cyB+LiAsIGRhdGE9VFJBSU4sIG1ldGhvZD0icmYiLAogICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kPSJjdiIsIG51bWJlcj01LCB2ZXJib3NlSXRlcj1UUlVFKSwKICAgICAgICAgICAgICAgICAgcHJveD1UUlVFLCB2ZXJib3NlPVRSVUUpCnNhdmVSRFMocmZfbW9kZWwsIi4uL2RhdGEvcmZfbW9kZWwuUmRzIikKYGBgCgpQcmludCBmaW5hbCBtb2RlbApgYGB7cn0KcmZfbW9kZWwgPC0gcmVhZFJEUygiLi4vZGF0YS9yZl9tb2RlbC5SZHMiKQoKcHJpbnQocmZfbW9kZWwkZmluYWxNb2RlbCkKCmBgYAoKCgojI0NsYXNzaWZpZXIgcGVyZm9ybWFuY2UKYGBge3J9CgpwcmVkVEVTVCA8LSBwcmVkaWN0KHJmX21vZGVsLCBuZXdkYXRhPVRFU1QsIHR5cGU9InByb2IiKQpwcmVkQUxMIDwtIHByZWRpY3QocmZfbW9kZWwsIG5ld2RhdGE9R2RfZm9yUkYsIHR5cGU9InByb2IiKQoKI3N1bW1hcnkocHJlZFRFU1QpCiNzdW1tYXJ5KHByZWRBTEwpCgoKI2FjY3VyYWN5IG9uIGhvbGQtb3V0IFRFU1Qgc2V0OgpURVNUICU+JSAgbXV0YXRlKFJGZXhhY3RfcHJlZCA9IHByZWRURVNUJGV4YWN0TWF0Y2gpICU+JSAKICBtdXRhdGUocHJlZFN0YXR1cz1pZmVsc2UoUkZleGFjdF9wcmVkID49IDAuNSwiZXhhY3RNYXRjaCIsIm5vTWF0Y2giKSkgJT4lIAogIGNvdW50KG1hdGNoU3RhdHVzLCBwcmVkU3RhdHVzKQoKI2VudGlyZSBwcm90ZW9tZQpHZF9mb3JSRiAlPiUgbXV0YXRlKFJGZXhhY3RfcHJlZCA9IHByZWRBTEwkZXhhY3RNYXRjaCkgJT4lIAogIG11dGF0ZShwcmVkU3RhdHVzPWlmZWxzZShSRmV4YWN0X3ByZWQgPj0gMC41LCJleGFjdE1hdGNoIiwibm9NYXRjaCIpKSAlPiUgCiAgY291bnQobWF0Y2hTdGF0dXMsIHByZWRTdGF0dXMpCgpHZF9tYXRjaFByZWRpY3QgPC0gR2RfZm9yUkYgJT4lIG11dGF0ZShleGFjdE1hdGNoUHJlZCA9IHByZWRBTEwkZXhhY3RNYXRjaCkgJT4lIHVuZ3JvdXAoKQoKCmBgYAoKIyNGaWcgM2EKIyMjQ29tcHV0ZSBmZWF0dXJlIGltcG9ydGFuY2UgCmBgYHtyfQoKR2RfaW1wIDwtIGRhdGEuZnJhbWUodmFySW1wKHJmX21vZGVsLCBzY2FsZT1GQUxTRSkkaW1wb3J0YW5jZSkgIAoKR2RfaW1wJG5vaSAgPC0gcm93Lm5hbWVzKEdkX2ltcCk7IHJvdy5uYW1lcyhHZF9pbXApIDwtIE5VTEwKbmFtZXMoR2RfaW1wKSA8LSBjKCdDb250cmlibicsICdpbXBGYWN0b3InKSA7ICNoZWFkKEdkX2ltcCkKR2RfaW1wIDwtIEdkX2ltcCAlPiVkcGx5cjo6c2VsZWN0KDIsMSkgJT4lIGFycmFuZ2UoZGVzYyhDb250cmlibikpICU+JSAgbXV0YXRlKHByb3BDb250ID0gQ29udHJpYm4vc3VtKENvbnRyaWJuKSkKCmltcF9wbG90IDwtIEdkX2ltcCAlPiUgCiAgbXV0YXRlKGltcEZhY3Rvcl9yZWNvZGUgPSBjYXNlX3doZW4oaW1wRmFjdG9yPT0iQUFwYyIgfiAnQUFfJUlEJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltcEZhY3Rvcj09IkNzY29yZSIgfiAnQ19zY29yZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbXBGYWN0b3I9PSJBQXBjIiB+ICJBQV8lSUQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1wRmFjdG9yPT0iQ292IiB+ICdDb3ZlcmFnZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbXBGYWN0b3I9PSJleGFjdE1hdGNoUHJlZCIgfiAnRXhhY3RfbWF0Y2hfcHJlZGljdGlvbicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbXBGYWN0b3I9PSJsZW5SYXRpbyIgfiAnTGVuZ3RoX3JhdGlvJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBpbXBGYWN0b3IpKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXJlb3JkZXIoaW1wRmFjdG9yX3JlY29kZSwgcHJvcENvbnQpLCB5PXByb3BDb250KSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgYWVzKGZpbGw9aW1wRmFjdG9yX3JlY29kZSksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICB5bGFiKCJJbXBvcnRhbmNlIikgKyB4bGFiKCIiKSArIHlsaW0oMCwwLjMpICsKICBjb29yZF9mbGlwKCkgIAoKaW1wX3Bsb3QKCmdnc2F2ZSgiLi4vcmVzdWx0cy9TRjNhLnBkZiIsaW1wX3Bsb3QsIHdpZHRoPTQsaGVpZ2h0PTMpCgpgYGAKCgojI0ZpZyAzYgojIyNTZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHkKCmBgYHtyfQoKIyNBVVJPQwoKI2h0dHBzOi8vZ2lzdC5naXRodWIuY29tL2p3YWFnZS82ZDhmNGViMDk2ZTRmMThhMDg5NGNhMWNlMjdhZjgzNAoKZm9yUk9DIDwtIEdkX21hdGNoUHJlZGljdCAlPiUgCiAgZHBseXI6OnNlbGVjdChUTTpleGFjdE1hdGNoUHJlZCkgJT4lIAogIG11dGF0ZShtYXRjaFN0YXR1cyA9IGFicyhhcy5udW1lcmljKGZhY3RvcihtYXRjaFN0YXR1cykpLTIpKSAKCmF1Y091dCA8LSBkYXRhX2ZyYW1lKCdzZW5zUGx0JyA9IE5BLCAnc3BlY1BsdCcgPSBOQSwgJ01ldHJpYyc9TkEsJ0FVQycgPSBOQSkKZm9yIChpIGluIG5hbWVzKGZvclJPQykpeyNwcmludChpKQogIHIgPC0gcm9jKGZvclJPQyRtYXRjaFN0YXR1cywgZm9yUk9DWyAsIGldICU+JSBwdWxsKCkpCiAgc2VucyA8LSByJHNlbnNpdGl2aXRpZXMKICBzcGVjIDwtIHIkc3BlY2lmaWNpdGllcwogIGEgPC0gYXVjKHIpWzFdCiAgcm5kIDwtIHJvdW5kKGEsMykKICByZXN1bHQgPC0gZGF0YV9mcmFtZSgnc2Vuc1BsdCcgPSByZXYoc2VucyksICdzcGVjUGx0JyA9IHJldihzcGVjKSkgJT4lIG11dGF0ZShNZXRyaWMgPSBpLCBBVUMgPSBybmQpCiAgYXVjT3V0IDwtIHJiaW5kKGF1Y091dCxyZXN1bHQpICU+JSBuYS5vbWl0KCkgfQoKYXVjX3Bsb3QgPC0gYXVjT3V0ICU+JSAgbXV0YXRlKE1ldHJpYyA9IGNhc2Vfd2hlbihNZXRyaWM9PSJBQXBjIiB+ICdBQV8lSUQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWV0cmljPT0iQ3Njb3JlIiB+ICdDX3Njb3JlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1ldHJpYz09IkFBcGMiIH4gIkFBXyVJRCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNZXRyaWM9PSJDb3YiIH4gJ0NvdmVyYWdlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1ldHJpYz09ImV4YWN0TWF0Y2hQcmVkIiB+ICdFeGFjdF9tYXRjaF9wcmVkaWN0aW9uJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1ldHJpYz09ImxlblJhdGlvIiB+ICdBQV9sZW5ndGhfcmF0aW8nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE1ldHJpYykpICU+JSAKICBmaWx0ZXIoTWV0cmljICE9Im1hdGNoU3RhdHVzIikgJT4lIAogIGRpc3RpbmN0KCkgJT4lIG5hLm9taXQoKSAlPiUgZmlsdGVyKEFVQyA+PSAwLjcpICU+JSAKICBnZ3Bsb3QoYWVzKHg9c3BlY1BsdCx5PXNlbnNQbHQpKSArIAogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAxLCB4ZW5kID0gMSwgeWVuZCA9IDApLCBhbHBoYSA9IDAuNSkgKyAKICBnZW9tX3N0ZXAoYWVzKGNvbD1NZXRyaWMpLCBsdHkgPSAyLGx3ZD0xKSArCiAgc2NhbGVfeF9yZXZlcnNlKG5hbWUgPSAiRmFsc2UgcG9zaXRpdmUgcmF0ZSAoU3BlY2lmaWNpdHkpIixsaW1pdHMgPSBjKDEsMCkpICsgCiAgeWxhYigiVHJ1ZSBwb3NpdGl2ZSByYXRlIChTZW5zaXRpdml0eSkiKSArIAogIGNvb3JkX2VxdWFsKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIkFBXyVJRCIgPSAiI0Y4NzY2RCIsIkNfc2NvcmUiID0gIiNERThDMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkV4YWN0X21hdGNoX3ByZWRpY3Rpb24iID0gJ2JsYWNrJywnQUFfbGVuZ3RoX3JhdGlvJyA9ICIjMDBCQTM4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSTVNEIiA9ICIjMDBCRkM0IiwiVE1fbW9kZWwiID0gIiNGNTY0RTMiKSkgCgphdWNPdXQgJT4lIHNlbGVjdCgtY29udGFpbnMoJ1BsdCcpKSAlPiUgZGlzdGluY3QoKSAlPiUgYXJyYW5nZShkZXNjKEFVQykpCgphdWNfcGxvdAoKZ2dzYXZlKCIuLi9yZXN1bHRzL0YzYi5wZGYiLGF1Y19wbG90LCB3aWR0aD01LGhlaWdodD01KQoKYGBgCgoKIyNUZXN0IGNsYXNzaWZpZXIgb24gbW9kZWxzIGZyb20gSHVtYW4KYGBge3J9CgpIc19URVNUIDwtIHJlYWRfdHN2KCIuLi9kYXRhL0hzYXBpZW5zX1RFU1RkYXRhLnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKCndyaXRlX3RzdihIc19URVNULCBwYXRoPSIuLi9yZXN1bHRzL1NUYWJsZTEudHN2IikKCiNjb25maXJtIHRoYXQgR2QgVFJBSU5pbmcgc2V0IGFuZCBIc19URVNUIHNldCBoYXZlIHNhbWUgZm9ybWF0CiNUUkFJTiAlPiUgc3RyKCkKI0hzX1RFU1RbLDM6MTRdICU+JSBzdHIoKQoKcHJlZF9IcyA8LSBhc190aWJibGUocHJlZGljdChyZl9tb2RlbCwgbmV3ZGF0YT1Ic19URVNUWywzOjE0XSwgdHlwZT0icHJvYiIpKQpIc19URVNUcHJlZCA8LSBjYmluZChIc19URVNULHByZWRfSHMpIAoKSHNfVEVTVHByZWQgJT4lIG11dGF0ZShwcmVkX21hdGNoU3RhdHVzID0gaWZlbHNlKGV4YWN0TWF0Y2ggPiAwLjUsJ2V4YWN0Jywnbm9NYXRjaCcpKSAlPiUgCiAgY291bnQobWF0Y2hTdGF0dXMsIHByZWRfbWF0Y2hTdGF0dXMpICU+JSAKICBncm91cF9ieShtYXRjaFN0YXR1cykgJT4lIG11dGF0ZShncEVycj1uL3N1bShuKSkKCmBgYAoKCiMjTWV0cmljIGRpc3RyaWJ1dGlvbiBieSBSRiBjb25maWRlbmNlCmBgYHtyfQoKR2RfYWxsIDwtIG1ldHJpY3Nfbk1hdGNoICU+JSBsZWZ0X2pvaW4oR2RfbWF0Y2hQcmVkaWN0ICU+JSBkcGx5cjo6c2VsZWN0KDEsZXhhY3RNYXRjaFByZWQpLGJ5PSJHZW5lSUQiKSAgCgpHZF9hbGxfUkZjb25mIDwtIEdkX2FsbCAlPiUgCiAgbXV0YXRlKFJGX2NvbmZpZGVuY2UgPSBjYXNlX3doZW4obWF0Y2hTdGF0dXM9PSJleGFjdE1hdGNoIiAmIGV4YWN0TWF0Y2hQcmVkID49IDAuNSB+ICdIaUNvbmYnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoU3RhdHVzPT0ibm9NYXRjaCIgJiBleGFjdE1hdGNoUHJlZCA8IDAuNSAgICAgICAgfiAnTG93ZXJDb25mJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaFN0YXR1cz09ImV4YWN0TWF0Y2giICYgZXhhY3RNYXRjaFByZWQgPCAwLjUgICAgIH4gIkxvd2VyQ29uZi1saWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaFN0YXR1cz09Im5vTWF0Y2giICYgZXhhY3RNYXRjaFByZWQgPj0gMC41ICAgICAgIH4gIkhpQ29uZi1saWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIiIpKSAKCgpHZF9hbGxfUkZjb25mICU+JSBzZWxlY3QoVE06Uk1TRF9tb2RlbF9zZCxsZW5SYXRpbyxTU19zZCxtYXRjaFN0YXR1cyxleGFjdE1hdGNoUHJlZCxSRl9jb25maWRlbmNlKSAlPiUgCiAgcmVuYW1lKEV4YWN0X21hdGNoX3ByZWRpY3Rpb24gPSBleGFjdE1hdGNoUHJlZCwgQUFfbGVuZ3RoX3JhdGlvID0gbGVuUmF0aW8sCiAgICAgICAgIGBBQV8lSURgID0gQUFwYywgQ292ZXJhZ2UgPSBDb3YsIENfc2NvcmUgPSBDc2NvcmUpICU+JSAKICBmaWx0ZXIoQ19zY29yZSA+IC04ICYgUk1TRF9tb2RlbCA8IDI1KSAlPiUgCiAgZ2F0aGVyKGtleSx2YWx1ZSwtYyhSRl9jb25maWRlbmNlLG1hdGNoU3RhdHVzKSkgJT4lIAogIGZpbHRlcihzdHJfZGV0ZWN0KFJGX2NvbmZpZGVuY2UsIkNvbmYiKSkgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgbXV0YXRlKGtleSA9IGZjdF9yZWxldmVsKGZhY3RvcihrZXkpLCBjKCdTU19zZCcsICdDX3Njb3JlJywnQ19zZCcsICdBQV9sZW5ndGhfcmF0aW8nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVE0nLCdSTVNEJywnQUFfJUlEJywnQ292ZXJhZ2UnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVE1fbW9kZWwnLCdUTV9tb2RlbF9zZCcsJ1JNU0RfbW9kZWwnLCdSTVNEX21vZGVsX3NkJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0V4YWN0X21hdGNoX3ByZWRpY3Rpb24nKSkpICU+JSAKICBnZ3Bsb3QoYWVzKHg9a2V5LCB5PXZhbHVlLCBjb2w9UkZfY29uZmlkZW5jZSkpICsgCiAgZ2VvbV9wb2ludChwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjEsIGRvZGdlLndpZHRoPTEpLCAKICAgICAgICAgICAgIHNpemU9MC4wMiwgYWxwaGE9MC4yLCBzaG93LmxlZ2VuZCA9IFRSVUUpICsKICBnZW9tX2JveHBsb3QoIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDEpLCBhbHBoYT0wKSArCiAgeGxhYigiIikgKyB5bGFiKCIiKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MCkpICsKICBmYWNldF93cmFwKCB+IGtleSwgc2NhbGVzPSJmcmVlIikKCmdnc2F2ZSgiLi4vcmVzdWx0cy9GNC5wZGYiLHdpZHRoPTkuNSxoZWlnaHQ9OSkKCmBgYAoKCgoKIyNTRmlndXJlIDRhClRlY2huaWNhbCB2YXJpYXRpb246IFRyYWluIDUwMCBtb2RlbHMgb24gdGhlIHNhbWUgZGF0YS4KYGBge3IsIGV2YWwgPSBGQUxTRX0KClJGX3RyYWluX2l0ZXI1MDAgPC0gZGF0YV9mcmFtZSgnZHVtbXknPXJlcChOQSwgbnJvdyhHZF9mb3JSRikpKQpmb3IoaSBpbiAxOjUwMCl7CiAgCiAgYSA8LSB0cmFpbihtYXRjaFN0YXR1cyB+LiAsIGRhdGE9VFJBSU4sIG1ldGhvZD0icmYiLAogICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZD0iY3YiLCBudW1iZXI9NSwgdmVyYm9zZUl0ZXI9VFJVRSksCiAgICAgICAgICAgICBwcm94PVRSVUUsIHZlcmJvc2U9VFJVRSkKICAKICBmbSA8LSBhc19kYXRhX2ZyYW1lKHByZWRpY3QoYSwgbmV3ZGF0YSA9IEdkX2ZvclJGLCB0eXBlPSJwcm9iIikpCiAgZm0gPC0gZm1bICwgMV0KICBuYW1lcyhmbSkgPC0gcGFzdGUwKCdyZl8nLGkpCiAgUkZfdHJhaW5faXRlcjUwMCA8LSBjYmluZChSRl90cmFpbl9pdGVyNTAwLCBmbSkKICAKfQoKUkZfdHJhaW5faXRlcjUwMCA8LSBSRl90cmFpbl9pdGVyNTAwWyAsIC0xXQoKc2F2ZVJEUyhSRl90cmFpbl9pdGVyNTAwLCAiLi4vZGF0YS9SRl90cmFpbl9pdGVyNTAwLlJkcyIpCmBgYAogClBsb3QgdGVjaG5pY2FsIHZhcmlhdGlvbgpgYGB7cn0KClJGX3RyYWluX2l0ZXI1MDAgPC0gcmVhZFJEUygiLi4vZGF0YS9SRl90cmFpbl9pdGVyNTAwLlJkcyIpCgpSRl90cmFpbl9pdGVyNTAwX3N1bW1hcnkgPC0gZGF0YV9mcmFtZSgnbWVhbicgPSByb3dNZWFucyhSRl90cmFpbl9pdGVyNTAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAnc2QnID0gYXBwbHkoUkZfdHJhaW5faXRlcjUwMCAsMSwgc2QsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAnc2VtJyA9IGFwcGx5KFJGX3RyYWluX2l0ZXI1MDAgLCAxLCBmdW5jdGlvbih4KSBzZCh4KS9zcXJ0KGxlbmd0aCh4KSkpLAogICAgICAgICAgICAgICAgICAgICAgJ2xlbicgPSBhcHBseShSRl90cmFpbl9pdGVyNTAwICwgMSwgbGVuZ3RoICkpClJGX3RyYWluX2l0ZXI1MDBfc3VtbWFyeSAlPiUgY2JpbmQoR2RfZm9yUkYpICU+JSBkcGx5cjo6c2VsZWN0KG1lYW4sc2Qsc2VtLG1hdGNoU3RhdHVzKSAlPiUgCiAgZ2dwbG90KGFlcyhtZWFuLCBsb2cxMCgxL3NkKSkpICsgZ2VvbV9wb2ludChhZXMoY29sPW1hdGNoU3RhdHVzKSwgY2V4PTAuNSkgKwogIHlsaW0oMSwzLjUpCgpnZ3NhdmUoIi4uL3Jlc3VsdHMvU0Y2YS5wZGYiLHdpZHRoPTUsaGVpZ2h0PTQpCgpgYGAKCgoKCgojI1NGaWd1cmUgNGIKClJvYnVzdG5lc3M6IFRyYWluIDUwIG1vZGVscyBvbiBkaWZmZXJlbnQgdHJhaW5pbmcgZGF0YSBhbmQgc2V0IHNpemVzCmBgYHtyLCBldmFsPUZBTFNFfQpSRl9zYW1wbGVfaXRlcjUwMCA8LSBkYXRhX2ZyYW1lKCJHZW5lSUQiID0gR2RfZm9yUkYgJT4lIHNlbGVjdChHZW5lSUQpICU+JSBwdWxsKCkpCgpmb3IoaSBpbiBjKDUwLDEwMCwyMDAsMzAwLDQwMCw1MDApKXsgCiAgZm9yKGogaW4gMTo1MCl7CiAgICBzYW1wbGVfaXRlclRyYWluIDwtIHJiaW5kKEdkX2ZvclJGICU+JSBmaWx0ZXIobWF0Y2hTdGF0dXM9PSdub01hdGNoJykgJT4lIHNhbXBsZV9uKGkpLAogICAgICAgICAgICAgICAgICAgICAgIEdkX2ZvclJGICU+JSBmaWx0ZXIobWF0Y2hTdGF0dXM9PSdleGFjdE1hdGNoJykgJT4lIHNhbXBsZV9uKGkpKQogICAgCiAgICByZk1vZF9pdGVyIDwtIHRyYWluKG1hdGNoU3RhdHVzIH4gLiAsIGRhdGEgPSBzYW1wbGVfaXRlclRyYWluICU+JSBzZWxlY3QoLUdlbmVJRCksIG1ldGhvZD0icmYiLAogICAgICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kPSJjdiIsIG51bWJlcj01LCB2ZXJib3NlSXRlcj1UUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgcHJveD1UUlVFLCB2ZXJib3NlPVRSVUUpCiAgICBmbV90IDwtIGFzX2RhdGFfZnJhbWUocHJlZGljdChyZk1vZF9pdGVyLCBuZXdkYXRhPUdkX2ZvclJGLCB0eXBlPSJwcm9iIikpCiAgICBmbV90IDwtIGZtX3RbICwgMV0KICAgIG5hbWVzKGZtX3QpIDwtIHBhc3RlKCdyZl90cmFpbicsIDIqaSwgJ2l0ZXInLCBqLCBzZXA9Il8iKQogICAgUkZfc2FtcGxlX2l0ZXI1MDAgPC0gY2JpbmQoUkZfc2FtcGxlX2l0ZXI1MDAsIGZtX3QpCiAgfQp9CgpzYXZlUkRTKFJGX3NhbXBsZV9pdGVyNTAwLCAiLi4vZGF0YS9SRl9zYW1wbGVfaXRlcjUwMC5SZHMiKQoKYGBgCgpQbG90IHJlcHJvZHVjaWJpbGl0eQpgYGB7ciwgZXZhbD1UUlVFfQoKUkZfc2FtcGxlX2l0ZXI1MDAgPC0gcmVhZFJEUygiLi4vZGF0YS9SRl9zYW1wbGVfaXRlcjUwMC5SZHMiKQoKUkZfc2FtcGxlX2l0ZXI1MDAgJT4lIAogIGdhdGhlcihrZXksdmFsdWUsLUdlbmVJRCkgJT4lIAogIHNlcGFyYXRlKGtleSxpbnRvPWMoInYxIiwidjIiLCJ2MyIsInY0IiwidjUiKSxzZXA9Il8iLGNvbnZlcnQgPSBUUlVFKSAlPiUgCiAgc2VsZWN0KEdlbmVJRCx2Myx2NSx2YWx1ZSkgJT4lIGRwbHlyOjpyZW5hbWUodHJhaW5pbmdTZXRTaXplPXYzLGl0ZXJhdGlvbj12NSkgJT4lCiAgZ3JvdXBfYnkoR2VuZUlELHRyYWluaW5nU2V0U2l6ZSkgJT4lIHN1bW1hcml6ZShtZWFuPW1lYW4odmFsdWUpLHNkPXNkKHZhbHVlKSkgJT4lIAogIGxlZnRfam9pbihHZF9mb3JSRiAlPiUgc2VsZWN0KEdlbmVJRCxtYXRjaFN0YXR1cyksYnk9IkdlbmVJRCIpICU+JSAKICBnZ3Bsb3QoYWVzKHg9ZmFjdG9yKHRyYWluaW5nU2V0U2l6ZSkseT1zZCkpICsKICBnZW9tX2JveHBsb3QoYWxwaGE9MC4yLCBhZXMoY29sPW1hdGNoU3RhdHVzICkpICsKICB4bGFiKCdUcmFpbmluZyBzZXQgc2l6ZScpICsgeWxhYigic2QoUHJvYmFiaWxpdHkgb2YgaGlnaC1jb25maWRlbmNlIGNhdGVnb3J5KSIpCgpnZ3NhdmUoIi4uL3Jlc3VsdHMvU0Y2Yi5wZGYiLHdpZHRoPTcsaGVpZ2h0PTQpCmBgYAoKCiMjU0ZpZ3VyZSA0YwpgYGB7cn0KUkZfc2FtcGxlX2l0ZXI1MDAgJT4lIAogIGdhdGhlcihrZXksdmFsdWUsLUdlbmVJRCkgJT4lIAogIHNlcGFyYXRlKGtleSxpbnRvPWMoInYxIiwidjIiLCJ2MyIsInY0IiwidjUiKSxzZXA9Il8iLGNvbnZlcnQgPSBUUlVFKSAlPiUgCiAgc2VsZWN0KEdlbmVJRCx2Myx2NSx2YWx1ZSkgJT4lIAogIGRwbHlyOjpyZW5hbWUodHJhaW5pbmdTZXRTaXplPXYzLGl0ZXJhdGlvbj12NSkgJT4lCiAgZ3JvdXBfYnkoR2VuZUlELHRyYWluaW5nU2V0U2l6ZSkgJT4lIAogIG11dGF0ZShjYWxsPWlmZWxzZSh2YWx1ZT4wLjUsMSwwKSkgJT4lIAogIGdyb3VwX2J5KEdlbmVJRCx0cmFpbmluZ1NldFNpemUpICU+JSAKICBtdXRhdGUobWVhbkNhbGw9bWVhbihjYWxsKSwgbWVhblZhbD1tZWFuKHZhbHVlKSwKICAgICAgICAgc2RDYWxsPXNkKGNhbGwpLCBzZFZhbD1zZCh2YWx1ZSkpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHNlbGVjdCgtYyh2YWx1ZSxpdGVyYXRpb24sY2FsbCkpICU+JSBkaXN0aW5jdCgpICU+JSAKICBsZWZ0X2pvaW4oR2RfZm9yUkYgJT4lIHNlbGVjdChHZW5lSUQsIG1hdGNoU3RhdHVzKSxieT0iR2VuZUlEIikgJT4lIAogIGxlZnRfam9pbihHZF9hbGxfUkZjb25mICU+JSBzZWxlY3QoR2VuZUlELGV4YWN0TWF0Y2hQcmVkLFJGX2NvbmZpZGVuY2UpLAogICAgICAgICAgICBieT0iR2VuZUlEIikgJT4lIGZpbHRlcihSRl9jb25maWRlbmNlIT0iIikgJT4lIAogIGdncGxvdChhZXMoeD1tZWFuQ2FsbCx5PW1lYW5WYWwpKSArICAgICAgICAgCiAgZ2VvbV9wb2ludChhZXMoY29sPVJGX2NvbmZpZGVuY2UpLGNleD0wLjIpICsgCiAgZmFjZXRfd3JhcCh+IHRyYWluaW5nU2V0U2l6ZSkgCgpnZ3NhdmUoIi4uL3Jlc3VsdHMvU0Y2Yy5wZGYiLHdpZHRoPTgsaGVpZ2h0PTQpCmBgYAoKCgojI0ZlYXR1cmVzIG9mIGxvd2VyIGNvbmYtbGlrZSBtb2RlbHM/CmBgYHtyfQpHZF9hbGxfUkZjb25mICU+JSBmaWx0ZXIoUkZfY29uZmlkZW5jZT09Ikxvd2VyQ29uZi1saWtlIikgJT4lIAogIGxlZnRfam9pbihtZXRyaWNzX2xvbmcsYnk9IkdlbmVJRCIpICU+JSAKICBmaWx0ZXIoUERCX1BGQU1wcmVmPT0gR0RCX1BGQU1wcmVmKSAlPiUgCiAgc2VsZWN0KEdlbmVJRCxHREJfUEZBTXByZWYpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBsZWZ0X2pvaW4oUEZBTV9kZXNjcmlwdGlvblRhYmxlLGJ5PWMoJ0dEQl9QRkFNcHJlZicgPSAnUEZBTWNvZGUnKSkgJT4lIAogIGNvdW50KGRlc2MpICU+JSBhcnJhbmdlKGRlc2MobikpICU+JSBmaWx0ZXIobj4xKQoKR2RfYWxsX1JGY29uZiAlPiUgZmlsdGVyKFJGX2NvbmZpZGVuY2U9PSJMb3dlckNvbmYiKSAlPiUgCiAgbGVmdF9qb2luKG1ldHJpY3NfbG9uZyxieT0iR2VuZUlEIikgJT4lIAogIHNlbGVjdChHZW5lSUQsR0RCX1BGQU1wcmVmKSAlPiUgCiAgbmEub21pdCgpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBsZWZ0X2pvaW4oUEZBTV9kZXNjcmlwdGlvblRhYmxlLGJ5PWMoJ0dEQl9QRkFNcHJlZicgPSAnUEZBTWNvZGUnKSkgJT4lIAogIGNvdW50KGRlc2MpICU+JSBhcnJhbmdlKGRlc2MobikpICU+JSBmaWx0ZXIobj41KQoKCgpgYGAKCgojI0NvbXB1dGUgcmVsYXRpdmUgYWJ1bmRhbmNlIG9mIGRvbWFpbnMgYWNyb3NzIGNvbmZpZGVuY2UgZ3JvdXBzCmBgYHtyfQoKR2RfYWxsX1JGY29uZiAlPiUgCiAgbGVmdF9qb2luKG1ldHJpY3NfbG9uZyxieT0iR2VuZUlEIikgJT4lIAogIHNlbGVjdChHZW5lSUQsR0RCX1BGQU1wcmVmLFBEQl9QRkFNcHJlZiwgUkZfY29uZmlkZW5jZSkgJT4lZGlzdGluY3QoKSAlPiUgIAogIGdhdGhlcihrZXksdmFsdWUsLWMoR2VuZUlELFJGX2NvbmZpZGVuY2UpKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgdW5ncm91cCgpICU+JSAKICBmaWx0ZXIoUkZfY29uZmlkZW5jZSE9IiIpICU+JSBuYS5vbWl0KCkgJT4lIAogIGdyb3VwX2J5KFJGX2NvbmZpZGVuY2Usa2V5KSAlPiUgY291bnQodmFsdWUpICU+JSAKICBzcHJlYWQoUkZfY29uZmlkZW5jZSxuLCBmaWxsID0gMCkgJT4lIAogIGZpbHRlcihrZXk9PSJHREJfUEZBTXByZWYiKSAlPiUgCiAgcm93d2lzZSgpICU+JSAKICBtdXRhdGUocmF0aW8gPSAoTG93ZXJDb25mIC8xMzg5KSAvIChzdW0oYEhpQ29uZmAsYEhpQ29uZi1saWtlYCxgTG93ZXJDb25mLWxpa2VgKSAvIDEzODkpKSAlPiUgCiAgZmlsdGVyKExvd2VyQ29uZj4wLCByYXRpbyE9IkluZiIpICU+JSAKICBhcnJhbmdlKGRlc2MocmF0aW8pKSAlPiUgCiAgbGVmdF9qb2luKFBGQU1fZGVzY3JpcHRpb25UYWJsZSxieT1jKCd2YWx1ZSc9J1BGQU1jb2RlJykpICU+JSAKICBzZWxlY3QoZGVzYyxyYXRpbywgZXZlcnl0aGluZygpKQogIAogIAogICAgCmBgYAoKCgoKI0NsdXN0ZXJpbmcgYW5hbHlzaXMKCgojI1NGaWd1cmUgNQpDb21wYXJlIHNlcXVlbmNlLSBhbmQgc3RydWN0dXJlLWJhc2VkIGNsdXN0ZXJzCmBgYHtyIGNsdXN0ZXJpbmcsIGV2YWw9VFJVRX0KCmJsc3RfTmVrIDwtIHJlYWRfdHN2KCIuLi9kYXRhL05la19raW5hc2VfQkxBU1RwLnRzdiIsIGNvbF9uYW1lcyA9IFRSVUUpClRNX05layA8LSByZWFkX3RzdigiLi4vZGF0YS9OZWtfa2luYXNlX1RNLnRzdiIsIGNvbF9uYW1lcyA9IFRSVUUpCgpibHN0X21hdEZ1bGwgPC0gYmxzdF9OZWsgJT4lIG11dGF0ZSh2YWx1ZT1wZXJjZW50X3JhbmsoYml0X3Njb3JlKSkgJT4lIAogIHNlbGVjdChxdWVyeV9pZCxzdWJqZWN0X2lkLHZhbHVlKSAlPiUgCiAgc3ByZWFkKHN1YmplY3RfaWQsdmFsdWUsIGZpbGwgPSAwKSAlPiUgc2VsZWN0KC1xdWVyeV9pZCkgJT4lIGFzLm1hdHJpeCgpIApyb3duYW1lcyhibHN0X21hdEZ1bGwpIDwtIGNvbG5hbWVzKGJsc3RfbWF0RnVsbCkKClRNX21hdEZ1bGwgPC0gVE1fTmVrICU+JSBzcHJlYWQoc3RydWMyLFRNLCBmaWxsPTApICU+JSBzZWxlY3QoLXN0cnVjMSkgJT4lIGFzLm1hdHJpeCgpCnJvd25hbWVzKFRNX21hdEZ1bGwpIDwtIGNvbG5hbWVzKFRNX21hdEZ1bGwpCgoKYmxzdF9UTV9tZHMgPC0gcmJpbmQoKDEtY29yKGJsc3RfbWF0RnVsbCkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBjbWRzY2FsZSgpICU+JQogICAgICAgICAgICAgICAgICAgICAgIGFzX3RpYmJsZSgpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZHR5cGU9ImJsc3QiKSwgCiAgICAgICAgICAgICAgICAgICAgICgxLWNvcihUTV9tYXRGdWxsKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIGNtZHNjYWxlKCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShkdHlwZT0iVE0iKSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoRGltLjEgPSBWMSwgRGltLjIgPSBWMikgJT4lIAogIG11dGF0ZShHZW5lSUQ9c3RyX3JlcGxhY2UocmVwKHJvd25hbWVzKGJsc3RfbWF0RnVsbCksMiksIkdMXyIsIkdMNTA4MDNfIikpCgoKYmxzdF9UTV9tZHMgJT4lIAogIGxlZnRfam9pbihHZF9hbGxfUkZjb25mLCBieT0iR2VuZUlEIikgJT4lIAogIG11dGF0ZShkdHlwZT1yZWNvZGUoZHR5cGUsYmxzdD0iQkxBU1QiLFRNPSJUTS1hbGlnbiIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShSRl9jb25maWRlbmNlKSkgJT4lCiAgZHBseXI6OnJlbmFtZSgiUkYgY29uZmlkZW5jZSIgPSBSRl9jb25maWRlbmNlKSAlPiUgCiAgZ2dwbG90KGFlcyh4PURpbS4xLHk9RGltLjIgKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2w9YFJGIGNvbmZpZGVuY2VgLCBzaGFwZT1gUkYgY29uZmlkZW5jZWApLCBzaXplPTIpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoJ0hpQ29uZic9MSwnSGlDb25mLWxpa2UnID0gMSwgJ0xvd2VyQ29uZicgPTIsICJMb3dlckNvbmYtbGlrZSIgPSAyKSkgKwogIGZhY2V0X3dyYXAofiBkdHlwZSAsIHNjYWxlcz0iZnJlZSIpCgpnZ3NhdmUoIi4uL3Jlc3VsdHMvU0Y3LnBkZiIsd2lkdGg9OSxoZWlnaHQ9NCkKCmBgYAoKCgojVHJhbnNjcmlwdGlvbmFsIGFidW5kYW5jZQojI1NGaWd1cmUgNgpUcmFuc2NyaXB0aW9uYWwgYWJ1bmRhbmNlIGJ5IFJGIGNvbmZpZGVuY2UKYGBge3IsIG1lc3NhZ2U9J2hpZGUnLCB3YXJuaW5nPSdub25lJ30KCnRyYW5zY3JpcHRpb25fY3BtIDwtIHJlYWRfdHN2KCIuLi9kYXRhL0Fuc2VsbF8yMDE3X0dpYXJkaWFDUE0udHN2IiwgY29sX3R5cGVzID0gY29scygpKQoKCnRyYW5zY19ieV9jYXRlZ29yeSA8LSBHZF9hbGxfUkZjb25mICU+JSAKICAgbXV0YXRlKHRyYW5zY3JpcHRMZW49KEdEQl9BQSAqIDMpIC0gMykgJT4lIAogICBsZWZ0X2pvaW4odHJhbnNjcmlwdGlvbl9jcG0sYnk9IkdlbmVJRCIpICU+JSAKICAgc2VsZWN0KEdlbmVJRCxSRl9jb25maWRlbmNlLHRyYW5zY3JpcHRMZW4sY29udGFpbnMoJy1zJykpICU+JSAKICAgZ2F0aGVyKGtleSx2YWx1ZSwtYyhHZW5lSUQsdHJhbnNjcmlwdExlbixSRl9jb25maWRlbmNlKSkgJT4lIAogICBtdXRhdGUodmFsdWU9aWZlbHNlKGlzLm5hKHZhbHVlKSwwLjEsdmFsdWUpKSAlPiUgCiAgIG11dGF0ZSh2YWx1ZT12YWx1ZS90cmFuc2NyaXB0TGVuKSAlPiUgbmEub21pdCgpICU+JSAKICAgZ3JvdXBfYnkoR2VuZUlELFJGX2NvbmZpZGVuY2UpICU+JSBzdW1tYXJpemUobWVhblZhbD1tZWFuKHZhbHVlKSkgJT4lIAogIGZpbHRlcighUkZfY29uZmlkZW5jZT09IiIpIAogCnRyYW5zY19ieV9jYXRlZ29yeSAlPiUgCiAgIGZpbHRlcihtZWFuVmFsID4gMC4wMDEpICU+JSAKICAgZ2dwbG90KGFlcyh4PVJGX2NvbmZpZGVuY2UseT1sb2cxMChtZWFuVmFsKSkpICsgCiAgIGdlb21fYm94cGxvdChhZXMoZmlsbD1SRl9jb25maWRlbmNlKSwgd2lkdGg9MC41LCBjb2w9ImJsYWNrIiwgYWxwaGE9MC41KSArCiAgIGdlb21fdmlvbGluKGFlcyhjb2w9UkZfY29uZmlkZW5jZSksIGFscGhhPTApICsKICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSArIAogICB4bGFiKCIiKSArIHlsYWIoImxvZzEwKGxlbmd0aC1ub3JtYWxpemVkIENQTSkiKQoKZ2dzYXZlKCIuLi9yZXN1bHRzL1NGOC5wZGYiLHdpZHRoPTQsaGVpZ2h0PTQpCgojVGVzdCBkaWZmZXJlbmNlcyAKYW92X3RyYW5zYy5yZXMgPC0gYW92KG1lYW5WYWwgfiBSRl9jb25maWRlbmNlLCAKICAgICAgICAgICAgICAgICAgICAgIGRhdGE9dHJhbnNjX2J5X2NhdGVnb3J5ICU+JSBmaWx0ZXIobWVhblZhbD4gMC4wMDEpKSAKc3VtbWFyeShhb3ZfdHJhbnNjLnJlcykgIAoKVHVrZXlIU0QoYW92X3RyYW5zYy5yZXMpCiAKYGBgCgojU3VwcGxlbWVudGFyeSBUYWJsZXMKCldyaXRlIHN1cHBsZW1lbnRhcnkgVGFibGVzCmBgYHtyfQoKd3JpdGVfdHN2KEdkX2FsbF9SRmNvbmYgJT4lIAogICAgICAgICAgICBzZWxlY3QoLWMoc2VxLnNzTGVuLAogICAgICAgICAgICAgICAgICAgICAgbkhyYyxuRXJjLG5DcmMsCiAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y1N1bSxzdHJwUERCX0FBLCBjb2RlY2hhaW4pKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpyZW5hbWUoRXhhY3RfbWF0Y2hfcHJlZGljdGlvbiA9ZXhhY3RNYXRjaFByZWQsCiAgICAgICAgICAgICAgICBMZW5ndGhfcmF0aW89bGVuUmF0aW8sTWF0Y2hfc3RhdHVzPW1hdGNoU3RhdHVzLGBBQV8lSURgPUFBcGMsCiAgICAgICAgICAgICAgICBDX3Njb3JlPUNzY29yZSwKICAgICAgICAgICAgICAgIEFubm90X3N0YXR1cz1kZXNjQmluLENvbmZpZGVuY2VfY2F0ZWdvcnkgPVJGX2NvbmZpZGVuY2UpICU+JSAKICAgICAgICAgICAgYXJyYW5nZShkZXNjKENfc2NvcmUsQ29uZmlkZW5jZV9jYXRlZ29yeSkpLAogICAgICAgICAgICBwYXRoPSIuLi9yZXN1bHRzL1NUYWJsZV8yLnRzdiIpCgp3cml0ZV90c3YoR2RfYWxsX1JGY29uZiAlPiUgCiAgICAgICAgICAgIHNlbGVjdCgtYyhzZXEuc3NMZW4sCiAgICAgICAgICAgICAgICAgICAgICBuSHJjLG5FcmMsbkNyYywKICAgICAgICAgICAgICAgICAgICAgIHN0cnVjU3VtLHN0cnBQREJfQUEsIGNvZGVjaGFpbikpICU+JSAKICAgICAgICAgICAgZmlsdGVyKFJGX2NvbmZpZGVuY2U9PSJIaUNvbmYtbGlrZSIgJiBkZXNjQmluPT0iSHlwIikgJT4lCiAgICAgICAgICAgIGRwbHlyOjpyZW5hbWUoRXhhY3RfbWF0Y2hfcHJlZGljdGlvbiA9ZXhhY3RNYXRjaFByZWQsCiAgICAgICAgICAgICAgICBMZW5ndGhfcmF0aW89bGVuUmF0aW8sTWF0Y2hfc3RhdHVzPW1hdGNoU3RhdHVzLGBBQV8lSURgPUFBcGMsCiAgICAgICAgICAgICAgICBDX3Njb3JlPUNzY29yZSwKICAgICAgICAgICAgICAgIEFubm90X3N0YXR1cz1kZXNjQmluLENvbmZpZGVuY2VfY2F0ZWdvcnkgPVJGX2NvbmZpZGVuY2UpICU+JSAKICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoQ19zY29yZSxDb25maWRlbmNlX2NhdGVnb3J5KSksIAogICAgICAgICAgcGF0aD0iLi4vcmVzdWx0cy9TVGFibGVfMy50c3YiKQoKYGBgCgoKCgoKCgojUkYgY2xhc2lmaWVyIHNhbnMgJUFBIElECiMjRmlndXJlIDNiClJGIGNsYXNzaWZpZXIgd2l0aG91dCBBQV8lSUQKYGBge3IsIGV2YWw9RkFMU0V9CgpUUkFJTl9ub3BjQUEgPC0gZm9yVFJBSU4gJT4lIGRwbHlyOjpzZWxlY3QoLWMoR2VuZUlELEFBcGMpKSAKCnJmX21vZGVsX25vcGNBQSA8LSB0cmFpbihtYXRjaFN0YXR1cyB+LiAsIGRhdGE9VFJBSU5fbm9wY0FBLCBtZXRob2Q9InJmIiwKICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZD0iY3YiLCBudW1iZXI9NSwgdmVyYm9zZUl0ZXI9RkFMU0UpLAogICAgICAgICAgICAgICAgICBwcm94PVRSVUUsIHZlcmJvc2U9RkFMU0UpCnNhdmVSRFMocmZfbW9kZWxfbm9wY0FBLCAiLi4vZGF0YS9yZl9tb2RlbF9ub3BjQUEuUmRzIikKYGBgCgpgYGB7cn0KCnJmX21vZGVsX25vcGNBQSA8LSByZWFkUkRTKCIuLi9kYXRhL3JmX21vZGVsX25vcGNBQS5SZHMiKQpwcmludChyZl9tb2RlbF9ub3BjQUEkZmluYWxNb2RlbCkKCmBgYAoKCgpDbGFzc2lmaWVyIHBlcmZvcm1hbmNlIHdpdGhvdXQgJSBBQSBJRC4KYGBge3J9CgpwcmVkVEVTVF9ub3BjQUEgPC0gcHJlZGljdChyZl9tb2RlbF9ub3BjQUEsIG5ld2RhdGE9VEVTVCwgdHlwZT0icHJvYiIpCnByZWRBTExfbm9wY0FBIDwtIHByZWRpY3QocmZfbW9kZWxfbm9wY0FBLCBuZXdkYXRhPUdkX2ZvclJGLCB0eXBlPSJwcm9iIikKCiMgc3VtbWFyeShwcmVkVEVTVF9ub3BjQUEpCiMgc3VtbWFyeShwcmVkQUxMX25vcGNBQSkKCiNhY2N1cmFjeSBvbiBob2xkLW91dCBURVNUIHNldDoKVEVTVCAlPiUgIG11dGF0ZShSRmV4YWN0X3ByZWRfbm9wY0FBID0gcHJlZFRFU1Rfbm9wY0FBJGV4YWN0TWF0Y2gpICU+JSAKICBtdXRhdGUocHJlZFN0YXR1cz1pZmVsc2UoUkZleGFjdF9wcmVkX25vcGNBQSA+IDAuNSwiZXhhY3RNYXRjaCIsIm5vTWF0Y2giKSkgJT4lIAogIGNvdW50KG1hdGNoU3RhdHVzLCBwcmVkU3RhdHVzKSAlPiUgCiAgZ3JvdXBfYnkobWF0Y2hTdGF0dXMpICU+JSBtdXRhdGUoZ3BFcnI9bi9zdW0obikpCgojZW50aXJlIHByb3Rlb21lCkdkX2ZvclJGICU+JSBtdXRhdGUoUkZleGFjdF9wcmVkX25vcGNBQSA9IHByZWRBTExfbm9wY0FBJGV4YWN0TWF0Y2gpICU+JSAKICBtdXRhdGUocHJlZFN0YXR1cz1pZmVsc2UoUkZleGFjdF9wcmVkX25vcGNBQSA+IDAuNSwiZXhhY3RNYXRjaCIsIm5vTWF0Y2giKSkgJT4lIAogIGNvdW50KG1hdGNoU3RhdHVzLCBwcmVkU3RhdHVzKSAlPiUgCiAgZ3JvdXBfYnkobWF0Y2hTdGF0dXMpICU+JSBtdXRhdGUoZ3BFcnI9bi9zdW0obikpCgoKYGBgCgoKQ29tcHV0ZSBmZWF0dXJlIGltcG9ydGFuY2UgYW5kIHByZWRpY3RpdmUgcG93ZXIKYGBge3J9CgpHZF9pbXBfbm9wY0FBIDwtIGRhdGEuZnJhbWUodmFySW1wKHJmX21vZGVsX25vcGNBQSwgc2NhbGU9RkFMU0UpJGltcG9ydGFuY2UpIAoKR2RfaW1wX25vcGNBQSRub2kgIDwtIHJvdy5uYW1lcyhHZF9pbXBfbm9wY0FBKTsgcm93Lm5hbWVzKEdkX2ltcF9ub3BjQUEpIDwtIE5VTEwKbmFtZXMoR2RfaW1wX25vcGNBQSkgPC0gYygnQ29udHJpYm4nLCAnaW1wRmFjdG9yJykgCkdkX2ltcF9ub3BjQUEgPC0gR2RfaW1wX25vcGNBQSAlPiVkcGx5cjo6c2VsZWN0KDIsMSkgJT4lIAogIGFycmFuZ2UoZGVzYyhDb250cmlibikpICU+JSAgbXV0YXRlKHByb3BDb250ID0gQ29udHJpYm4vc3VtKENvbnRyaWJuKSkKCmltcF9wbG90X25vcGNBQSA8LSBHZF9pbXBfbm9wY0FBICU+JSAKICBtdXRhdGUoaW1wRmFjdG9yX3JlY29kZSA9IGNhc2Vfd2hlbihpbXBGYWN0b3I9PSJDc2NvcmUiIH4gJ0Nfc2NvcmUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1wRmFjdG9yPT0iQ292IiB+ICdDb3ZlcmFnZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbXBGYWN0b3I9PSJleGFjdE1hdGNoUHJlZCIgfiAnRXhhY3RfbWF0Y2hfcHJlZGljdGlvbicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbXBGYWN0b3I9PSJsZW5SYXRpbyIgfiAnTGVuZ3RoX3JhdGlvJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBpbXBGYWN0b3IpKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXJlb3JkZXIoaW1wRmFjdG9yX3JlY29kZSwgcHJvcENvbnQpLCB5PXByb3BDb250KSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgYWVzKGZpbGw9aW1wRmFjdG9yX3JlY29kZSksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICB5bGFiKCJJbXBvcnRhbmNlIikgKyB4bGFiKCIiKSArCiAgY29vcmRfZmxpcCgpICAKCmltcF9wbG90X25vcGNBQQoKZ2dzYXZlKCIuLi9yZXN1bHRzL1NGNS5wZGYiLCBpbXBfcGxvdF9ub3BjQUEsIHdpZHRoPTQsaGVpZ2h0PTMpCmBgYAo=